Save all attachments to separate files

For now we just save them unmodified and give them an extension that
will cause the web server to provide the correct content-type. This is
probably *not safe*: A user could send malicious html as an attachment
and the browser will interpret it when another user clicks on the link.
We might try to sanitize attachments (but you would normally expect an
attachment to be preserved) or to preserve the content-dispostion header
(but I don't think this is possible with just a static archive).
This commit is contained in:
Peter J. Holzer 2019-03-02 12:10:01 +01:00
parent 48ea68eaef
commit 9f44375354
1 changed files with 35 additions and 15 deletions

View File

@ -49,12 +49,45 @@ def render_message(msg):
msghtml = msgtmpl.render(context)
return jinja2.Markup(msghtml)
def save_part(msg):
content_type = msg.get_content_type()
extension = {
"application/octet-stream": ".bin",
"text/html": ".html",
"text/x-vcard": ".vcf",
}[content_type]
name = msg.get_param("name") or "(data)"
m = hashlib.sha256()
payload = msg.get_payload(decode=True)
m.update(payload)
filename = m.hexdigest() + extension
os.makedirs("parts", exist_ok=True)
with open("parts/" + filename, "wb") as fh:
fh.write(payload)
bodytmpl = jenv.get_template("body_application_octet_stream.html")
context = {
"name": name,
"url": "../../parts/" + filename,
}
bodyhtml = bodytmpl.render(context)
return bodyhtml
partial_message_cache = {}
def render_body(msg):
content_type = msg.get_content_type()
content_disposition = msg.get_content_disposition()
if content_disposition == "attachment":
# XXX - not sure, if we should just store all content-types.
# We probably should clean up html. Alternatively we could just store
# all of them application/octet-stream, which browsers should download
# and not try to display.
bodyhtml = save_part(msg)
if content_type == "text/plain":
elif content_type == "text/plain":
bodytmpl = jenv.get_template("body_text_plain.html")
context = {
"body": msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1")
@ -129,20 +162,7 @@ def render_body(msg):
html.escape(whole_msg_id))
elif content_type == "application/octet-stream":
name = msg.get_param("name") or "(data)"
m = hashlib.sha256()
payload = msg.get_payload(decode=True)
m.update(payload)
filename = m.hexdigest() + ".bin"
os.makedirs("parts", exist_ok=True)
with open("parts/" + filename, "wb") as fh:
fh.write(payload)
bodytmpl = jenv.get_template("body_application_octet_stream.html")
context = {
"name": name,
"url": "../../parts/" + filename,
}
bodyhtml = bodytmpl.render(context)
bodyhtml = save_part(msg)
elif content_type == "multipart/signed":
content, signature = msg.get_payload()