Class: Sentiero::Web::AssetsApp

Inherits:
BaseApp
  • Object
show all
Defined in:
lib/sentiero/web/assets_app.rb

Overview

Standalone Rack endpoint serving the gem's static assets (mounted via r.sentiero_assets). Shares #serve with BaseApp#handle_asset so the dashboard's /assets/* route applies the same traversal guard, content types, and caching.

Constant Summary

Constants inherited from BaseApp

BaseApp::ASSETS_DIR, BaseApp::AUTH_WARNING_LOCK, BaseApp::CONTENT_TYPES, BaseApp::CSP_POLICY

Constants included from Escaping

Escaping::HTML_UNSAFE_IN_SCRIPT, Escaping::HTML_UNSAFE_IN_SCRIPT_PATTERN

Instance Method Summary collapse

Methods inherited from BaseApp

reset_auth_warning!, warn_unauthenticated_once

Methods included from Formatting

#format_duration, #format_vital, #parse_browser, #parse_device

Methods included from Escaping

#escape_html, #escape_js_string, #escape_json

Instance Method Details

#call(env) ⇒ Object



11
12
13
14
15
# File 'lib/sentiero/web/assets_app.rb', line 11

def call(env)
  return [405, {"content-type" => "text/plain"}, ["Method Not Allowed"]] unless env["REQUEST_METHOD"] == "GET"

  serve(env["PATH_INFO"].delete_prefix("/"))
end

#serve(relative_path) ⇒ Object

Resolved path must stay inside ASSETS_DIR (blocks traversal/absolute paths); .erb files are never served raw. Fingerprinted basenames (name-HASH.ext) get a year of immutable cache (31536000s), else one day.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/sentiero/web/assets_app.rb', line 20

def serve(relative_path)
  return not_found if relative_path.nil? || relative_path.empty?

  full_path = File.expand_path(relative_path, ASSETS_DIR)

  return not_found unless full_path.start_with?(ASSETS_DIR + File::SEPARATOR)
  return not_found if full_path.end_with?(".erb")
  return not_found unless File.file?(full_path)

  ext = File.extname(full_path)
  content_type = CONTENT_TYPES.fetch(ext, "application/octet-stream")

  cache_control = if File.basename(full_path).match?(/\A[^\/]+-[A-Za-z0-9]+\.\w+\z/)
    "public, max-age=31536000, immutable"
  else
    "public, max-age=86400"
  end

  [200, {"content-type" => content_type, "cache-control" => cache_control}, [File.binread(full_path)]]
end