- 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>
78 lines
No EOL
3.6 KiB
Markdown
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 |