"""Serving user-uploaded files without handing the browser a script.

Uploads reach these routes from people, and one of the accepted image types is
not inert: an SVG is an XML document that may carry <script>, and it is wanted
for floor-plan maps and branding, where vector is the right format. Loaded
through an <img> tag a script inside it never runs, so the tiles and maps in
this app were never the risk. Opening the file's own URL is - and the
application image route is public, so the URL is reachable without a session.

Rather than banning the format that has a real use, every uploaded file is
served with headers that make the document case inert:

  Content-Security-Policy: default-src 'none'; sandbox
      No script, no fetch, no plugin, and a unique opaque origin. This is what
      stops an SVG (or an HTML file that talked its way past an allowlist)
      executing in the site's origin and reading a token out of localStorage.
  X-Content-Type-Options: nosniff
      A file whose extension and bytes disagree is not re-typed by the browser
      into something executable.

Both are cheap and apply to every upload route, so a new one added later starts
from the same place instead of repeating the reasoning.
"""

from flask import send_from_directory

# 'sandbox' with no allow-* tokens: opaque origin, scripts blocked, forms and
# popups blocked. default-src 'none' is belt and braces for a UA that ignores
# sandbox in a header.
UPLOAD_CSP = "default-src 'none'; sandbox"


def harden_upload_response(response):
    """Apply the inert-document headers to a response serving an upload."""
    response.headers['Content-Security-Policy'] = UPLOAD_CSP
    response.headers['X-Content-Type-Options'] = 'nosniff'
    return response


def send_upload(directory, filename, **kwargs):
    """send_from_directory, with the upload headers applied.

    Any keyword send_from_directory takes is passed through, so a route that
    already sends as an attachment keeps doing so.
    """
    return harden_upload_response(send_from_directory(directory, filename, **kwargs))
