{"id":27055492,"url":"https://github.com/duesee/imap-proxy","last_synced_at":"2025-04-05T09:27:53.931Z","repository":{"id":249393079,"uuid":"831378316","full_name":"duesee/imap-proxy","owner":"duesee","description":null,"archived":false,"fork":false,"pushed_at":"2025-03-05T22:25:54.000Z","size":53,"stargazers_count":5,"open_issues_count":4,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-05T23:25:38.254Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/duesee.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["duesee"]}},"created_at":"2024-07-20T11:30:29.000Z","updated_at":"2025-03-05T22:25:52.000Z","dependencies_parsed_at":"2024-11-18T22:44:32.820Z","dependency_job_id":"29f68047-6843-4866-8a7a-13796b407cab","html_url":"https://github.com/duesee/imap-proxy","commit_stats":null,"previous_names":["duesee/imap-proxy"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duesee%2Fimap-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duesee%2Fimap-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duesee%2Fimap-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duesee%2Fimap-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/duesee","download_url":"https://codeload.github.com/duesee/imap-proxy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247315900,"owners_count":20919161,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-04-05T09:27:53.013Z","updated_at":"2025-04-05T09:27:53.896Z","avatar_url":"https://github.com/duesee.png","language":"Rust","readme":"[![main](https://github.com/duesee/imap-proxy/actions/workflows/main.yml/badge.svg)](https://github.com/duesee/imap-proxy/actions/workflows/main.yml)\n[![audit](https://github.com/duesee/imap-proxy/actions/workflows/audit.yml/badge.svg)](https://github.com/duesee/imap-proxy/actions/workflows/audit.yml)\n\n# IMAP Proxy 𓃸\n\nA proxy that receives, `Debug`-prints, and forwards IMAP messages *without changing their semantics* (but see note below).\n\n```mermaid\n%%{init: {'theme': 'neutral' } }%%\nflowchart LR\n    imap-types --\u003e imap-codec\n    imap-codec --\u003e imap-next\n    imap-next --\u003e imap-proxy\n    \n    style imap-codec stroke-dasharray: 10 5\n    style imap-next stroke-dasharray: 10 5\n    style imap-proxy stroke-width:4px\n    \n    click imap-types href \"https://github.com/duesee/imap-codec/tree/main/imap-types\"\n    click imap-codec href \"https://github.com/duesee/imap-codec\"\n    click imap-next href \"https://github.com/duesee/imap-next\"\n    click imap-proxy href \"https://github.com/duesee/imap-proxy\"\n```\n\nThanks to imap-next, the proxy takes advantage of asynchronous I/O, abstracts away literal handling, and fully supports unsolicited responses.\n\n# Quickstart\n\nFor now there is no officially released binary. You can install the proxy via cargo ...\n\n```shell\ncargo install --git https://github.com/duesee/imap-proxy\n```\n\n... and then run ...\n\n```shell\nimap-proxy --help\n```\n\n... for an overview of arguments. But we suggest to run it directly via cargo ...\n\n```shell\ncargo run -- --help\n```\n\n... because it allows you to tinker with the source code.\n\n**Important**: You must enable tracing (logging) to see a `Debug`-print of exchanged messages.\n\nTo do so, set the `RUST_LOG` environment variable.\n\nUse ...\n\n```sh\nRUST_LOG=proxy=trace cargo run\n```\n\n... to start the proxy (using the default `config.toml`), enabling all log messages for the \"proxy\" module.\n\nYou should probably experiment with the environment variable. For example, you can use ...\n\n```sh\nRUST_LOG=trace cargo run\n```\n\n... to enable logs from lower libraries. This way, you will get TLS events and `io/{read,write}/raw` events.\n\n```mermaid  \ngraph LR;\n\tClient --\u003e|\"① parse Command\"| Proxy;\n\tProxy  --\u003e|\"② change Command (currently no change)\"| Proxy;\n\tProxy  --\u003e|\"③ serialize Command'\"| Server;\n\tServer --\u003e|\"④ parse Response\"| Proxy;\n\tProxy  --\u003e|\"⑥ serialize Response'\"| Client;\n\tProxy  --\u003e|\"⑤ change Response (currently no change)\"| Proxy;\n```\n\n\u003cdetails\u003e\n\t\u003csummary\u003eExample Trace\u003c/summary\u003e\n\n```\n$ RUST_LOG=trace cargo run\n\n# Insecure to Insecure\nimap://127.0.0.1:1143 (insecure) -\u003e imap://127.0.0.1:2143 (insecure)\n\n INFO  Bound to bind_addr_port=\"127.0.0.1:1143\"\n INFO  Accepted client client_addr=127.0.0.1:46500\n\n INFO  Connecting to server server_addr_port=\"127.0.0.1:2143\"\n INFO  Connected to server server_addr_port=\"127.0.0.1:2143\"\nTRACE  io/read/raw data=\"* OK Hello, World!\\\\r\\\\n\"\nTRACE  \u003c--| role=\"s2p\" greeting=Greeting {\n\tkind: Ok,\n\tcode: None,\n\ttext: Text(\"Hello, World!\")\n}\nTRACE  io/write/raw data=\"* OK Hello, World!\\\\r\\\\n\"\nTRACE  \u003c--- greeting role=\"p2c\"\nTRACE  io/read/raw data=\"A LOGIN {4}\\\\r\\\\n\"\nTRACE  io/write/raw data=\"+ proxy: Literal accepted by proxy\\\\r\\\\n\"\nTRACE  io/read/raw data=\"user {4}\"\nTRACE  io/read/raw data=\"\\\\r\\\\n\"\nTRACE  io/write/raw data=\"+ proxy: Literal accepted by proxy\\\\r\\\\n\"\nTRACE  io/read/raw data=\"pass\"\nTRACE  io/read/raw data=\"\\\\r\\\\n\"\nTRACE  |--\u003e role=\"c2p\" command=Command {\n\ttag: Tag(\"A\"),\n\tbody: Login {\n\t\tusername: String(Literal(Literal { data: b\"user\", mode: Sync })),\n\t\tpassword: String(Literal(Literal { data: b\"pass\", mode: Sync }))\n\t}\n}\n```\n\u003c/details\u003e\n\n## Config\n\nThe `config.toml` file has pre-configured scenarios.\nThe first scenario \"Insecure to TLS\" is useful for a (local) forwarding proxy and is already enabled.\n\nYou can start multiple services using TOML's [array of tables](https://toml.io/en/v1.0.0#array-of-tables) syntax:\n\n```toml\n[[services]]\n# ...\n\n[[services]]\n# ...\n```\n\nThe `encryption` field configures transport encryption, i.e., `Insecure` or `Tls`.\n`Insecure` disables TLS encryption and SHOULD NOT be used when proxying to a remote server.\n\n### Using TLS\n\n#### Create local TLS certificate(s)\n\nYou can use [`mkcert`](https://github.com/FiloSottile/mkcert) to create a local certificate authority (CA).\nThe tool takes care to \"register\" the local CA with [typical trust stores](https://github.com/FiloSottile/mkcert#supported-root-stores) on your system.\n\nWe recommend creating a `private` folder before creating certificates and keys.\nThe `private` folder is `.gitignore`d, so you can't accidentally push your keys.\n\n```shell\nmkdir private\ncd private\n```\n\nWith `mkcert`, you should now be able to create a certificate (+ key), e.g., ...\n\n```shell\nmkcert localhost\n```\n\nThe command creates two files, `localhost.pem` (certificate) and `localhost-key.pem` (key).\n\n#### Configure to accept TLS connections\n\nEdit your `config.toml` ...\n\n```toml\n[services.bind.identity]\ntype = \"CertificateChainAndLeafKey\"\ncertificate_chain_path = \"private/localhost.pem\"\nleaf_key_path = \"private/localhost-key.pem\"\n```\n\n... accordingly, start the proxy, and test your connection with OpenSSL, e.g., ...\n\n```shell\nopenssl s_client -verify_return_error -crlf -connect \u003chost\u003e:\u003cport\u003e\n```\n\nNote: `openssl s_client` should only really be used for testing.\n\n# Semantic changes\n\n\u003e A few semantic changes are required to make the proxy more useful.\n\u003e These changes are communicated by the proxy, e.g., by emitting a warning or prefixing a `text` field.\n\u003e \n\u003e **Literal handling** IMAP allows sending commands \"piece-by-piece\" using literals.\n\u003e However, forwarding single pieces rules out modifications that change the size of a literal.\n\u003e Thus, the proxy collects all pieces first and presents single messages that can be easily replaced (if so desired).\n\u003e \n\u003e **Capability stripping** Capabilities can introduce fundamental protocol changes.\n\u003e Thus, forwarding unknown capabilities would mean we are willing to \"lose track\" of our session understanding.\n\u003e It also implies the proxy needs to forward unparsed messages and (somehow) \"get on track\" at some later point.\n\u003e Doing so requires an in-depth analysis of the problem and its implications.\n\u003e Thus, we prefer to strip unsupported capabilities and error out on parsing errors.\n\n# Supported authentication mechanisms\n\nThe proxy forwards authentication messages unchanged, and uses an [allow-list](https://github.com/duesee/imap-proxy/blob/main/src/util.rs#L95)\nof capabilities and authentication mechanisms to exclude everything it doesn't understand.\n\nSome authentication mechanisms \"bind\" to the TLS connection (\"channel binding\") and will fail when proxied.\nThese mechanisms are not proxyable by design -- at least without further ado -- and are filtered from the connection.\n\n| Authentication mechanism | Support                                |\n|--------------------------|----------------------------------------|\n| LOGIN                    | supported                              |\n| PLAIN                    | supported                              |\n| XOAUTH2                  | supported                              |\n| SCRAM-*                  | supported                              |\n| SCRAM-*-PLUS             | not supported (due to channel binding) |\n| Others                   | not supported (yet)                    |\n\n# Future work\n\nThe proxy could enrich existing clients' functionality to improve compatibility, performance, and security.\nThis could be done by fleshing out the proxy into a configurable framework.\n\nExamples:\n\n* Support\n  * `XOAUTH2` could transparently be added to non-supporting clients\n* Security\n    * Encryption could be transparently added such that emails are always appended in encrypted form and decrypted during fetching\n* Support \u0026 Security\n  * Vintage clients could use the proxy as a TLS/Compatibility gateway (See [\"Using modern email on vintage clients\"](https://julienblanchard.com/articles/modern-email-and-vintage-clients).)\n* Performance\n  * Support for \"capabilities in greetings\" or `LITERAL+` could be transparently added to improve performance\n* Testing\n  * Messages could be forwarded to other software for analysis\n  * Protocol traces could be automatically analyzed for supported features\n  * Proxy could inject non-semantic changes to expose interoperability issues (See issue #62.)\n\n# License\n\nThis crate is licensed under AGPL terms.\n\n# Thanks\n\nThanks to the [NLnet Foundation](https://nlnet.nl/) for supporting the imap-codec project through [NGI Assure](https://nlnet.nl/assure/)!\n\n\u003cdiv align=\"right\"\u003e\n    \u003cimg height=\"100px\" src=\"https://user-images.githubusercontent.com/8997731/215262095-ab12d43a-ca8a-4d44-b79b-7e99ab91ca01.png\"/\u003e\n    \u003cimg height=\"100px\" src=\"https://user-images.githubusercontent.com/8997731/221422192-60d28ed4-10bb-441e-957d-93af58166707.png\"/\u003e\n    \u003cimg height=\"100px\" src=\"https://user-images.githubusercontent.com/8997731/215262235-0db02da9-7c6c-498e-a3d2-7ea7901637bf.png\"/\u003e\n\u003c/div\u003e\n","funding_links":["https://github.com/sponsors/duesee"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduesee%2Fimap-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fduesee%2Fimap-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduesee%2Fimap-proxy/lists"}