4 Commits

Author SHA1 Message Date
ordinarthur
2452f2642a feat: inbox of received transfers in /settings
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 47s
Auto-claim on receive so /settings shows transfers others sent you.
Filename decryption stays client-side using the key stored in localStorage
when the share link is opened.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 12:47:10 +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
ordinarthur
2913618ee6 feat: stealth accounts + data layer (Phase 1)
Some checks failed
Build & Deploy / build-and-deploy (push) Failing after 1m47s
2026-04-20 09:57:22 +02:00