# dove: condensed implementation context Status vocabulary: - SHIPPED: verified in current source. - DESIGNED: approved behavior that may not be released. - FUTURE: direction without an availability or timing promise. Source precedence: current tests/source, then current CLI help, then approved design documents, then marketing copy. Preserve conflicts; never merge planned syntax into shipped docs. ## Product and security boundary dove shares files from infrastructure the operator controls. Simple tier stores an object in a private S3 bucket and prints a presigned URL. Full tier encrypts locally and uploads ciphertext; a gate enforces expiry, one/N downloads, and optional PIN access without receiving the URL-fragment secret. A full link is `https:///d/#`. Browsers and ordinary HTTP clients do not send the fragment. The default page reads it locally. Filename, sender name, and message are encrypted with a domain-separated metadata key and stored server-side only as opaque ciphertext. Full file container, big-endian: `"DOVE" | version:u8 | nonce_prefix:[u8;8] | chunk_size:u32`, followed by repeated `is_last:u8 | ct_len:u32 | AES-256-GCM ciphertext_and_tag`. Default plaintext chunk size is 1 MiB. Nonce is the random prefix plus a u32 counter. Counter and `is_last` are AAD, so changes, reordering, and truncation fail authentication. PIN shares derive the content key with PBKDF2-HMAC-SHA256(PIN, salt=fragment_secret), 600,000 iterations. The gate verifies submitted PINs online against a stored SHA-256 share-bound verifier and locks after five wrong attempts. The gate sees the PIN but not the fragment; the link has the fragment but not the PIN. Non-guarantees: simple plaintext is readable by infrastructure; a recipient can copy decrypted bytes; traffic metadata and object size remain; a compromised endpoint can read local secrets; an operator controls its own HTML and a malicious page could exfiltrate the fragment. The server-cannot-read claim assumes the audited default page or a customization that preserves the no-exfiltration contract. ## SHIPPED CLI `dove provision [--bucket NAME] [--region REGION] [--profile PROFILE] [--expire-days DAYS]` - region default us-east-1; expire-days default 7 - profile selection and final confirmation are interactive when applicable `dove share [--expires DUR] [--encrypt] [--downloads N] [--pin [VALUE]] [--from NAME] [--message TEXT]` - expires default 3d; duration is positive integer plus d/h/m/s - directory is zipped; symlinks skipped - full always encrypts; default full download budget 100 - bare --pin generates a six-digit PIN - PIN, from, and message are rejected outside full. Downloads has an effect only in full; the current simple path silently ignores it. Zero downloads creates no usable budget. - a supplied PIN is not CLI-validated; use 4-6 numeric digits for browser compatibility. Simple expiry max seven days. `dove get [-o|--out PATH] [--pin PIN]` - requires no provisioned backend `dove ls` `dove revoke ` `dove status` `dove use ` `dove domain add ` `dove gate disable|enable|status` Missing: stable --json, stdin upload, batch sharing, unattended provision, destroy, released file-request commands. ## SHIPPED gate routes - `GET /d/`: static HTML page; no policy decrement. - `GET /meta/`: expiry, size, budgets, opaque metadata, pin_required, locked; no decrement. - `GET /verify/?pin=...`: PIN rate-limit/lock pre-check; no decrement. - `GET /dl/?pin=...`: policy check and atomic decrement, then 302 to 15-minute presigned S3 GET. - `GET /og.png`: generic preview image. The browser must not call `/dl` on load. Files below 2 GB use WebCrypto; at 2 GB and above the page shows the complete `dove get ` handoff. ## SHIPPED core API `Transfer`: - `share(&self, ShareRequest, &dyn Progress) -> Result` - `get(&self, GetRequest, &dyn Progress) -> Result` - `list(&self) -> Result>` - `revoke(&self, id: &str) -> Result<()>` - `status(&self) -> Result` `ShareRequest`: path PathBuf, expires Duration, encrypt bool, downloads Option, pin/from/message Option. `Share`: id String, link String, size u64, expires_at u64. `GetRequest`: url String, out Option, pin Option. `Fetched`: path PathBuf, from/message Option. `Progress`: step(label), done(label), field(key,value), bytes(uploaded,total). `Silent` is provided. Resolve active backend with `dove_core::resolve(&Registry)`. `self-hosted` works. External `dove-` discovery exists, but subprocess dispatch/wire protocol is not implemented. Provisioning core: - `provision_simple(&ProvisionArgs, Option, &dyn Progress) -> anyhow::Result` - `provision_full(&ProvisionArgs, Option, Option, &dyn Progress) -> anyhow::Result` - ProvisionArgs: bucket Option, region String, expire_days u32. Core assumes the caller selected identity/confirmed and returns config; caller persists it. ## SHIPPED provisioning Simple: private S3 bucket, all public access blocked, lifecycle cleanup, scoped IAM user/key limited to S3 Get/Put/Delete/List on one bucket. Secrets at `~/.config/dove/secrets.toml` (0600 Unix). Config at `~/.config/dove/config.toml`. XDG_CONFIG_HOME relocates both; DOVE_CONFIG overrides only config registry. Full adds S3 CORS, DynamoDB PAY_PER_REQUEST table with TTL, gate IAM role, stable HMAC secret in SSM SecureString, Python 3.12 gate Lambda, API Gateway HTTP API, CloudFront, and cost breaker. Stage throttle is burst 50/rate 25 per second. Breaker triggers above 5,000 invocations in five minutes and sets gate concurrency zero. `dove gate enable` removes the override. Provision is idempotent where implemented: reuses resource names, existing access key, API, distribution, gate secret, and custom gate URL. No destroy command exists. ## Custom page checklist Current customization is source-level: build a self-contained recipient page, replace `dove-core/assets/share.html`, test, then re-run `dove provision full` to update Lambda. No theme manifest/runtime plugin exists. Preserve: no fragment/PIN/plaintext logs or network egress; no decrement on load; explicit download click; local decryption; authenticated chunk order/termination; PIN remaining-attempt and terminal locked UI; expiry/gone/limit/integrity/network states; browser accessibility; 2 GB handoff; canonical install pointer to dove.sh; no third-party scripts by default. ## DESIGNED, not released File requests reverse the flow: requester creates a PIN-protected request, browser encrypts one file locally, and the gate authorizes a short-lived upload to requester-owned storage. Proposed request commands and routes are not current CLI contracts.