mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-09-09 11:47:14 +02:00
feat(frontend): rename inj roles to sys-front-*, add sys-svc-cdn, cache-busting lookup
Introduce sys-svc-cdn (cdn_paths/cdn_urls/cdn_dirs) and ensure CDN directories + latest symlink. Rename sys-srv-web-inj-* → sys-front-inj-*; update includes/templates; serve shared/per-app CSS & JS via CDN. Add lookup_plugins/local_mtime_qs.py for mtime-based cache busting; split CSS into default.css/bootstrap.css + optional per-app style.css. CSP: use style-src-elem; drop unsafe-inline for styles. Services: fix SYS_SERVICE_ALL_ENABLED bool and controlled flush. BREAKING CHANGE: role names changed; replace includes and references accordingly. Conversation: https://chatgpt.com/share/68b55494-9ec4-800f-b559-44707029141d
This commit is contained in:
91
roles/sys-front-inj-all/templates/location.lua.j2
Normal file
91
roles/sys-front-inj-all/templates/location.lua.j2
Normal file
@@ -0,0 +1,91 @@
|
||||
{# Jinja macro: expands feature snippets into Lua array pushes at render time #}
|
||||
{% macro push_snippets(list_name, features) -%}
|
||||
{% set kind = list_name | regex_replace('_snippets$','') %}
|
||||
{% for f in features if inj_enabled.get(f) -%}
|
||||
{{ list_name }}[#{{ list_name }} + 1] = [=[
|
||||
{%- include 'roles/sys-front-inj-' ~ f ~ '/templates/' ~ kind ~ '_sub.j2' -%}
|
||||
]=]
|
||||
{% endfor -%}
|
||||
{%- endmacro %}
|
||||
|
||||
lua_need_request_body on;
|
||||
|
||||
header_filter_by_lua_block {
|
||||
local ct = ngx.header.content_type or ""
|
||||
if ct:lower():find("^text/html") then
|
||||
ngx.ctx.is_html = true
|
||||
-- IMPORTANT: body will be modified → drop Content-Length to avoid mismatches
|
||||
ngx.header.content_length = nil
|
||||
else
|
||||
ngx.ctx.is_html = false
|
||||
end
|
||||
}
|
||||
|
||||
body_filter_by_lua_block {
|
||||
-- Only process HTML responses
|
||||
if not ngx.ctx.is_html then
|
||||
return
|
||||
end
|
||||
|
||||
-- Buffer all chunks until EOF
|
||||
ngx.ctx.buf = ngx.ctx.buf or {}
|
||||
local chunk, eof = ngx.arg[1], ngx.arg[2]
|
||||
|
||||
if chunk ~= "" then
|
||||
table.insert(ngx.ctx.buf, chunk)
|
||||
end
|
||||
|
||||
if not eof then
|
||||
-- Swallow intermediate chunks; emit once at EOF
|
||||
ngx.arg[1] = nil
|
||||
return
|
||||
end
|
||||
|
||||
-- Concatenate the full HTML
|
||||
local whole = table.concat(ngx.ctx.buf)
|
||||
ngx.ctx.buf = nil
|
||||
|
||||
-- Remove inline CSP <meta http-equiv="Content-Security-Policy"> (case-insensitive)
|
||||
local meta_re = [[<meta[^>]+http-equiv=["']Content-Security-Policy["'][^>]*>\s*]]
|
||||
whole = ngx.re.gsub(whole, meta_re, "", "ijo")
|
||||
|
||||
-- Build head snippets (rendered by Jinja at template time)
|
||||
local head_snippets = {}
|
||||
{{ push_snippets('head_snippets', inj_head_features) }}
|
||||
local head_payload = table.concat(head_snippets, "\n") .. "</head>"
|
||||
|
||||
-- Inject before </head> (first occurrence)
|
||||
local function repl_head(_) return head_payload end
|
||||
local new, n, err = ngx.re.sub(whole, [[</head\s*>]], repl_head, "ijo")
|
||||
if new then
|
||||
whole = new
|
||||
else
|
||||
ngx.log(ngx.WARN, "No </head> found; trying <body> fallback: ", err or "nil")
|
||||
-- Fallback: inject right AFTER the opening <body ...> tag
|
||||
local body_open_re = [[<body\b[^>]*>]]
|
||||
new, n, err = ngx.re.sub(whole, body_open_re, "$0\n" .. table.concat(head_snippets, "\n"), "ijo")
|
||||
if new then
|
||||
whole = new
|
||||
else
|
||||
ngx.log(ngx.ERR, "Head-fallback failed: ", err or "nil")
|
||||
end
|
||||
end
|
||||
|
||||
-- Build body snippets (rendered by Jinja at template time)
|
||||
local body_snippets = {}
|
||||
{{ push_snippets('body_snippets', inj_body_features) }}
|
||||
local body_payload = table.concat(body_snippets, "\n") .. "</body>"
|
||||
|
||||
-- Inject before </body> (first occurrence), or append if missing
|
||||
local function repl_body(_) return body_payload end
|
||||
new, n, err = ngx.re.sub(whole, [[</body\s*>]], repl_body, "ijo")
|
||||
if new then
|
||||
whole = new
|
||||
else
|
||||
ngx.log(ngx.WARN, "No </body> found; appending body snippets at end: ", err or "nil")
|
||||
whole = whole .. table.concat(body_snippets, "\n")
|
||||
end
|
||||
|
||||
-- Emit the modified HTML
|
||||
ngx.arg[1] = whole or ""
|
||||
}
|
3
roles/sys-front-inj-all/templates/server.conf.j2
Normal file
3
roles/sys-front-inj-all/templates/server.conf.j2
Normal file
@@ -0,0 +1,3 @@
|
||||
{% if inj_enabled.logout %}
|
||||
{% include 'roles/web-svc-logout/templates/logout-proxy.conf.j2' %}
|
||||
{% endif %}
|
Reference in New Issue
Block a user