Secure Files: encrypted .mydt file vault, shared format crate and CLI - #312
Open
itsmeakhil wants to merge 2 commits into
Open
Secure Files: encrypted .mydt file vault, shared format crate and CLI#312itsmeakhil wants to merge 2 commits into
itsmeakhil wants to merge 2 commits into
Conversation
…nd CLI
Adds the Secure Files tool ("Files" in the UI): import files or folders and
store them as opaque `<32 random hex>.mydt` objects in a storage folder the
user picks. Original names, folder paths, types and contents are encrypted;
the app shows them only while the vault is unlocked.
Format (docs/MYDT_FORMAT.md, crates/mydt):
- Self-contained per file: Argon2id salt/params + per-file DEK wrapped by the
key derived from the master password + XChaCha20-Poly1305 metadata and
payload, with the header bound in as AAD. No index — listing scans the
folder and decrypts headers, so a folder is portable and self-healing.
- Extracted into the standalone `mydt` crate: library plus a `mydt` CLI
(encrypt/decrypt/info/ls) behind `--features cli`, so the desktop app and
the CLI read and write identical objects. Wired into rust.yml.
Desktop:
- New `/api/v1/secure-files/*` routes: settings, list, import, patch, replace,
export, delete, folder rename/delete; raw-bytes `secure_file_read` command
for previews.
- The webview gate hands the verified master password to Rust once per unlock
so Argon2id can derive the Secure Files key; it lives in AppState only and
is dropped on lock (idle auto-lock included).
- Listing keeps a decrypted-metadata cache reconciled by an id-set diff, and
import encrypts across threads with one directory fsync per batch. 10k
files: import 1.75s, cold list 0.30s, warm list 24ms.
UI:
- Folder tree, list and grid views (both virtualized), preview for text,
code, images and PDF, export with a plaintext warning, rename/move/replace,
dismissible warning for unreadable objects. Files up to 20 MB.
- Fixes a latent bug in the shared s3-drive FilePreviewDialog, which used
Radix Tooltip without a TooltipProvider and crashed the dialog subtree.
`pnpm i18n:sync` also backfilled unrelated missing keys across the 26
non-English locales, which is why messages/ is broad.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01No7es2PjF9SNQs22RYHcdM
Grid tiles show the actual image instead of a type icon, Drive-style. Only the tiles currently on screen are decrypted (the hook is fed the same visible window the virtualizer computes), at most three at a time, and the queue re-prioritizes on scroll. Each image is downscaled to 256px and re-encoded before it is kept, so the plaintext original is dropped right away and the blob pool stays bounded — 150 thumbnails, oldest off-screen ones revoked, everything revoked when the tool unmounts on lock. Cache keys include size and mtime so Replace invalidates a stale thumbnail. SVG skips the canvas (WKWebView cannot createImageBitmap it) and anything that fails to decode falls back to its icon without retrying. Also moves blobMime into lib/secure-files.ts so the preview and thumbnail paths share one implementation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01No7es2PjF9SNQs22RYHcdM
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
ThreatCrush Security Scan0 finding(s) No findings. |
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.
Adds Files (Secure Files), an offline encrypted file vault, plus the
.mydtformat as a standalone crate and CLI.Import files or folders and they are stored as opaque
<32 random hex>.mydtobjects in a storage folder you pick. Original names, folder paths, types and contents are encrypted — outside the app the folder is unreadable noise; inside, after unlocking, it looks like a normal file browser.Format
Each
.mydtis self-contained: Argon2id salt/params, a per-file DEK wrapped by the key derived from the master password, and XChaCha20-Poly1305 metadata + payload, with the header bound in as AAD. No index — listing scans the folder and decrypts headers, so a storage folder is portable and self-healing (a copied or corrupt object is reported, never fatal).Spec:
docs/MYDT_FORMAT.md. Implementation lives incrates/mydt— a library plus amydtCLI (encrypt/decrypt/info/ls) behind--features cli, used unchanged by the desktop app so both sides read and write identical objects.Desktop
/api/v1/secure-files/*: settings, list, import, patch, replace, export, delete, folder rename/delete; a raw-bytessecure_file_readcommand for previews.AppStateonly and is dropped on lock, including idle auto-lock.UI
Folder tree, list and grid views (both virtualized), image thumbnails in grid, preview for text/code/images/PDF, export with a plaintext warning, rename/move/replace, and a dismissible warning for unreadable objects. Files up to 20 MB.
Also fixes a latent bug in the shared s3-drive
FilePreviewDialog: it used RadixTooltipwithout aTooltipProvider, which crashed the dialog subtree for any consumer that did not supply one.Verification
cargo test(69, including a tamper/truncation/garbage mutation sweep over every byte of the container),mydtcrate tests, jest,tsc,i18n:audit, and a manual pass in the desktop app: import, preview, rename, move, replace, export, lock/unlock, and confirming the storage folder holds only masked objects with no plaintext names.Notes
pnpm i18n:syncalso backfilled unrelated missing keys across the 26 non-English locales, which is whymessages/is broad.🤖 Generated with Claude Code
https://claude.ai/code/session_01No7es2PjF9SNQs22RYHcdM