Commit Graph
5 Commits
Author SHA1 Message Date
thandClaude Opus 4.7 d83de30d6d security: v2.0 — AES-GCM crypto, SSRF guards, rate limits, hardening
Breaking wire-format change: dual-read (V1+V2) / single-write (V2) so
existing user secrets, stored messages, and inter-tenant key keep
working. Old clients and relays lose cross-version chat until both
sides are upgraded.

Relay
- Switch clientEncrypt/masterEncrypt to AES-256-GCM with HKDF-derived
  per-ciphertext salts; keep CBC-V1 fallback on decrypt only.
- On-bootstrap migration re-envelopes tenant secret_encrypted and the
  inter-tenant key to GCM-V2 (idempotent).
- CORS: stop reflecting arbitrary Origin; allow own origin + optional
  RELAY_CORS_ORIGINS env allowlist; drop Access-Control-Allow-Credentials.
- Generic error messages replace "no such user: <name>" enumeration.
- Exception messages no longer echoed back; logged server-side.
- Collab-lock max hold capped at 10min so a member can't grief-refresh
  forever.
- Attachment filenames validated against hex.<ext> pattern.
- Passwords min length 10; /api/account/password rate-limited.

App / Electron client
- Shared hyprcrdRelayEncrypt/Decrypt helpers (GCM-V2 write, V1 read).
- Chat + collab-buckets plugins delegate to the shared helpers.
- Poll + push + attachments migrated to the dual-format path.
- /api/relay/settings GET returns has_key boolean; secret never echoed.
- Setup endpoint now CSRF-checked.
- SSRF: CURLOPT_PROTOCOLS restricted to HTTP(S) everywhere; bookmarks
  favicon fetch also blocks private/loopback/link-local.
- Login / password-change rate limiter moved to DB-backed IP keying.
- Passwords min length 10 throughout.
- Zip import enforces per-file (25MB) and total (500MB) caps, extension
  allowlist, no-overwrite.
- Verbose relay-push debug gated behind APP_DEBUG env.

Version bumped to 2.0.0 (protocol-breaking).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 17:02:04 +02:00
thandClaude Opus 4.6 6c0ca4373b relay: file attachments, outbox, CC-self, chat view, mobile layout
Compose: attach files (encrypted, hex-named, linked via relay_uid),
CC-self checkbox tags copy with recipient name. Outbox section shows
sent messages with delete. Chat view: session-based threads/history/
send endpoints, split layout with sidebar, read receipts, 5s poll.
Mobile: threads as horizontal scroll bar above messages. Fix chat
input pushed offscreen by adding min-height:0 on flex container.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 08:48:23 +02:00
thandClaude Opus 4.6 c16659c2ad new-card unread dot + pulse fix, relay inbox readable, UI polish pass
Board: new-card unread indicator (public/js/modules/board.js,
public/js/modules/buckets.js, public/js/modules/state.js,
public/css/style.css):

* state.unseenCardIds (Set) tracks card ids that arrived since the
  last visit to the "all" view. Diff runs in renderBoard() against a
  module-private knownCardIds snapshot.
* Bug fix: the first renderBoard runs with state.cards = [] (before
  the API returns). The previous diff treated every card from the
  real load as "new" and pulsed the entire board. Now the diff is
  skipped when knownCardIds is null or empty — the first non-empty
  render is a silent prime.
* When activeBucket === 'all' and unseenCardIds is non-empty, the set
  is drained and every matching board card gets a 3-cycle accent glow
  (`.card-pulse-new`, 0.8s × 3, pinned for anim-fast/slow). Works
  both when navigating TO all and when a poll arrives while already
  on all.
* When the user is on a different bucket: unseenCardIds accumulates
  across polls and a red dot (`.bar-unread-dot`) appears on the "all"
  tab. Position is top:3px right:3px *inside* the tab to survive
  the double overflow clip (`#main-header overflow:hidden` +
  `#bucket-bar overflow-x:auto`). renderBar() bakes the dot into the
  all-tab template on every render so it survives bar re-renders that
  aren't followed by a board render.
* decorateAllUnreadDot() in board.js is a fallback called at the end
  of every renderBoard for cases where the diff changed unseenCardIds
  but renderBar hasn't run yet.

Relay: readable inbox (relay/inc/routes/messages.php,
relay/ui/app.js, relay/ui/layout.php, relay/ui/style.css):

* New session-based GET /api/messages/inbox — returns up to 200
  messages for the logged-in user, decrypted server-side with the
  inter-tenant key (no extra leakage — the relay already sees
  plaintext during the routing hop). Does NOT mark messages as
  fetched; the hyprcrd client is still the canonical receiver.
* loadInbox() now fetches from /api/messages/inbox and renders
  actual inbox items: sender (with user-circle icon + accent2),
  optional title (bold), body (pre-wrap, max-height 120px), relative
  timestamp (formatRelTime: "just now", "2 min ago", "today 14:32",
  "3 d ago", or YYYY-MM-DD for older). Unfetched messages show a
  small "new" accent badge next to the sender name.
* deleteMessage(id, btn) — confirms, calls existing DELETE
  /api/messages/{id} (already session-aware), removes the DOM row,
  re-loads the list, toasts "message deleted".
* Auto-poll: startInboxPoll / stopInboxPoll refresh the inbox every
  15s while the compose view is active. Stops on view switch.
* Header-status badge: mirrors the real message count (not just the
  /api/status count) and toggles the has-unread class + dot so the
  tap-to-scroll-to-inbox target stays fresh.

Relay UI polish (relay/ui/style.css):
* .header-status is now a clickable button with tray icon, hover
  tint, focus-ring, and a red dot (::after pseudo) when has-unread.
  jumpToInbox() scrolls smoothly to #inbox-section and flashes it
  with a 1.6s accent box-shadow pulse.
* .inbox-item .from is flex-row with icon + badge-new pill.
* .inbox-item .del gets hover-background for better mobile tappability.
* @keyframes flash-highlight for the scroll-to-inbox animation.

chore: bump version to 0.9.9

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 09:09:29 +02:00
th ef238f3b9c image push fix 2026-04-10 18:50:04 +02:00
th 5b18c46ac2 multi-tenant relay und card-push to user 2026-04-10 18:23:07 +02:00