mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-10-29 00:44:05 +09:00
Serve uploads that aren't media as downloads
Uploaded files come from this origin, so one served with a JavaScript
type could run as one of the app's own scripts. Browsers accept sixteen
spellings of that type, and Disk URLs sign the type they were minted
with, so refusing a list of types at upload can't cover links already
out there. Instead, a middleware rewrites the type of anything Active
Storage reads out that isn't plainly media, a PDF or plain text to
application/octet-stream, whatever the URL says.
(cherry picked from commit cad2d7211d)
This commit is contained in:
1 parent
049fc920d3
commit
3a140f65b2
2 files changed
+68
No files matched your search
@@ -0,0 +1,31 @@
|
||||
# Uploaded files are served from this origin, so under script-src 'self' an
|
||||
# upload served with any JavaScript MIME type would run as one of our scripts.
|
||||
# Browsers accept sixteen spellings of that type, and Disk URLs sign the type
|
||||
# they were minted with, so a list of types to refuse can't cover old links.
|
||||
# Instead, anything Active Storage serves that isn't plainly media goes out as
|
||||
# a download, whatever its URL says. Only reads are touched: uploading
|
||||
# (direct upload JSON, Disk PUT) answers in its own types.
|
||||
#
|
||||
# Accepted on upgrade: a browser that cached an upload under a script type
|
||||
# before this guard shipped can still run it from that cache until the entry
|
||||
# expires, up to an hour after it was fetched (config/initializers/active_storage.rb).
|
||||
# Revalidation doesn't help, since a 304 carries no content type.
|
||||
class UploadedScriptGuard
|
||||
SERVABLE = %r{\A(image|video|audio)/|\A(application/pdf|application/octet-stream|text/plain)\z}
|
||||
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
status, headers, body = @app.call(env)
|
||||
|
||||
if env["REQUEST_METHOD"].in?(%w[ GET HEAD ]) && env["PATH_INFO"].start_with?("#{ActiveStorage.routes_prefix}/") && (type = headers["content-type"])
|
||||
headers["content-type"] = ActiveStorage.binary_content_type unless type.split(";").first.strip.downcase.match?(SERVABLE)
|
||||
end
|
||||
|
||||
[ status, headers, body ]
|
||||
end
|
||||
end
|
||||
|
||||
Rails.application.config.middleware.use UploadedScriptGuard
|
||||
Reference in new issue
Block a user