tuimail/PROTON.md
Shautvast 05b6aac692 Add proton-bridge crate: workspace setup and SRP authentication (Step 2)
- Convert tuimail repo to Cargo workspace with tuimail and proton-bridge members
- Add proton-bridge binary crate with config, SRP 6a, and auth modules
- Implement ProtonMail SRP 6a exactly matching go-srp:
  - Little-endian bigints throughout
  - expandHash = SHA512(data||0..3) producing 256 bytes
  - k, u, M1, M2 all via expandHash with 256-byte normalised inputs
  - Password hashing v3/v4: bcrypt($2y$, salt+proton) + expandHash(output||N)
- Authenticate against Proton API (auth/info → auth/v4), verify server proof
- Persist session (UID, access/refresh tokens) to session.json
- Add bridge.toml and session.json to .gitignore (contain credentials/tokens)
- Add PROTON.md with full build plan for the mini-bridge

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 21:31:10 +01:00

78 lines
No EOL
3.6 KiB
Markdown

# ProtonMail Mini-Bridge
A minimal ProtonMail Bridge implementation in Rust that exposes local IMAP and SMTP servers,
allowing `skim` (and any other standard email client) to connect without code changes.
The full ProtonMail Bridge is ~50,000 lines of Go. This mini-bridge targets only the subset
of functionality that `skim` needs: one account, INBOX only, one concurrent client.
## Components
### 1. Project scaffold
New binary crate with `Cargo.toml` dependencies (`tokio`, `reqwest`, `proton-srp`, `rpgp`,
`serde`, `toml`). Config file format covering ProtonMail credentials and local bind ports.
### 2. ProtonMail authentication
SRP 6a login flow against the Proton API:
- POST `/auth/info` with username → receive modulus, server ephemeral, salt
- Compute SRP proof locally using `proton-srp`
- POST `/auth/login` with client proof → receive access token + encrypted private keys
- Handle optional TOTP 2FA interactively on first run
- Persist session (access token + refresh token) to disk to avoid re-authenticating on restart
### 3. ProtonMail API client
Thin `reqwest`-based HTTP wrapper around the endpoints the bridge needs:
- List messages (with pagination)
- Fetch single message (metadata + encrypted body)
- Delete message
- Fetch recipient public key (for outbound encryption)
- Send message (modelled from the open-source `ProtonMail/proton-bridge` Go implementation)
### 4. Crypto layer
Using `rpgp` or `proton-crypto-rs`:
- Decrypt the user's private key (delivered encrypted by the API, unlocked with the mailbox password)
- Decrypt incoming message bodies with the private key
- Encrypt outbound messages to recipient public keys
### 5. Message store
In-memory (optionally persisted) mapping between IMAP sequence numbers and Proton message IDs.
IMAP uses stable sequential integers; Proton uses opaque string IDs. The store must:
- Assign sequence numbers to messages in order
- Renumber correctly after deletes
- Survive restarts without breaking existing client state
### 6. IMAP server
TCP listener on `localhost:143` (configurable). Implements the nine commands `skim` uses:
| Command | Purpose |
|---------|---------|
| `LOGIN` | Accept local credentials (no real auth needed) |
| `NOOP` | Keepalive / connection check |
| `SELECT INBOX` | Open mailbox, report message count |
| `FETCH range BODY.PEEK[HEADER.FIELDS (SUBJECT FROM DATE)]` | List emails |
| `FETCH seq BODY.PEEK[]` | Fetch full message body |
| `SEARCH OR SUBJECT "..." FROM "..."` | Search by subject or sender |
| `STORE seq +FLAGS (\Deleted)` | Mark for deletion |
| `EXPUNGE` | Delete marked messages |
| `LOGOUT` | Disconnect |
Each command translates to API client + crypto layer calls via the message store.
### 7. SMTP server
TCP listener on `localhost:587` (configurable). Minimal implementation:
- EHLO, AUTH, MAIL FROM, RCPT TO, DATA, QUIT
- On DATA completion: hand the message to the crypto layer to encrypt, then POST via API client
## Build order
Components 2 → 3 → 4 can be built and tested with a simple CLI harness before any
network server exists. Component 5 is pure logic with no I/O. Components 6 and 7 are
the final pieces and can be validated by pointing `skim` at localhost.
## References
- [ProtonMail/proton-bridge](https://github.com/ProtonMail/proton-bridge) — official Bridge (Go, open source)
- [ProtonMail/go-proton-api](https://github.com/ProtonMail/go-proton-api) — official Go API client
- [ProtonMail/proton-crypto-rs](https://github.com/ProtonMail/proton-crypto-rs) — official Rust crypto crates
- [ProtonMail/proton-srp](https://github.com/ProtonMail/proton-srp) — official Rust SRP implementation
- [rpgp](https://github.com/rpgp/rpgp) — pure Rust OpenPGP implementation