5 Commits

Author SHA1 Message Date
ordinarthur
48ace8af34 feat(web): native share sheet for created + saved links
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 39s
Adds a "Share link" button that invokes navigator.share() so iOS
home-screen PWA users (and any platform with the Web Share API)
get the system share sheet — AirDrop, Messages, Mail, WhatsApp…
Falls back to copy-only on platforms without support.

Wired on both CloudSharePanel (just-created link) and Settings →
Shared links (re-share an existing one).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 15:31:38 +02:00
ordinarthur
54021f88d8 refactor(design): brighter modern blue ink (#2563EB)
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 37s
Shift ink from Prussian-deep #1E3A8A to the brighter blue-600 #2563EB
(Linear/Notion register). Muted + faint tokens follow into cooler
blue-grays. QR codes and rule-strong border updated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 13:01:57 +02:00
ordinarthur
3ed673e215 feat(design): shift ink tokens to deep modern blue
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 43s
All text, borders and QR codes now render in blue-ink on cream paper.
ink #1A1714 → #1E3A8A, ink-muted warm → cool blue-gray, rule-strong
+ QR fgColor updated to match.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 12:59:14 +02:00
ordinarthur
dbd500b0b5 feat: simpler Home + password-protected cloud links
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 51s
Home is now two sections, no clutter:

- Nearby — tap a device on the same Wi-Fi and the composer takes its
  place (drop files, optionally write a note, send). Pair-across-networks
  and public-room panels moved off the main page into the footer as a
  single discrete link (/pair).
- Share a link — inline WeTransfer-style card. Pick a file, optionally
  expand email / password / expiry, upload. Result shows QR + copy link
  + the password to share out-of-band.

The password gate is a server-side access control layer on top of the
existing E2E encryption: scrypt-hashed on create, verified on consume.
The encryption key still lives only in the URL fragment; the password
does not participate in the crypto.

- server: password_hash column (migration 0002), scrypt+timingSafeEqual
  verify on /consume, requiresPassword surfaced on the HEAD response.
- web: Composer merges drop zone + text note into one surface; Receive
  shows a password prompt when requiresPassword is true and recovers in
  place on a wrong attempt.
- responsive: mobile-first paddings, DeviceChip shrinks on narrow widths,
  no 2-col grids on the main page.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 11:54:05 +02:00
ordinarthur
0b639dfc3c feat: encrypted cloud relay (Phase 2)
Adds a "Via AnyDrop" flow for senders who need to reach someone not
present on the mesh. The file is sealed client-side (XChaCha20-Poly1305),
uploaded directly to an in-cluster MinIO bucket via a presigned PUT, and
handed off to the recipient as a URL whose fragment carries the key.
The server only ever sees ciphertext, opaque metadata blobs, and sizes.

- server: transfers table (drizzle migration), /api/transfers CRUD +
  consume endpoint, presigned PUT/GET via @aws-sdk/client-s3, cleanup
  loop that purges expired + exhausted blobs.
- web: @noble/ciphers sealFile/openFile, high-level sendCloud/receive
  helpers, CloudSharePanel on Home, /r/:id receive page, /inbox page
  for signed-in users (sent + received tabs).
- k8s: MinIO StatefulSet with bucket-init initContainer, S3 env vars
  on the server Deployment (credentials pulled from minio-credentials
  Secret).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 11:09:58 +02:00