Require login to export files; allow downloading the original too
CI / check (push) Successful in 43s
CI / deploy (push) Successful in 16s

?download=... on GET /api/gpx/file now requires login, same as
upload/move/delete/create-folder -- plain viewing (no ?download)
stays public. Added ?download=original alongside the existing
GeoJSON export, serving the untouched, as-uploaded file directly via
send_file -- the file name link still downloads GeoJSON, a new
button next to delete downloads the original.

Since both are real <a href> links (so right-click/middle-click still
work), a logged-out click can't just be left as a plain navigation --
it would land on a raw JSON error page instead of being sent to log
in. _download (gpx.js) fetches instead, reuses the existing
redirectIfUnauthorized 401 check, and only then turns the response
into a blob and clicks a throwaway <a download> to trigger the save.

Verified in a real browser: an anonymous click on either download
correctly redirects through /login to the real OAuth login page
instead of showing raw JSON.
This commit is contained in:
randy committed 2026-09-07 23:18:59 +02:00
1 parent ceaaa0bb92
commit eca8519152
4 files changed
+123 -30

No files matched your search

+22 -4
View File
@@ -191,11 +191,29 @@ module Maptool
json paths: paths, tree: GPX_STORE.tree
end
# ?download=1 exports the file's GeoJSON as an attachment instead of
# rendering it on the map — the only way to get a .gpx/.fit's converted
# form out of the app, since GpxStore#geojson's cache is otherwise an
# internal implementation detail with no filename of its own to expose.
# ?download=geojson exports the file's GeoJSON as an attachment instead
# of rendering it on the map — the only way to get a .gpx/.fit's
# converted form out of the app, since GpxStore#geojson's cache is
# otherwise an internal implementation detail with no filename of its
# own to expose. ?download=original exports the untouched, as-uploaded
# file instead (a .geojson source's "original" is that same file, so
# the two downloads are identical there — harmless, not special-cased).
# Both gated the same as the other write/manage actions below (upload,
# move, create folder) — viewing a file on the map stays open to
# anyone, exporting it as a file does not.
get "/api/gpx/file/*" do
require_login! if params[:download]
if params[:download] == "original"
begin
path = GPX_STORE.resolve_file(params[:splat].first)
rescue GpxStore::InvalidPath
halt 400
end
halt 404 unless File.file?(path)
return send_file(path, filename: File.basename(path), disposition: "attachment")
end
begin
body = GPX_STORE.geojson(params[:splat].first)
rescue GpxStore::InvalidPath