@@ -5,9 +5,9 @@ import Link from "next/link";
55import { DONATE_PATH , APP_URL } from "@/lib/config" ;
66
77const FAQ_TITLE =
8- "FAQ — Flowvault: encrypted online notepad, Cmd+K in-memory search, Markdown preview, Bring-Your-Own-Storage local vaults, trusted handover to a beneficiary, time-locked notes, Encrypted Send, encrypted backup & restore; ProtectedText / Standard Notes / CryptPad / Privnote / Bitwarden Send alternative" ;
8+ "FAQ — Flowvault: encrypted online notepad, Cmd+K in-memory search, Markdown preview, Bring-Your-Own-Storage local vaults, trusted handover to a beneficiary, time-locked notes, Encrypted Send, Encrypted File Send (10 MiB self-destructing file uploads with a secure delete link), encrypted backup & restore; ProtectedText / Standard Notes / CryptPad / Privnote / Bitwarden Send alternative" ;
99const FAQ_DESCRIPTION =
10- "Honest answers about Flowvault: how plausible-deniability hidden volumes work, how the Cmd+K command-palette search runs entirely in memory over the notebooks you've already unlocked (no persistent index, no server round-trip, deniability preserved), how the Markdown preview renders GitHub-flavored Markdown safely (HTML blocked, external images click-to-load, no-referrer links, syntax-highlighted code), how Bring-Your-Own-Storage local vaults keep the entire ciphertext on your own disk as a single .flowvault file, how the trusted handover releases a vault to a beneficiary if you stop checking in, how drand-backed time-locked notes keep messages sealed until a future date, how Encrypted Send creates self-destructing one-time links with view caps and optional passwords, how zero-knowledge .fvault backup and restore let you migrate or self-host without decrypting anything server-side, and how Flowvault compares to ProtectedText, Standard Notes, CryptPad, Privnote, OneTimeSecret, PrivateBin, Yopass, Notesnook, Joplin, Obsidian, Bitwarden Send, 1Password Share, and Skiff Notes." ;
10+ "Honest answers about Flowvault: how plausible-deniability hidden volumes work, how the Cmd+K command-palette search runs entirely in memory over the notebooks you've already unlocked (no persistent index, no server round-trip, deniability preserved), how the Markdown preview renders GitHub-flavored Markdown safely (HTML blocked, external images click-to-load, no-referrer links, syntax-highlighted code), how Bring-Your-Own-Storage local vaults keep the entire ciphertext on your own disk as a single .flowvault file, how the trusted handover releases a vault to a beneficiary if you stop checking in, how drand-backed time-locked notes keep messages sealed until a future date, how Encrypted Send creates self-destructing one-time links with view caps and optional passwords, how Encrypted File Send adds 10 MiB self-destructing file uploads with a separate secure delete link, how zero-knowledge .fvault backup and restore let you migrate or self-host without decrypting anything server-side, and how Flowvault compares to ProtectedText, Standard Notes, CryptPad, Privnote, OneTimeSecret, PrivateBin, Yopass, Notesnook, Joplin, Obsidian, Bitwarden Send, 1Password Share, and Skiff Notes." ;
1111
1212export const metadata : Metadata = {
1313 title : FAQ_TITLE ,
@@ -35,9 +35,14 @@ export const metadata: Metadata = {
3535 "drand tlock" ,
3636 "plausible deniability notes" ,
3737 "encrypted send" ,
38+ "encrypted file send" ,
3839 "one-time secret link" ,
3940 "self-destructing note" ,
41+ "self-destructing file upload" ,
42+ "secure file sharing" ,
4043 "burn after reading" ,
44+ "burn after download file" ,
45+ "secure delete link" ,
4146 "encrypted notepad backup" ,
4247 "zero-knowledge backup file" ,
4348 "Flowvault backup" ,
@@ -1289,12 +1294,16 @@ const FEATURES: QA[] = [
12891294 q : "Does Encrypted Send support files or just text?" ,
12901295 a : (
12911296 < >
1292- Text only for now. Plaintext is capped at 128 KiB —
1293- plenty for credentials, recovery phrases, configs, a long
1294- paragraph of context. File attachments are on the roadmap and
1295- would use Firebase Storage with a similar URL-fragment-keyed
1296- wrap; they’ll ship when we can do it without bloating
1297- the threat model.
1297+ Encrypted Send itself is text-only (plaintext capped at
1298+ 128 KiB). For files, use the sibling{ " " }
1299+ < Strong > Encrypted File Send</ Strong > at{ " " }
1300+ < Link href = "/file/new" className = "text-accent hover:underline" >
1301+ /file/new
1302+ </ Link > { " " }
1303+ — same threat model, same URL-fragment-keyed AES-GCM
1304+ wrap, but sized for documents and screenshots up to
1305+ 10 MiB. The encrypted bytes live in Cloud Storage rather
1306+ than Firestore. See the dedicated entries just below.
12981307 </ >
12991308 ) ,
13001309 } ,
@@ -1312,6 +1321,193 @@ const FEATURES: QA[] = [
13121321 </ >
13131322 ) ,
13141323 } ,
1324+ {
1325+ q : "What is Encrypted File Send?" ,
1326+ a : (
1327+ < >
1328+ The file-shaped sibling of Encrypted Send. Drop a file at{ " " }
1329+ < Link href = "/file/new" className = "text-accent hover:underline" >
1330+ /file/new
1331+ </ Link > { " " }
1332+ (up to < Strong > 10 MiB</ Strong > ), pick how long it lives
1333+ (max < Strong > 7 days</ Strong > ) and how many times it can be
1334+ downloaded (default 1, up to 10), and you get back{ " " }
1335+ < Strong > two</ Strong > links:
1336+ < ul className = "mt-2 list-disc space-y-1 pl-5" >
1337+ < li >
1338+ A < Strong > download link</ Strong > for the recipient
1339+ (< Code > useflowvault.com/file/<id>#k=<key></ Code > ).
1340+ </ li >
1341+ < li >
1342+ A < Strong > secure delete link</ Strong > for you to keep
1343+ (< Code >
1344+ useflowvault.com/file/<id>/delete#t=<token>
1345+ </ Code > ) — opening it lets you destroy the upload
1346+ immediately, before the cap or expiry.
1347+ </ li >
1348+ </ ul >
1349+ < p className = "mt-3" >
1350+ Optional password gate works the same way as Encrypted
1351+ Send. Read the{ " " }
1352+ < Link
1353+ href = "/blog/encrypted-file-send-zero-knowledge-uploads"
1354+ className = "text-accent hover:underline"
1355+ >
1356+ File Send deep dive
1357+ </ Link > { " " }
1358+ for the full protocol walkthrough.
1359+ </ p >
1360+ </ >
1361+ ) ,
1362+ } ,
1363+ {
1364+ q : "How is the file actually encrypted?" ,
1365+ a : (
1366+ < >
1367+ < p >
1368+ AES-256-GCM in your browser before any byte leaves your
1369+ device. The exact key tree:
1370+ </ p >
1371+ < ol className = "mt-2 list-decimal space-y-1 pl-5" >
1372+ < li >
1373+ A random 256-bit key < Code > K</ Code > is generated client-side.
1374+ It travels in the URL fragment (< Code > #k=…</ Code > ); browsers
1375+ never transmit fragments to servers.
1376+ </ li >
1377+ < li >
1378+ If a password is set, an Argon2id key is derived from it
1379+ (64 MiB / 3 iterations) and concatenated with{ " " }
1380+ < Code > K</ Code > to form the base material.
1381+ </ li >
1382+ < li >
1383+ Two HKDF subkeys are derived: a{ " " }
1384+ < Code > contentKey</ Code > (used to AEAD-encrypt the file
1385+ bytes, uploaded to Cloud Storage) and a{ " " }
1386+ < Code > metadataKey</ Code > (used to AEAD-encrypt a small JSON
1387+ blob with the filename, MIME type, and size, stored in
1388+ Firestore).
1389+ </ li >
1390+ < li >
1391+ A separate random 256-bit < Strong > delete token</ Strong > is
1392+ generated. The server stores only its{ " " }
1393+ < Strong > SHA-256 digest</ Strong > ; the raw token lives in
1394+ your secure delete link, so possession of the link is the
1395+ only thing that authorizes deletion.
1396+ </ li >
1397+ </ ol >
1398+ < p className = "mt-3" >
1399+ Direct reads on the Storage object and the Firestore
1400+ document are denied by rules. The only path to the bytes is{ " " }
1401+ < Code > readFileSend</ Code > , a Cloud Function that atomically
1402+ consumes a download in a Firestore transaction and returns a
1403+ 5-minute v4 signed URL.
1404+ </ p >
1405+ </ >
1406+ ) ,
1407+ } ,
1408+ {
1409+ q : "What does the server actually see for a file send?" ,
1410+ a : (
1411+ < >
1412+ Same disclosure standard as the rest of Flowvault. The server
1413+ sees:
1414+ < ul className = "mt-2 list-disc space-y-1 pl-5" >
1415+ < li >
1416+ The opaque ciphertext bytes in Cloud Storage at{ " " }
1417+ < Code > fileSends/<id></ Code > (file size + 28 bytes of
1418+ AEAD overhead).
1419+ </ li >
1420+ < li >
1421+ A small encrypted metadata blob in Firestore (server
1422+ can't open it).
1423+ </ li >
1424+ < li >
1425+ Expiry, max downloads, current download count.
1426+ </ li >
1427+ < li >
1428+ A boolean < Code > passwordProtected</ Code > flag and, when
1429+ set, a 16-byte Argon2id salt — useless without the
1430+ password and the URL fragment.
1431+ </ li >
1432+ < li >
1433+ The 32-byte SHA-256 of the delete token. Useless without
1434+ the original token.
1435+ </ li >
1436+ </ ul >
1437+ < p className = "mt-3" >
1438+ It does < em > not</ em > see the filename, MIME type, file
1439+ content, AES key, password, delete token, or any account /
1440+ email / persistent identifier — because none exist.
1441+ </ p >
1442+ </ >
1443+ ) ,
1444+ } ,
1445+ {
1446+ q : "Can Flowvault delete a file send for me?" ,
1447+ a : (
1448+ < >
1449+ Two ways an upload gets removed, both server-side:
1450+ < ul className = "mt-2 list-disc space-y-1 pl-5" >
1451+ < li >
1452+ The recipient consumes the final allowed download. The
1453+ Cloud Function deletes the Firestore doc immediately and
1454+ the scheduled < Code > fileSendsSweep</ Code > drops the
1455+ Storage object on the next tick (after the 5-minute
1456+ signed-URL grace window expires).
1457+ </ li >
1458+ < li >
1459+ The expiry passes. < Code > fileSendsSweep</ Code > deletes
1460+ both the doc and the object on the next hourly run.
1461+ </ li >
1462+ </ ul >
1463+ < p className = "mt-3" >
1464+ You can also force an immediate delete yourself by opening
1465+ your < Strong > secure delete link</ Strong > . The Cloud Function{ " " }
1466+ < Code > deleteFileSend</ Code > SHA-256s the token from your URL
1467+ fragment, compares it to the stored hash in constant-ish
1468+ time, and (on match) drops the Storage object plus the
1469+ Firestore document. We can’t recover the upload after
1470+ that, and we can’t do this on your behalf because we
1471+ never stored the raw token.
1472+ </ p >
1473+ </ >
1474+ ) ,
1475+ } ,
1476+ {
1477+ q : "Why 10 MiB and 7 days, exactly?" ,
1478+ a : (
1479+ < >
1480+ File Send is deliberately sized for documents and
1481+ screenshots, not large transfers. < Strong > 10 MiB</ Strong > { " " }
1482+ is the cap because that’s the line where browser
1483+ encryption + Cloud Function + signed-URL plumbing stays
1484+ snappy on a phone over 4G; above it the better tool is
1485+ Bitwarden Send Files, OnionShare, or Magic Wormhole.{ " " }
1486+ < Strong > 7 days</ Strong > is the retention cap because, in
1487+ practice, almost every legitimate use case finishes within
1488+ 72 hours, and a hard ceiling reduces the window where a
1489+ forgotten upload can leak. The cap can be raised in a future
1490+ release, but it will stay scoped to ephemeral file transfer
1491+ rather than “cloud storage.”
1492+ </ >
1493+ ) ,
1494+ } ,
1495+ {
1496+ q : "What if I lose the secure delete link?" ,
1497+ a : (
1498+ < >
1499+ Same answer as “what if I lose my password” for the
1500+ rest of Flowvault: we can't recover it. The server only
1501+ ever stored the SHA-256 of the delete token; the raw token
1502+ existed exactly once, in the link we showed you on the
1503+ success screen. Without it, the upload sits until the expiry
1504+ or the download cap is consumed and then gets swept. Treat
1505+ the secure delete link the same way you treat the download
1506+ link: copy it, save it somewhere you control, understand we
1507+ can't re-derive it later.
1508+ </ >
1509+ ) ,
1510+ } ,
13151511] ;
13161512
13171513const MARKDOWN : QA [ ] = [
@@ -1568,9 +1764,10 @@ const BYOS: QA[] = [
15681764 corresponds to. Your browser never uploads the ciphertext or
15691765 the file name to us. The one caveat is the editor chrome: if
15701766 you use server-dependent features while a local vault is
1571- open — time-locked notes composition, Encrypted Send
1572- — those specific flows still talk to our backend for
1573- their own documents (a time-locked capsule, a send record),
1767+ open — time-locked notes composition, Encrypted Send,
1768+ Encrypted File Send — those specific flows still talk
1769+ to our backend for their own documents (a time-locked
1770+ capsule, a send record, a file-send ciphertext object),
15741771 same as they would from a hosted vault. They never see your
15751772 local vault's plaintext or ciphertext.
15761773 </ >
@@ -1669,14 +1866,15 @@ const BYOS: QA[] = [
16691866 ) ,
16701867 } ,
16711868 {
1672- q : "What about time-locked notes and Encrypted Send from a local vault?" ,
1869+ q : "What about time-locked notes, Encrypted Send, and Encrypted File Send from a local vault?" ,
16731870 a : (
16741871 < >
16751872 Those still work — they have nothing to do with where
1676- your < em > vault</ em > lives. Composing a time-locked note or an
1677- Encrypted Send from the editor stores the one-shot capsule /
1678- send document in our backend the same way as always; only the
1679- notebook text lives in your local file.
1873+ your < em > vault</ em > lives. Composing a time-locked note, an
1874+ Encrypted Send, or an Encrypted File Send from the editor
1875+ stores the one-shot capsule / send document / file ciphertext
1876+ in our backend the same way as always; only the notebook text
1877+ lives in your local file.
16801878 </ >
16811879 ) ,
16821880 } ,
@@ -1872,8 +2070,10 @@ const BACKUP: QA[] = [
18722070 a : (
18732071 < >
18742072 Yes. The whole stack — Next.js frontend, Cloud Functions
1875- (the trusted-handover release sweep and the Encrypted Send read
1876- path), and Firestore security rules — is in one public
2073+ (the trusted-handover release sweep, the Encrypted Send /
2074+ File Send read & delete paths, and the file-send sweep),
2075+ Cloud Storage rules, and Firestore security rules —
2076+ is in one public
18772077 repository. Bring your own Firebase project, deploy the rules
18782078 and Functions, point the frontend at it, and drop a{ " " }
18792079 < Code > .fvault</ Code > file onto < Code > /restore</ Code > . Because
@@ -2234,8 +2434,10 @@ export default function FAQPage() {
22342434 already unlocked, Bring-Your-Own-Storage local vaults stored
22352435 as a single < Code > .flowvault</ Code > file on your device,
22362436 the trusted handover to a beneficiary, drand-backed
2237- time-locked notes, Encrypted Send, < Code > .fvault</ Code > { " " }
2238- encrypted backups and restore, and how Flowvault compares
2437+ time-locked notes, Encrypted Send, Encrypted File Send (10
2438+ MiB self-destructing file uploads with a separate secure
2439+ delete link), < Code > .fvault</ Code > encrypted backups and
2440+ restore, and how Flowvault compares
22392441 to ProtectedText, Standard Notes, CryptPad, and other
22402442 alternatives. If yours isn't here, open an issue on
22412443 GitHub.
@@ -2248,7 +2450,7 @@ export default function FAQPage() {
22482450 />
22492451 < Section title = "Security" items = { SECURITY } />
22502452 < Section
2251- title = "Trusted handover & time-locked notes"
2453+ title = "Trusted handover, time-locked notes, Encrypted Send & File Send "
22522454 items = { FEATURES }
22532455 />
22542456 < Section title = "Using Flowvault" items = { USAGE } />
@@ -2314,6 +2516,13 @@ export default function FAQPage() {
23142516 >
23152517 Encrypted Send vs Bitwarden Send vs Privnote
23162518 </ Link >
2519+ , a deep dive on{ " " }
2520+ < Link
2521+ href = "/blog/encrypted-file-send-zero-knowledge-uploads"
2522+ className = "text-accent hover:underline"
2523+ >
2524+ Encrypted File Send
2525+ </ Link >
23172526 , the{ " " }
23182527 < Link
23192528 href = "/blog/encrypted-backup-fvault-format"
0 commit comments