Harden security model and refresh UI to an editorial Obsidian Gallery theme#1
Merged
Merged
Conversation
…y' theme Server ------ * New server/config.js as a single source of truth for env settings. Production fail-fast on missing/placeholder JWT_SECRET; development generates an ephemeral random secret with a clear warning. * Authorization is now enforced on every transfer event: only the sender can push chunks or mark a transfer complete, only the recipient can accept or reject, and cancellation requires the caller to be a party to the transfer. UUID transferIds were not sufficient on their own. * Chunk payloads are size-bounded (3 MiB hard cap) and shape-validated before being relayed. * Transfers with no chunk activity are auto-cancelled by an idle sweep, preventing memory leaks when a sender abandons a transfer without disconnecting. Cancel events now carry a reason field (cancelled_by_peer | peer_disconnected | idle_timeout). * Per-socket chat rate limit (sliding window) and per-IP rate limits on /login (5/15m) and /register (5/1h), no extra dependencies. * users.json writes go through a single-writer queue and an atomic temp-file + rename, eliminating the prior read-modify-write race. * Login now performs a bcrypt compare even when the user does not exist, mitigating user-enumeration via timing. * Bcrypt cost bumped to 12; minimum password length is now 8 (with a 128-char ceiling). * Express now sends X-Content-Type-Options, X-Frame-Options, a Referrer-Policy, a tight Permissions-Policy, and a CSP that allows self plus Google Fonts and the Socket.IO CDN. compression is enabled. CORS supports an explicit allowlist (defaults to same-origin, which is the recommended LAN posture). * /api/* fall-throughs now return JSON 404 instead of the SPA shell. * Socket.IO maxHttpBufferSize lowered from 100 MiB to 4 MiB. * SIGINT/SIGTERM trigger a graceful shutdown that closes Socket.IO and HTTP cleanly, with a 10s force-exit safety net. * Multi-tab disconnects no longer cancel a user's transfers when other tabs are still connected. Client ------ * public/js/app.js: removed the unused logout import and the dynamic import workaround for the circular auth dependency. initAuth now receives showNotification through its options object. escapeHtml is a regex-based lookup table, no DOM allocation. Browser Notifications are now opt-in per call and only fire when the tab is hidden, ending the prior toast-spam behaviour. Added a handler for the new server:shutdown event. * public/js/fileTransfer.js: pendingFile is now a correlation-id Map, removing the race when multiple requests are in flight. Drag-and-drop now works anywhere on the dashboard, not just inside the dropzone. Each transfer card shows live transfer rate and ETA (rolling 0.5 s sample window), and exposes a cancel button. Multiple incoming requests queue cleanly so none are lost. * public/js/auth.js: no longer dynamically imports app.js, accepts showNotification via init, surfaces 429 retryAfter, raises the password minimum to 8. * public/js/chat.js: exposes getActiveChatTarget() so app.js can decide whether an inbound chat should toast. * public/js/dashboard.js: avatar palette refined to the new theme; activity feed restructured for typographic detail rather than emoji glyphs. UI -- * New 'Obsidian Gallery' theme: graded obsidian surfaces, platinum text, champagne-gold accents, hairline borders, deep soft shadows. * Cormorant Garamond serif for the wordmark and section headings, Inter for body. The italic 'Drop' in the brand carries the gold gradient. * Subtle SVG noise grain over the obsidian field; three slow aurora orbs (champagne, plum, slate) drift over 38–54 s. * All UI emojis replaced with an inline SVG sprite (hex, user, lock, power, upload, download, inbox, chat, send, close). * Drop zone, transfer cards, modals, and notifications redesigned with restrained motion, tracked uppercase labels, and tabular numerals for sizes and percentages. * Page-wide drag overlay shows a champagne-tinted dashed border whenever a file enters the window. * Reduced-motion media query disables animations for users who prefer that. * New theme-color and color-scheme metas; ARIA attributes added on modals, tabs, and notification regions. Tests ----- * All server and client modules pass node --check. * End-to-end HTTP smoke test verifies status codes, security headers, the scoped 404 for unknown /api routes, and the rate limiter triggering on the configured threshold. Co-authored-by: isilicon <219942559+isiliconx@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request was created by @kiro-agent on behalf of @isiliconx 👻
Comment with /kiro fix to address specific feedback or /kiro all to address everything.
Learn about Kiro autonomous agent
Summary
This PR addresses every issue from the recent code review and reskins the app to a more refined aesthetic.
Security & correctness
server/config.js). Production fail-fast on missing/placeholderJWT_SECRET; development gets an ephemeral random secret with a clear warning. No more duplicate secret reads inauth.jsandindex.js.maxHttpBufferSizelowered from 100 MiB to 4 MiB.reasonfield (cancelled_by_peer|peer_disconnected|idle_timeout)./login(5/15 m) and/register(5/1 h); per-socket on chat messages.users.json. The previous read-modify-write was racy; now goes through a single-writer queue with temp-file + rename.X-Content-Type-Options,X-Frame-Options: DENY,Referrer-Policy: no-referrer,Permissions-Policylocking down camera/mic/geo/payment, and a tight CSP allowing self + Google Fonts + Socket.IO CDN. Pluscompression.*via env./api/*fall-throughs now return JSON 404 instead of the SPA shell.SIGINT/SIGTERM/uncaughtException, with aserver:shutdownbroadcast and 10 s force-exit safety net.Client cleanups
logoutimport and the dynamicimport('./app.js')workaround for the circular dependency inauth.js.escapeHtmlrewritten as a regex+lookup table (no DOM allocation).pendingFileis now a correlation-idMap, removing the race when multiple transfer requests are in flight.retryAfternow surfaced in the auth UI.UI — Obsidian Gallery theme
A full reskin built around restraint:
--ink-0through--ink-4), platinum text scale (--pearl-100through--pearl-05), champagne-gold accents.prefers-reduced-motionis honoured.theme-color/color-schememetas; ARIA attributes on modals, tabs, and the toast region.Testing
node --check.GET /with full security header set/api/unknownreturns JSON 404 (scoped catch-all working)Notes for reviewers
compression(~10 KB).JWT_SECRETin.envis now blank by default (so dev gets the auto-generated ephemeral secret). For production, set it to a long random string (the example has the one-liner).users.jsonschema is unchanged; existing accounts work without migration. Existing passwords stay valid (any new ones are hashed at cost 12).