Conversation
Drafts are authored by the current user and are never signed until they are sent, so signature_valid is always null on them. renderDrafts was filtering on signature_valid !== true whenever hide_unsigned_messages was enabled (the default), which silently hid every saved draft from the drafts page. Mirror the sent-mail rendering path, which already bypasses this filter because that mail is self-authored, and drop the now-unreachable 'no verified drafts' empty state.
Remove signature verification filter from drafts rendering
…ent workflow Generalize the existing hybrid attachment encryption (random AES-256 key wrapped with NIP-44) to N recipients via a per-message Content Encryption Key and a new RECIPIENTS armor block. Define To:=signer / Cc:=viewer roles, the sender self-stanza for Sent-folder access, per-level recipients in reply chains, signature coverage of the recipients block, and a DocuSign-style agreement/signing-round workflow that is independently verifiable from the email thread. Bumps spec to 0.3.0-draft.
spec: multi-recipient (group) encryption, To/Cc roles, and agreement workflow
Introduce a dedicated BEGIN NOSTR CONTRACT block so a signatory's consent is an explicit, intentional act rather than a side effect of replying (every reply is signed for chain-of-custody, so a signature alone cannot mean assent). - New block type + END tag in the armor vocabulary (Section 2.1). - Extend per-level signature coverage to include the CONTRACT block (level(L) = body || recipients || contract), fixed body->recipients->contract order (Section 4.2). - Define the consent block: fields (agreement H, signer), the document hash H (over level-1 body+recipients, excluding contracts to avoid self-reference), and ordering as content (not a trailer), one per level (Section 11.3). - Rewrite Signing Round / Completion / Verification to key off verified CONTRACT blocks over H, dedup by pubkey, and treat CONTRACT-less replies as comments (Sections 11.4-11.6); handle originator-as-signatory. - HTML rendering for agreements: status banner + green consent panels vs muted comment sections, with non-colour-dependent labels (Section 6.2.6). - Backward compatibility note: older clients ignore CONTRACT and see a plain signed reply (Section 12). Bumps spec to 0.4.0-draft.
…ly privacy roadmap - Rename the consent block CONTRACT -> CONSENT throughout (BEGIN/END NOSTR CONSENT, level(L) consent term, HTML rendering, completion/verification). CONSENT names the act, avoids colliding with 'agreement' (which SIGit and this spec both use for the whole container), and matches SIGit verbiage (signer/viewer roles are already identical). Also drop the '(Contract)' parenthetical from the Agreement Message heading. - Add Section 11.7 'Relation to SIGit' mapping our model onto SIGit's (keys<->RECIPIENTS, meta<->H, prevSig/docSignatures<->nested signatures, Sign event<->CONSENT block) and noting the email-native vs relay+Blossom transport difference. - Note the planned Nostr-only agreement transport (fold in SIGit's NIP-59 gift-wrap/Blossom privacy model) in Section 10.9; emphasize the consent semantics are transport-independent.
…p6sr Add consent block support for agreement workflows (v0.4.0)
verify_transport_authentication trusted the plaintext Authentication-Results header it selected with .pop() — the bottom-most, sender-injectable header. A sender could forge `dmarc=pass` for a spoofed From: and set transport_verified = true. Security fixes: - Select the FIRST (top-most) A-R header, stamped by the closest hop (our receiving provider), not the last. - Gate on authserv-id: honor an A-R header only when its organizational domain matches the user's provider (derived from email/IMAP host, with a known-provider map so Gmail's mx.google.com is trusted; fails closed otherwise). A sender-forged A-R with an unknown authserv-id is rejected even when it is the only one present. - SPF no longer counts as From-authentication (it authenticates the envelope MAIL FROM, not the visible From:). Correctness: - DKIM alignment now uses DMARC relaxed (organizational-domain) matching, so legitimate subdomain signatures are not false negatives. Threads the derived trusted-authserv set through the inbox filter and the spam-rescue path. Adds unit tests covering the exploit, the authserv-id gate, SPF-only, relaxed alignment, header selection, and fail-closed behavior. Adds SECURITY.md documenting the threat model (malicious provider / header-injection adversary), the npub-rooted trust model, the three trust states, what transport-auth does and does not prove, and the planned email-ownership binding. https://claude.ai/code/session_01PyRdoum6RhwJnVyQnVrEJ3
Fix forgeable transport-auth verdict; add SECURITY.md (#101)
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.
Lands the current
stagingdelta ontomaster. The checklist below tracks each feature/fix and the feature test that guards it (or flags it as test-owed when the code has landed but no test covers it yet).How to run
CI (
.github/workflows/test.yml) runscargo test --test email_integrationon every push/PR tomain,master,staging.Legend:
[x]code landed and covered by a feature test ·[ ]landed but test still owed before it's safe.🖋️ Draft rendering fix (focus)
Drafts are authored by the current user and are unsigned until sent, so
hide_unsigned_messages/require_signaturemust never hide them (mirrors the sent-mail render path). The preview must decode both glossia clear-signed and NIP-44 encrypted bodies. Code:email-service.jsrenderDrafts()/renderDraftItem()(commit5c8edce).hide_unsigned_messages/require_signatureis onhide_undecryptable_emailsis on🔏 Signing & verification — covered
defaults_header_sig_roundtrip)defaults_full_roundtrip_with_inline_sig)tampered_body_invalidates_signature)clearsigned_plaintext_verifies_via_header)inline_valid_header_broken_reports_body,inline_broken_header_valid_reports_header)broken_pubkey_fails_verification)decode_sig_and_pubkeyhonors schema canonical-first order🔐 Encryption (NIP-04 / NIP-44) & replies — covered
nip04_legacy_decrypt)X-Nostr-Sigheader fallback (nip04_header_sig_fallback_unlocks_decrypt)glossia_body_latin_roundtrip)signed_plaintext_reply_preserves_nested_signature)nip44_reply_preserves_nested_encrypted_armor)nip44_three_level_reply_chain)reply_threading_headers_and_encoded_quote)📎 Attachments
manifest_attachment_compose_inline_sig_verifies)manifest_attachment_default_jsformat_inline_sig_verifies)📬 Sent / inbox decryption — covered
sent_mail_decrypts_via_recipient_header_without_dm)sent_mail_undecryptable_without_any_counterparty_hint)multipart_html_and_text)non_ascii_subject_roundtrip)quoted_printable_body_roundtrip)🛡️ Transport authentication (in flight — PR #103, targets staging)
Authentication-Resultsheader ignored (top-most provider-stamped header selected)authserv-idgate fails closed for unknown authserv-ids🔄 IMAP sync, folders & spam (manual; no automated coverage yet)
sync_initial_count/sync_max_scan)gap_fillexamines each UID once and watermarks it (no full rescan)\Seenas intent\Seenread-state syncs both directions💬 Direct messages (manual; no automated coverage yet)
👥 Group / multi-recipient (spec only — future, not landing now)
Spec landed (To/Cc roles, group encryption, CONSENT block — PRs #97/#99/#100); implementation + tests are future work, tracked so they aren't lost.
https://claude.ai/code/session_01G8qsd2rk22GHN3RNspKTAD
Generated by Claude Code