Skip to content

Commit 1ba069d

Browse files
committed
Add configs to use a proxy for viewing attachments
1 parent 23dbdcf commit 1ba069d

File tree

4 files changed

+71
-20
lines changed

4 files changed

+71
-20
lines changed

.env.example

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
MONGO_URI=mongodb+srv://urihere
2-
LOG_URL_PREFIX=/logs
1+
# Your MongoDB Connection string, same as your bot's.
2+
CONNECTION_URI=mongodb+srv://urihere
3+
# Where should the logviewer serve your logs. Default: https://example.com/logs/LOGKEY
4+
LOG_URL_PREFIX=/logs
5+
# Listen address and port. Don't change them if you don't know what they do.
36
HOST=0.0.0.0
47
PORT=8000
8+
# Whether if the logviewer should use a proxy to view attachments.
9+
# If set to "no" (default), attachments will expire after 1 day and the logviewer won't be able to show the attachment.
10+
# Please be aware that this may violate Discord TOS and the proxy will have full access to your attachments.
11+
# Modmail/Logviewer is not affiliated with the proxy in any way. USE AT YOUR OWN RISK.
12+
USE_ATTACHMENT_PROXY=no
13+
ATTACHMENT_PROXY_URL=https://cdn.discordapp.xyz

app.json

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
{
2-
"name": "Modmail Log Viewer",
3-
"description": "A simple webserver to view self-hosted logs",
4-
"repository": "https://github.com/kyb3r/logviewer",
5-
"env": {
6-
"MONGO_URI": {
7-
"description": "MongoDB connection URI that contains your modmail logs.",
8-
"required": true
2+
"name": "Modmail Log Viewer",
3+
"description": "A simple webserver to view self-hosted logs",
4+
"repository": "https://github.com/kyb3r/logviewer",
5+
"env": {
6+
"MONGO_URI": {
7+
"description": "MongoDB connection URI that contains your modmail logs.",
8+
"required": true
99
}
10+
},
11+
"USE_ATTACHMENT_PROXY": {
12+
"description": "Whether if the logviewer should use a proxy to view attachments. If set to 'no', attachments will expire after 1 day. USE AT YOUR OWN RISK.",
13+
"required": false,
14+
"value": "no"
15+
},
16+
"ATTACHMENT_PROXY_URL": {
17+
"description": "Proxy URL for viewing attachments.",
18+
"required": false,
19+
"value": "https://cdn.discordapp.xyz"
1020
}
1121
}

app.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
__version__ = "1.1.1"
1+
__version__ = "1.1.2"
22

3+
import html
34
import os
45

56
from dotenv import load_dotenv
@@ -41,10 +42,34 @@ def render_template(name, *args, **kwargs):
4142
app.ctx.render_template = render_template
4243

4344

45+
def strtobool(val):
46+
"""
47+
Copied from distutils.strtobool.
48+
49+
Convert a string representation of truth to true (1) or false (0).
50+
51+
True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
52+
are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if
53+
'val' is anything else.
54+
"""
55+
val = val.lower()
56+
if val in ('y', 'yes', 't', 'true', 'on', '1'):
57+
return 1
58+
elif val in ('n', 'no', 'f', 'false', 'off', '0'):
59+
return 0
60+
else:
61+
raise ValueError("invalid truth value %r" % (val,))
62+
63+
4464
@app.listener("before_server_start")
4565
async def init(app, loop):
4666
app.ctx.db = AsyncIOMotorClient(MONGO_URI).modmail_bot
47-
67+
use_attachment_proxy = strtobool(os.getenv("USE_ATTACHMENT_PROXY", "https://cdn.discordapp.xyz"))
68+
if use_attachment_proxy:
69+
app.ctx.attachment_proxy_url = os.environ["ATTACHMENT_PROXY_URL"]
70+
app.ctx.attachment_proxy_url = html.escape(app.ctx.attachment_proxy_url).rstrip("/")
71+
else:
72+
app.ctx.attachment_proxy_url = None
4873

4974
@app.exception(NotFound)
5075
async def not_found(request, exc):

core/models.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ def __init__(self, app, data):
1919
)
2020
self.channel_id = int(data["channel_id"])
2121
self.guild_id = int(data["guild_id"])
22-
self.creator = User(data["creator"])
23-
self.recipient = User(data["recipient"])
24-
self.closer = User(data["closer"]) if not self.open else None
22+
self.creator = User(app, data["creator"])
23+
self.recipient = User(app, data["recipient"])
24+
self.closer = User(app, data["closer"]) if not self.open else None
2525
self.close_message = format_content_html(data.get("close_message") or "")
26-
self.messages = [Message(m) for m in data["messages"]]
26+
self.messages = [Message(app, m) for m in data["messages"]]
2727
self.internal_messages = [m for m in self.messages if m.type == "internal"]
2828
self.thread_messages = [
2929
m for m in self.messages if m.type not in ("internal", "system")
@@ -112,7 +112,8 @@ def render_plain_text(self):
112112

113113

114114
class User:
115-
def __init__(self, data):
115+
def __init__(self, app, data):
116+
self.app = app
116117
self.id = int(data.get("id"))
117118
self.name = data["name"]
118119
self.discriminator = data["discriminator"]
@@ -147,7 +148,8 @@ def type(self):
147148

148149

149150
class Attachment:
150-
def __init__(self, data):
151+
def __init__(self, app, data):
152+
self.app = app
151153
if isinstance(data, str): # Backwards compatibility
152154
self.id = 0
153155
self.filename = "attachment"
@@ -160,17 +162,22 @@ def __init__(self, data):
160162
self.url = data["url"]
161163
self.is_image = data["is_image"]
162164
self.size = data["size"]
165+
if self.app.ctx.attachment_proxy_url is not None:
166+
self.url = self.url.replace("https://cdn.discordapp.com", self.app.ctx.attachment_proxy_url)
167+
self.url = self.url.replace("https://media.discordapp.net", self.app.ctx.attachment_proxy_url)
168+
print(self.url)
163169

164170

165171
class Message:
166-
def __init__(self, data):
172+
def __init__(self, app, data):
173+
self.app = app
167174
self.id = int(data["message_id"])
168175
self.created_at = dateutil.parser.parse(data["timestamp"]).astimezone(timezone.utc)
169176
self.human_created_at = duration(self.created_at, now=datetime.now(timezone.utc))
170177
self.raw_content = data["content"]
171178
self.content = self.format_html_content(self.raw_content)
172-
self.attachments = [Attachment(a) for a in data["attachments"]]
173-
self.author = User(data["author"])
179+
self.attachments = [Attachment(app, a) for a in data["attachments"]]
180+
self.author = User(app, data["author"])
174181
self.type = data.get("type", "thread_message")
175182
self.edited = data.get("edited", False)
176183

0 commit comments

Comments
 (0)