Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
69d8da5
feat(crypto): add multi-recipient envelope + agreement primitives
claude Jun 13, 2026
1cc04b3
feat(email): parse HYBRID/RECIPIENTS/CONSENT and sign per spec §4.2
claude Jun 13, 2026
d17d807
feat(agreement): add hybrid multi-recipient message encoder
claude Jun 13, 2026
de9fb0a
spec+impl: drop HYBRID keyword; select envelope path by RECIPIENTS pr…
claude Jun 13, 2026
65e25e6
feat(agreement): bind email in RECIPIENTS stanza (issue #102 prerequi…
claude Jun 13, 2026
5a6f2cd
feat(agreement): stateless email↔npub binding verifier (issue #102)
claude Jun 13, 2026
b9d3245
feat(agreement): thread-wide completion status (spec §11.5)
claude Jun 13, 2026
818019e
feat(email): decrypt multi-recipient envelopes + expose recipients/co…
claude Jun 13, 2026
8a0a36c
feat: plaintext (public) agreements (spec §11.8)
claude Jun 13, 2026
c36a9e6
refactor: content-typed optional RECIPIENTS tokens + reserve gift-wra…
claude Jun 13, 2026
038f62f
feat(send): agreement compose/send path + IPC commands
claude Jun 14, 2026
16c56d5
feat(agreement): encrypt the subject under the message CEK
claude Jun 14, 2026
a603850
fix(agreement): glossia-encode envelope body + subject (transport int…
claude Jun 14, 2026
a2a813c
feat(agreement): honor the user's Advanced glossia encoding setting
claude Jun 14, 2026
ec00d09
feat(agreement): independent subject encoding setting
claude Jun 14, 2026
8a8c51b
feat(ui): agreement compose + completion status
claude Jun 14, 2026
3bcee16
feat(ui): click-to-explain trust badges + verified-identity (binding)…
claude Jun 14, 2026
96fd585
feat(ui): Agreements nav tab + Create-agreement button; drop compose …
claude Jun 14, 2026
3ba113d
feat(ui): Cc viewer picker for agreement compose
claude Jun 14, 2026
879644e
feat(ui): one-at-a-time To (signatory) picker; unify recipient pickers
claude Jun 14, 2026
fb231bc
feat(ui): unified sent + received Agreements tab
claude Jun 14, 2026
82420ba
feat: Cc on normal compose — encrypted multi-recipient, keyless Cc al…
claude Jun 14, 2026
1d863b4
fix(compose): Cc respects the user's encrypt/sign choice (no forced e…
claude Jun 15, 2026
bf5d54a
feat: optional cleartext subject on encrypted mail (validator context)
claude Jun 15, 2026
fe85817
feat: sign↔SEAL parity on the encrypted envelope (Sign button)
claude Jun 15, 2026
7c4e846
Adopt AGE-style ephemeral CEK keys for the multi-recipient envelope
claude Jun 15, 2026
5dd39e9
Clarify SEAL carries the sender's identity, not the ephemeral key
claude Jun 15, 2026
e733d67
Add attachment support to the multi-recipient envelope path
claude Jun 15, 2026
09c484a
Wire attachments into the multi-recipient send (frontend)
claude Jun 15, 2026
34f99b1
spec: document the attachment manifest on the multi-recipient envelop…
claude Jun 15, 2026
e0ad7a5
Regenerate stale capnp bindings from schema
claude Jun 15, 2026
91d457d
Add Rust capnp manifest module (build + parse) and aes_gcm_encrypt_pa…
claude Jun 15, 2026
a11c675
Wire decode path to the unified manifest module
claude Jun 15, 2026
97962ab
Build the capnp manifest in Rust for the multi-recipient send path
claude Jun 15, 2026
ddedb3f
Enforce attachment ciphertext hash on decrypt
claude Jun 15, 2026
e3ec859
Bind public-agreement attachments via a signed ATTACHMENTS block
claude Jun 15, 2026
526f02b
spec: document capnp manifest, signed ATTACHMENTS block, enforced hashes
claude Jun 15, 2026
69ea3b9
Drop redundant base64 armor from the capnp manifest
claude Jun 15, 2026
958c0ea
docs: refresh capnp wire-format notes; spec externalized keyring (draft)
claude Jun 17, 2026
e00d77d
Merge pull request #106 from asherp/claude/loving-gauss-7x130r
asherp Jun 30, 2026
47ae003
test: pass empty cc to send_email in integration tests
claude Jun 30, 2026
c0686f8
Recognize armor markers in quoted (> -prefixed) reply lines
claude Jun 30, 2026
8747604
Enforce public-agreement attachment binding on receive
claude Jun 30, 2026
d66c829
Migrate the 1:1 send path to capnp manifests (built in Rust)
claude Jun 30, 2026
c921ebd
Dark mode: match select background to text inputs
claude Jul 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 150 additions & 40 deletions docs/nostr-mail-spec.md

Large diffs are not rendered by default.

25 changes: 18 additions & 7 deletions tauri-app/backend/schema/nostr_mail.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,27 @@ enum NipVersion {
# Attachments travel as separate MIME parts with opaque filenames
# (a1.dat, a2.dat, …) and application/octet-stream content type.
#
# ── Binary vs JSON detection ──
# ── Cap'n Proto vs JSON detection ──
#
# After NIP decryption, the manifest payload is either:
# The encrypted body is either a manifest or an ordinary plaintext
# body. After the outer layer is opened (pairwise NIP-44, or the
# per-recipient-wrapped CEK), the decrypted payload is:
#
# JSON (legacy) — first byte is 0x7B ('{')
# Cap'n Proto — first 4 bytes are 0x00000000 (single-segment table)
# Cap'n Proto — "capnp:" marker, then the raw serialized
# single-segment Manifest message (binary)
# Cap'n Proto — "capnp64:" marker, then base64 of that message
# JSON (legacy)— first byte is 0x7B ('{')
# plaintext — anything else (not a manifest)
#
# The decoder checks the first byte to select the deserialization path.
# New messages SHOULD use Cap'n Proto; JSON is retained for reading
# older emails.
# The manifest never touches the wire in the clear: it is encrypted by
# the outer layer (CEK or NIP-44) and that ciphertext is what gets
# glossia-encoded for transport, so it needs no inner armor of its own.
# Two markers exist because the two transports differ: the multi-
# recipient CEK envelope is byte-clean and carries raw bytes ("capnp:");
# the pairwise NIP-44 API is string-typed (decrypt yields a String) and
# cannot carry raw binary, so the 1:1 path base64-armors the same bytes
# ("capnp64:"). New messages use Cap'n Proto; JSON is retained for
# reading older emails.

struct Manifest {
body @0 :EncryptedBlob;
Expand Down
Loading
Loading