d32c74052ca0e57471949ca35e92f346bbeaec84
15
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ad7d735739 |
fix(cinny-nginx): give content-hashed app files their own rate budget
Lint / Shell (shellcheck) (pull_request) Successful in 15s
Lint / JS (eslint) (pull_request) Successful in 10s
Lint / No secrets in webhook configs (pull_request) Successful in 5s
Lint / Landing page is rendered (matrix (pull_request) Successful in 5s
Lint / Python (ruff) (pull_request) Successful in 6s
Lint / Python deps (pip-audit) (pull_request) Failing after 57s
Lint / Secret scan (gitleaks) (pull_request) Successful in 11s
Lint / Shell (shellcheck) (push) Successful in 11s
Lint / JS (eslint) (push) Successful in 9s
Lint / No secrets in webhook configs (push) Successful in 5s
Lint / Landing page is rendered (matrix (push) Successful in 5s
Lint / Python (ruff) (push) Successful in 8s
Lint / Python deps (pip-audit) (push) Failing after 51s
Lint / Secret scan (gitleaks) (push) Successful in 6s
A cold page load fires ~75 requests within a second and the service worker precaches all ~126 build files at once (every deploy renames them), both past chat_limit's burst of 60. The excess got 503 "limiting requests": a fresh visit to /register/matrix.org rendered blank (4 chunks refused), and precache installs could fail after deploys. Like decorations (matrix #22), hashed js/css/fonts/images/wasm now use assets_limit (100 r/s, burst 400); pages and the webhook keep chat_limit. The deploy validates with nginx -t and restores the old config on failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5 |
||
|
|
a52d6a89bc |
fix(cinny-web): per-client rate limits; own budget for decorations
Lint / Shell (shellcheck) (pull_request) Successful in 7s
Lint / JS (eslint) (pull_request) Successful in 7s
Lint / No secrets in webhook configs (pull_request) Successful in 3s
Lint / Landing page is rendered (matrix (pull_request) Successful in 3s
Lint / Python (ruff) (pull_request) Successful in 4s
Lint / Python deps (pip-audit) (pull_request) Successful in 49s
Lint / Secret scan (gitleaks) (pull_request) Successful in 5s
Lint / Shell (shellcheck) (push) Successful in 7s
Lint / JS (eslint) (push) Successful in 6s
Lint / No secrets in webhook configs (push) Successful in 4s
Lint / Landing page is rendered (matrix (push) Successful in 4s
Lint / Python (ruff) (push) Successful in 4s
Lint / Python deps (pip-audit) (push) Successful in 30s
Lint / Secret scan (gitleaks) (push) Successful in 4s
Every request reaches LXC 106 from Nginx Proxy Manager (10.10.10.27), and nginx had no realip config, so chat_limit (20 r/s, burst 60, keyed by $binary_remote_addr) was ONE bucket for the whole community: a scanner burst 503ed real users. Trust X-Real-IP from the proxy only, in both server blocks. Decorations (#22) now come from this host, and the profile picker can fetch all 629 thumbnails: ~500 of them 503ed in testing. /decorations/ gets its own zone (100 r/s, burst 700) instead of chat_limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5 |
||
|
|
b6380b6c8a |
feat(cinny-web): serve avatar decorations from chat.lotusguild.org/decorations (#22)
Lint / Shell (shellcheck) (push) Successful in 14s
Lint / JS (eslint) (push) Successful in 11s
Lint / No secrets in webhook configs (push) Successful in 5s
Lint / Landing page is rendered (matrix (push) Successful in 4s
Lint / Python (ruff) (push) Successful in 6s
Lint / Python deps (pip-audit) (push) Successful in 32s
Lint / Secret scan (gitleaks) (push) Successful in 4s
Lint / Shell (shellcheck) (pull_request) Successful in 7s
Lint / JS (eslint) (pull_request) Successful in 5s
Lint / No secrets in webhook configs (pull_request) Successful in 4s
Lint / Landing page is rendered (matrix (pull_request) Successful in 3s
Lint / Python (ruff) (pull_request) Successful in 4s
Lint / Python deps (pip-audit) (pull_request) Successful in 30s
Lint / Secret scan (gitleaks) (pull_request) Successful in 4s
Decorations came through Nextcloud's public DAV: a new PHP session (four cookies) per image and no cache headers, on every decorated avatar. The set (629 decorations + thumbnails, 573 MB) is now a versioned Gitea generic package (avatar-decorations 1.0.0, 4 tar parts), pinned by sha256 in cinny/decorations.sha256. LXC 106's deploy installs it to /var/www/decorations-<version> (verified against the pin and the in-package manifest; previous version kept; failures leave the live set alone), and nginx serves /decorations/ with a one-week public cache. deploy/publish-decorations.sh publishes a new version and writes the pin. Fixes #22 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5 |
||
|
|
bf770fed83 |
fix(cinny-web): no-cache for the app shell on SPA routes; keep old hashed assets 14 days (#23)
Lint / Shell (shellcheck) (push) Successful in 24s
Lint / JS (eslint) (push) Successful in 15s
Lint / No secrets in webhook configs (push) Successful in 7s
Lint / Landing page is rendered (matrix (push) Successful in 42s
Lint / Python (ruff) (push) Successful in 11s
Lint / Python deps (pip-audit) (push) Successful in 40s
Lint / Secret scan (gitleaks) (push) Successful in 6s
Lint / Shell (shellcheck) (pull_request) Successful in 9s
Lint / JS (eslint) (pull_request) Successful in 7s
Lint / No secrets in webhook configs (pull_request) Successful in 5s
Lint / Landing page is rendered (matrix (pull_request) Successful in 4s
Lint / Python (ruff) (pull_request) Successful in 6s
Lint / Python deps (pip-audit) (pull_request) Successful in 1m59s
Lint / Secret scan (gitleaks) (pull_request) Successful in 15s
SPA URLs (/, /home/…, /login/…) are rewritten to /index.html inside location /, which set no cache headers, so browsers heuristically reused a stale shell after a deploy, and rsync --delete had just removed the assets it referenced: a blank app until the shell expired. Send no-cache for the rewritten shell (map on $uri; location / now includes the security headers, since add_header drops the inherited ones), and stop deleting previous builds' hashed assets: prune after 14 days. Fixes #23 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5 |
||
|
|
9c5a183025 |
feat(cinny): nginx for Element Call on call.chat.lotusguild.org (cinny #43)
Lint / Shell (shellcheck) (push) Successful in 21s
Lint / JS (eslint) (push) Successful in 14s
Lint / No secrets in webhook configs (push) Successful in 6s
Lint / Landing page is rendered (matrix (push) Successful in 6s
Lint / Python (ruff) (push) Successful in 7s
Lint / Python deps (pip-audit) (push) Successful in 52s
Lint / Secret scan (gitleaks) (push) Successful in 8s
Lint / Shell (shellcheck) (pull_request) Successful in 17s
Lint / JS (eslint) (pull_request) Successful in 13s
Lint / No secrets in webhook configs (pull_request) Successful in 6s
Lint / Landing page is rendered (matrix (pull_request) Successful in 6s
Lint / Python (ruff) (pull_request) Successful in 8s
Lint / Python deps (pip-audit) (pull_request) Successful in 53s
Lint / Secret scan (gitleaks) (pull_request) Successful in 8s
- cinny/nginx.conf: a call.chat.lotusguild.org server block that serves ONLY /public/element-call/ (the same files chat.lotusguild.org already serves there) and 404s everything else, including source maps and dotfiles. - cinny/nginx-security-headers-call.conf (new snippet): frame-ancestors https://chat.lotusguild.org instead of X-Frame-Options SAMEORIGIN, which would block the now cross-origin parent. - cinny/nginx-security-headers.conf: the app's Permissions-Policy delegates autoplay/camera/display-capture/microphone to the call origin (without it the cross-origin frame's getUserMedia is refused). Outer quotes switched to single: the inner "origin" quotes broke nginx parsing. Nothing changes for users until config.json sets elementCallUrl (separate step). Snippets are installed by hand on LXC 106; nginx.conf deploys on merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA |
||
|
|
d4fd1d0b8e |
fix(cinny/nginx): let the app frame its bundled Element Call again
Lint / Shell (shellcheck) (push) Successful in 20s
Lint / JS (eslint) (push) Successful in 13s
Lint / No secrets in webhook configs (push) Successful in 4s
Lint / Python (ruff) (push) Successful in 5s
Lint / Python deps (pip-audit) (push) Successful in 44s
Lint / Secret scan (gitleaks) (push) Successful in 8s
Web calls broke ("nobody can join calls from the web version"):
|
||
|
|
23ad133dc3 |
cinny(nginx): security headers on every location; sync repo with live (cinny #210, #214, #155)
Lint / Shell (shellcheck) (push) Successful in 13s
Lint / JS (eslint) (push) Successful in 12s
Lint / No secrets in webhook configs (push) Successful in 6s
Lint / Python (ruff) (push) Successful in 9s
Lint / Python deps (pip-audit) (push) Successful in 1m9s
Lint / Secret scan (gitleaks) (push) Successful in 10s
Applied on LXC 106 (backed up, `nginx -t`, reloaded) and recorded here: - Security headers (incl. CSP) moved to snippets/cinny-security-headers.conf and included at server level plus in the /sw.js, static-asset and json/html locations. nginx drops inherited add_header in any block that sets its own, so static assets were served without nosniff and /sw.js without a CSP (a service worker takes its CSP from its own script). Now every path carries all seven headers. Verified: the SW installs and controls the page under the CSP with no violations. - #214: CSP no longer allows fonts.googleapis.com / fonts.gstatic.com (VT323 is self-hosted since cinny 6f250353). - #155: the /share-target → /share 303 is now live (it was only in the repo; the 106 matrix-deploy hook has been dead since May, so repo edits never reached it). absolute_redirect off makes it relative. - README: the snippet, and that 106 needs these applied by hand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA |
||
|
|
a16cc85420 |
cinny: 303 /share-target → /share for the PWA share target (#155)
The service worker normally answers the share-sheet POST itself; this keeps a POST that reaches nginx before the worker controls the page from returning 405. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA |
||
|
|
c553c28957 |
cinny nginx: drop fonts.googleapis.com / fonts.gstatic.com from the CSP
Lotus Chat 6f250353 self-hosts VT323, so nothing legitimate loads from Google any more; keeping the hosts allowed would let a regression pass silently. NOTE: the live config is hand-maintained at /etc/nginx/sites-available/cinny on LXC 106 — apply the same two edits there after the cinny deploy lands. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA |
||
|
|
b72d6620cc |
chore(nginx): widen CSP frame-src to https: for room widgets (MSC1236)
Room widgets embed arbitrary third-party https pages in a sandboxed iframe; frame-src was 'self' + openstreetmap only. Apply + nginx -s reload. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
64262b39ec |
chore(nginx): drop api.qrserver.com from CSP (invite QR now generated locally)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6293a62e47 |
feat(nginx): add HSTS + Permissions-Policy to chat.lotusguild.org (P6-4)
Adds Strict-Transport-Security (2y, includeSubDomains, preload) and a Permissions-Policy that allows only the features the app uses (camera/mic/ display-capture for calls, geolocation for location share, autoplay/fullscreen/ encrypted-media) and denies the rest. Complements the existing X-Frame/CSP/ Referrer headers. Apply: reload nginx on the LXC. TLS terminates upstream (listen 80), so verify the header reaches the browser (front proxy must pass it through) — else set HSTS at the TLS terminator. Verify a call + location share still work. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
d6fd323262 |
cinny: enable mozilla.org (OIDC/next-gen-auth homeserver)
Now that the client supports MSC3861 OIDC login, add mozilla.org to the homeserverList and its origins to the CSP. mozilla delegates: homeserver -> mozilla.modular.im, OIDC issuer -> chat.mozilla.org, identity -> vector.im. - connect-src += mozilla.org mozilla.modular.im chat.mozilla.org vector.im - img-src += mozilla.org mozilla.modular.im Applied live to LXC 106 and synced here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
b39e3594d5 |
cinny: allow matrix.org media in CSP img-src
Federated matrix.org users load avatars/images from their own media endpoint (matrix-client.matrix.org), which img-src still blocked — so every avatar tripped a CSP violation. Add https://matrix.org + https://*.matrix.org to img-src to match connect-src. (media-src already allows https: so video/audio were fine.) Applied live to LXC 106 and synced here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
40ceb43672 |
cinny: version-control the production nginx site config
The chat.lotusguild.org nginx config (LXC 106) was edited directly on the box and never tracked — which is how its CSP drifted (kept a dead Sentry URL and blocked matrix.org logins). Snapshot it as cinny/nginx.conf (verbatim from prod, incl. the corrected connect-src that now allows matrix.org/*.matrix.org) and deploy it via lxc106-cinny.sh: back up the live file, swap, `nginx -t`, and reload only on success (auto-restore the backup if validation fails, so a bad config can't take the site down). TLS terminates at the NPM proxy, so this is a plain HTTP server block with no secrets. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |