From c58eebc5841cdae5a7f8750a3ab73469b985bd17 Mon Sep 17 00:00:00 2001 From: Guilhem Zeitoun Date: Tue, 14 Jul 2026 22:07:19 +0200 Subject: [PATCH 1/7] rebase --- Cargo.lock | 369 +++++++++++++++++++------------------------------- Cargo.toml | 1 + src/config.rs | 11 +- src/mail.rs | 49 ++++++- 4 files changed, 196 insertions(+), 234 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0715098c..1a2aa174 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,17 +8,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures 0.2.17", -] - [[package]] name = "ahash" version = "0.8.12" @@ -360,9 +349,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-config" -version = "1.8.18" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33f815b73a3899c03b380d543532e5865f230dce9678d108dc10732a8682275" +checksum = "47712fde1909402600ccfbb26e47d482d2e58bb9e9e603d9f17e67cc435a6319" dependencies = [ "aws-credential-types", "aws-runtime", @@ -381,7 +370,7 @@ dependencies = [ "fastrand", "hex", "http 1.4.2", - "sha1 0.10.6", + "sha1 0.10.7", "time", "tokio", "tracing", @@ -391,9 +380,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.14" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f20799b373a1be121fe3005fba0c2090af9411573878f224df44b42727fcaf7" +checksum = "e93964ffdaf57857f544be3666a5f57570bb699e934700f11b49708f61bb556e" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -403,9 +392,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.7.5" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c9b9de216a988dd54b754a82a7660cfe14cee4f6782ae4524470972fa0ccb39" +checksum = "7816e98ee912159f45d307e5ee6bfea4a335a55aee15f7f3e32f81a6f3000f1d" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -419,7 +408,7 @@ dependencies = [ "bytes-utils", "fastrand", "http 1.4.2", - "http-body 1.0.1", + "http-body 1.1.0", "percent-encoding", "pin-project-lite", "tracing", @@ -428,9 +417,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.102.0" +version = "1.103.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c82b3ac19f1431854f7ace3a7531674633e286bfdde21976893bfee36fd493b" +checksum = "0469f435f645ad2162cfb463b15bde37115966ee3acf2d87fb4871ee309b8401" dependencies = [ "arc-swap", "aws-credential-types", @@ -441,6 +430,7 @@ dependencies = [ "aws-smithy-observability", "aws-smithy-runtime", "aws-smithy-runtime-api", + "aws-smithy-schema", "aws-smithy-types", "aws-types", "bytes", @@ -453,9 +443,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.104.0" +version = "1.105.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321000d2b4c5519ee573f73167f612efd7329322d9b26969ad1979f0427f1913" +checksum = "085faefb253f770655e162b9304321e62a1e71adf7f019ee1f4454228a377b3a" dependencies = [ "arc-swap", "aws-credential-types", @@ -466,6 +456,7 @@ dependencies = [ "aws-smithy-observability", "aws-smithy-runtime", "aws-smithy-runtime-api", + "aws-smithy-schema", "aws-smithy-types", "aws-types", "bytes", @@ -478,9 +469,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.107.0" +version = "1.108.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0d328ba962af23ecfa3c9f23b98d3d35e325fa218d7f13d17a6bf522f8a560" +checksum = "3c72b08911d8128dd360fe1b22a9fec0fa8b552dde8ec828dcf20ef5ec974e9f" dependencies = [ "arc-swap", "aws-credential-types", @@ -492,6 +483,7 @@ dependencies = [ "aws-smithy-query", "aws-smithy-runtime", "aws-smithy-runtime-api", + "aws-smithy-schema", "aws-smithy-types", "aws-smithy-xml", "aws-types", @@ -504,9 +496,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.4.5" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae38512beae0ffee7010fc24e7a8a123c53efdfef42a61e80fda4882418dc71" +checksum = "723c2234ad7511ceef63eab016b7ba6ff7c55590fefb96fa8467af014a07309f" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -537,9 +529,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.63.6" +version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1ab2dc1c2c3749ead27180d333c42f11be8b0e934058fb4b2258ee8dbe5231" +checksum = "37843d9add67c3aff5856f409c6dc315d3cdff60f9c0cb5b670dab1e9920306d" dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", @@ -548,7 +540,7 @@ dependencies = [ "futures-core", "futures-util", "http 1.4.2", - "http-body 1.0.1", + "http-body 1.1.0", "http-body-util", "percent-encoding", "pin-project-lite", @@ -558,9 +550,9 @@ dependencies = [ [[package]] name = "aws-smithy-json" -version = "0.62.7" +version = "0.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "701a947f4797e52a911e114a898667c746c39feea467bbd1abd7b3721f702ffa" +checksum = "3dc65a121adb4b33729919fcfa14fa36fb33c1555a8f06bb0e2188dbfdc1d9ef" dependencies = [ "aws-smithy-runtime-api", "aws-smithy-schema", @@ -569,18 +561,18 @@ dependencies = [ [[package]] name = "aws-smithy-observability" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06c2315d173edbf1920da8ba3a7189695827002e4c0fc961973ab1c54abca9c" +checksum = "8e86338c869539a581bf161247762a6e87f92c5c075060057b5ed6d06632ed0c" dependencies = [ "aws-smithy-runtime-api", ] [[package]] name = "aws-smithy-query" -version = "0.60.15" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a56d79744fb3edb5d722ef79d86081e121d3b9422cb209eb03aea6aa4f21ebd" +checksum = "dd22a6ba36e3f113cb8d5b3d1fe0ed31c76ee608ef63322d753bb8d2c9479e77" dependencies = [ "aws-smithy-types", "urlencoding", @@ -588,9 +580,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e6f5caf6fea86f8c2206541ab5857cfcda9013426cdbe8fa0098b9e2d32182" +checksum = "bea94a9ff8464016338c851e24b472d7131c388c88898a502e781815b2ee6045" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -603,7 +595,7 @@ dependencies = [ "http 0.2.12", "http 1.4.2", "http-body 0.4.6", - "http-body 1.0.1", + "http-body 1.1.0", "http-body-util", "pin-project-lite", "pin-utils", @@ -642,9 +634,9 @@ dependencies = [ [[package]] name = "aws-smithy-schema" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7442cb268338f0eb8278140a107c046756aa01093d8ef5e99628d34ae09c94f5" +checksum = "7d56e0a4e53127a632224e43633b0fe045fa9e1e3cfc68b9830f1115e103f910" dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", @@ -663,7 +655,7 @@ dependencies = [ "http 0.2.12", "http 1.4.2", "http-body 0.4.6", - "http-body 1.0.1", + "http-body 1.1.0", "http-body-util", "itoa", "num-integer", @@ -676,18 +668,21 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.15" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce02add1aa3677d022f8adf81dcbe3046a95f17a1b1e8979c145cd21d3d22b3" +checksum = "ea3f68eec3607f02acd24067969ce2abc6ba16aa7d5ce59ca450ed2fb5f78957" dependencies = [ + "aws-smithy-runtime-api", + "aws-smithy-schema", + "aws-smithy-types", "xmlparser", ] [[package]] name = "aws-types" -version = "1.3.16" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16bf10b03a3c01e6b3b7d47cd964e873ffe9e7d4e80fad16bd4c077cb068531" +checksum = "e957a6c6dbce82b7a91f44231c09273159703769f447cbe85e854dfe9cf67f86" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -801,15 +796,6 @@ dependencies = [ "hybrid-array", ] -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - [[package]] name = "blocking" version = "1.6.2" @@ -861,9 +847,9 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "d6aedf8ae72766347502cf3cb4f41cf5e9cc37d28bee90f1fdaaae15f9cf9424" [[package]] name = "byteorder" @@ -921,20 +907,11 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26cf465651fa6ad902a2d327ba60c3a6bc61c6a2f4ad70d091cf20dfda0074ef" -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher", -] - [[package]] name = "cc" -version = "1.2.66" +version = "1.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" +checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" dependencies = [ "find-msvc-tools", "jobserver", @@ -983,16 +960,6 @@ dependencies = [ "phf 0.12.1", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common 0.1.6", - "inout", -] - [[package]] name = "cmov" version = "0.5.4" @@ -1574,9 +1541,9 @@ dependencies = [ [[package]] name = "diesel" -version = "2.3.10" +version = "2.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29fe29a87fb84c631ffb3ba21798c4b1f3a964701ba78f0dce4bf8668562ec88" +checksum = "e54d1f576cd3a3460f212a4615fd12ce1b6303c095b79a44449ffbe627753dc1" dependencies = [ "bigdecimal", "bitflags 2.13.0", @@ -2168,7 +2135,7 @@ dependencies = [ "parking_lot", "portable-atomic", "quanta", - "rand 0.9.4", + "rand 0.9.5", "smallvec", "spinning_top", "web-time", @@ -2230,9 +2197,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "6.4.2" +version = "6.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26569a2763497b7bd3fbd19374b774ea6038c5293678771259cd534d49740ff" +checksum = "4633d16a2350341713c379d6d06a4b9e1845329386026a49ce4fd09c2f3b16f6" dependencies = [ "derive_builder", "log", @@ -2447,9 +2414,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" dependencies = [ "bytes", "http 1.4.2", @@ -2457,14 +2424,14 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" dependencies = [ "bytes", "futures-core", "http 1.4.2", - "http-body 1.0.1", + "http-body 1.1.0", "pin-project-lite", ] @@ -2524,7 +2491,7 @@ dependencies = [ "futures-core", "h2", "http 1.4.2", - "http-body 1.0.1", + "http-body 1.1.0", "httparse", "itoa", "pin-project-lite", @@ -2542,7 +2509,7 @@ dependencies = [ "http 1.4.2", "hyper 1.10.1", "hyper-util", - "rustls 0.23.41", + "rustls 0.23.42", "tokio", "tokio-rustls 0.26.4", "tower-service", @@ -2559,13 +2526,13 @@ dependencies = [ "futures-channel", "futures-util", "http 1.4.2", - "http-body 1.0.1", + "http-body 1.1.0", "hyper 1.10.1", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.4", + "socket2 0.6.5", "system-configuration", "tokio", "tower-service", @@ -2735,23 +2702,13 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "block-padding", - "generic-array", -] - [[package]] name = "ipconfig" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222" dependencies = [ - "socket2 0.6.4", + "socket2 0.6.5", "widestring", "windows-registry", "windows-result", @@ -2801,9 +2758,9 @@ checksum = "47f142fe24a9c9944451e8349de0a56af5f3e7226dc46f3ed4d4ecc0b85af75e" [[package]] name = "jiff" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccfe6121cbe750cf81efa362d85c0bde7ea298ec43092d3a193baca59cdbd634" +checksum = "961d16382652bfdd8c6f68b223b26a8c93e0d475c672f414411db31c6c5c900e" dependencies = [ "defmt", "jiff-static", @@ -2819,9 +2776,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e165e897f662d428f3cd3828a919dbe067c2d42bb1031eede74ef9d27ecdedd2" +checksum = "d0879bd39df99c4c5e2c6615ccc026391a423dde10532c573e6086eb94a802cc" dependencies = [ "proc-macro2", "quote", @@ -2830,9 +2787,9 @@ dependencies = [ [[package]] name = "jiff-tzdb" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6142247df1a93c2b3587402a19710be3e6e942f1581a1702e76408f2c21d6590" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" [[package]] name = "jiff-tzdb-platform" @@ -2938,7 +2895,7 @@ dependencies = [ "p256", "p384", "pem", - "rand 0.8.6", + "rand 0.8.7", "rsa", "serde", "serde_json", @@ -2984,6 +2941,7 @@ dependencies = [ "async-std", "async-trait", "base64 0.22.1", + "ed25519-dalek", "email-encoding", "email_address", "fastrand", @@ -2996,10 +2954,12 @@ dependencies = [ "nom 8.0.0", "percent-encoding", "quoted_printable", - "rustls 0.23.41", + "rsa", + "rustls 0.23.42", "rustls-native-certs", "serde", - "socket2 0.6.4", + "sha2 0.10.9", + "socket2 0.6.5", "tokio", "tokio-rustls 0.26.4", "tracing", @@ -3185,9 +3145,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" dependencies = [ "libc", "wasi", @@ -3305,7 +3265,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.6", + "rand 0.8.7", "smallvec", "zeroize", ] @@ -3400,7 +3360,7 @@ dependencies = [ "chrono", "getrandom 0.2.17", "http 1.4.2", - "rand 0.8.6", + "rand 0.8.7", "serde", "serde_json", "serde_path_to_error", @@ -3450,7 +3410,7 @@ dependencies = [ "bytes", "futures", "http 1.4.2", - "http-body 1.0.1", + "http-body 1.1.0", "jiff", "log", "md-5", @@ -3519,7 +3479,7 @@ dependencies = [ "oauth2", "p256", "p384", - "rand 0.8.6", + "rand 0.8.7", "rsa", "serde", "serde-value", @@ -3687,16 +3647,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4" -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest 0.10.7", - "hmac 0.12.1", -] - [[package]] name = "pear" version = "0.2.9" @@ -3813,7 +3763,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared 0.11.3", - "rand 0.8.6", + "rand 0.8.7", ] [[package]] @@ -3887,21 +3837,6 @@ dependencies = [ "spki", ] -[[package]] -name = "pkcs5" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" -dependencies = [ - "aes", - "cbc", - "der", - "pbkdf2", - "scrypt", - "sha2 0.10.9", - "spki", -] - [[package]] name = "pkcs8" version = "0.10.2" @@ -3909,8 +3844,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", - "pkcs5", - "rand_core 0.6.4", "spki", ] @@ -4075,9 +4008,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.40.1" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2474bd2e5029e7ccb6abb2ba48cf2383a333851dedf495901544281590c7da7f" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", "serde", @@ -4123,9 +4056,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -4134,9 +4067,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -4237,9 +4170,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.4" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2" dependencies = [ "aho-corasick", "memchr", @@ -4249,9 +4182,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db" dependencies = [ "aho-corasick", "memchr", @@ -4283,9 +4216,9 @@ dependencies = [ [[package]] name = "reqsign-aws-v4" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75624bd8a466e37ddc0a7b6c33ac859a85347c153a916e1dd9d0b68338f74a" +checksum = "4e9e1168fab3883ec6afed1c2e20c25b2a09f366cdb662ac3e0878ae0332d63e" dependencies = [ "anyhow", "bytes", @@ -4294,7 +4227,7 @@ dependencies = [ "http 1.4.2", "log", "percent-encoding", - "quick-xml 0.40.1", + "quick-xml 0.41.0", "reqsign-core", "rust-ini", "serde", @@ -4305,9 +4238,9 @@ dependencies = [ [[package]] name = "reqsign-core" -version = "3.0.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fa5cb48808693614d1701fcd3db0b30fa292e0f18e122ae068b6d32eaeed3f" +checksum = "514a1e0b4aa288652a3fdbda4f0a610f379cdf5374e55a37c9edd03d57ed856b" dependencies = [ "anyhow", "base64 0.22.1", @@ -4320,9 +4253,6 @@ dependencies = [ "jiff", "log", "percent-encoding", - "rsa", - "serde", - "serde_json", "sha1 0.11.0", "sha2 0.11.0", "windows-sys 0.61.2", @@ -4330,9 +4260,9 @@ dependencies = [ [[package]] name = "reqsign-file-read-tokio" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a4b6f3a3fd29ffcc99a90aec585a65217783badfd73acddf847b63ae683bda9" +checksum = "2b472a8d1f2e5a4be8ce13bb7bdf4b59e9bee613ce124aca23959ddb42176b39" dependencies = [ "anyhow", "reqsign-core", @@ -4355,7 +4285,7 @@ dependencies = [ "futures-util", "h2", "http 1.4.2", - "http-body 1.0.1", + "http-body 1.1.0", "http-body-util", "hyper 1.10.1", "hyper-rustls", @@ -4365,7 +4295,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustls 0.23.41", + "rustls 0.23.42", "rustls-pki-types", "rustls-platform-verifier", "serde", @@ -4454,7 +4384,7 @@ dependencies = [ "num_cpus", "parking_lot", "pin-project-lite", - "rand 0.8.6", + "rand 0.8.7", "ref-cast", "rocket_codegen", "rocket_http", @@ -4553,7 +4483,6 @@ dependencies = [ "pkcs1", "pkcs8", "rand_core 0.6.4", - "sha2 0.10.9", "signature", "spki", "subtle", @@ -4635,9 +4564,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.41" +version = "0.23.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" +checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" dependencies = [ "log", "once_cell", @@ -4689,7 +4618,7 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.41", + "rustls 0.23.42", "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki 0.103.13", @@ -4738,15 +4667,6 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - [[package]] name = "same-file" version = "1.0.6" @@ -4810,17 +4730,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scrypt" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" -dependencies = [ - "pbkdf2", - "salsa20", - "sha2 0.10.9", -] - [[package]] name = "sct" version = "0.7.1" @@ -5022,9 +4931,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", "cpufeatures 0.2.17", @@ -5111,15 +5020,15 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "simd_cesu8" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" dependencies = [ "rustc_version", "simdutf8", @@ -5173,9 +5082,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", "windows-sys 0.61.2", @@ -5183,9 +5092,9 @@ dependencies = [ [[package]] name = "spin" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" [[package]] name = "spinning_top" @@ -5392,9 +5301,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" dependencies = [ "cfg-if", ] @@ -5461,9 +5370,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" dependencies = [ "tinyvec_macros", ] @@ -5486,7 +5395,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.4", + "socket2 0.6.5", "tokio-macros", "windows-sys 0.61.2", ] @@ -5518,7 +5427,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.41", + "rustls 0.23.42", "tokio", ] @@ -5622,7 +5531,7 @@ version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] @@ -5639,7 +5548,7 @@ checksum = "f8e43134db17199f7f721803383ac5854edd0d3d523cc34dba321d6acfbe76c3" dependencies = [ "digest 0.10.7", "hmac 0.12.1", - "sha1 0.10.6", + "sha1 0.10.7", "sha2 0.10.9", ] @@ -5670,7 +5579,7 @@ dependencies = [ "futures-core", "futures-util", "http 1.4.2", - "http-body 1.0.1", + "http-body 1.1.0", "http-body-util", "pin-project-lite", "tokio", @@ -5773,8 +5682,8 @@ dependencies = [ "http 1.4.2", "httparse", "log", - "rand 0.8.6", - "sha1 0.10.6", + "rand 0.8.7", + "sha1 0.10.7", "thiserror 1.0.69", "url", "utf-8", @@ -5868,9 +5777,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.23.4" +version = "1.23.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" +checksum = "ea5fab0d6c3c01ae70085a09cb03d4c7a1d6314e2b3e075392783396d724ca0a" dependencies = [ "getrandom 0.4.3", "js-sys", @@ -5886,9 +5795,9 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "value-bag" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" +checksum = "5dd4ec1eb1d240636e354a30110a1dfcb37047169a4d9bd6d9d3469df574b5c4" [[package]] name = "vaultwarden" @@ -5948,7 +5857,7 @@ dependencies = [ "rocket", "rocket_ws", "rpassword", - "rustls 0.23.41", + "rustls 0.23.42", "semver", "serde", "serde_json", @@ -6150,7 +6059,7 @@ dependencies = [ "nom 7.1.3", "openssl", "openssl-sys", - "rand 0.9.4", + "rand 0.9.5", "rand_chacha 0.9.0", "serde", "serde_cbor_2", @@ -6479,9 +6388,9 @@ dependencies = [ [[package]] name = "winnow" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" [[package]] name = "wit-bindgen" @@ -6576,26 +6485,26 @@ dependencies = [ "form_urlencoded", "futures", "hmac 0.12.1", - "rand 0.9.4", + "rand 0.9.5", "reqwest", - "sha1 0.10.6", + "sha1 0.10.7", "threadpool", ] [[package]] name = "zerocopy" -version = "0.8.53" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.53" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" dependencies = [ "proc-macro2", "quote", @@ -6678,9 +6587,9 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zstd" diff --git a/Cargo.toml b/Cargo.toml index 909570e7..eba482df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -166,6 +166,7 @@ lettre = { version = "0.11.22", default-features = false, features = [ "tracing", "serde", "builder", + "dkim", "hostname", # TLS/Security "ring", diff --git a/src/config.rs b/src/config.rs index 49281b6c..85696b83 100644 --- a/src/config.rs +++ b/src/config.rs @@ -14,7 +14,7 @@ use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor}; use crate::{ error::Error, - storage, + mail::check_dkim, util::{ FeatureFlagFilter, get_active_web_release, get_env, get_env_bool, is_valid_email, parse_experimental_client_feature_flags, @@ -885,6 +885,12 @@ make_config! { smtp_username: String, true, option; /// Password smtp_password: Pass, true, option; + /// Dkim signature (type:privatekey). Private must be base64-encoded ed key or PKCS#1 format RSA key. + dkim_signature: String, true, option; + /// Dkim algo (true if RSA else ed25519) + dkim_use_rsa: bool, true, def, false; + /// Dkim infos (selector:domain) + dkim_infos: String, true, option; /// SMTP Auth mechanism |> Defaults for SSL is "Plain" and "Login" and nothing for Non-SSL connections. Possible values: ["Plain", "Login", "Xoauth2"]. Multiple options need to be separated by a comma ','. smtp_auth_mechanism: String, true, option; /// SMTP connection timeout |> Number of seconds when to stop trying to connect to the SMTP server @@ -1161,6 +1167,9 @@ fn validate_config(cfg: &ConfigItems, on_update: bool) -> Result<(), Error> { if cfg._enable_email_2fa && cfg.email_token_size < 6 { err!("`EMAIL_TOKEN_SIZE` has a minimum size of 6") } + if let Err(e) = check_dkim() { + err!(format!("DKIM config fails. {}", e)) + } } if cfg._enable_email_2fa && !(cfg.smtp_host.is_some() || cfg.use_sendmail) { diff --git a/src/mail.rs b/src/mail.rs index f31234d7..73c1ded4 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -2,8 +2,15 @@ use std::{env::consts::EXE_SUFFIX, str::FromStr}; use chrono::NaiveDateTime; use lettre::{ +<<<<<<< HEAD Address, AsyncSendmailTransport, AsyncSmtpTransport, AsyncTransport, Tokio1Executor, message::{Attachment, Body, Mailbox, Message, MultiPart, SinglePart}, +======= + message::{ + dkim::{DkimConfig, DkimSigningAlgorithm, DkimSigningKey}, + dkim_sign, Attachment, Body, Mailbox, Message, MultiPart, SinglePart, + }, +>>>>>>> daa9e075 (corrections on config parsing) transport::smtp::authentication::{Credentials, Mechanism as SmtpAuthMechanism}, transport::smtp::client::{Tls, TlsParameters}, transport::smtp::extension::ClientId, @@ -699,7 +706,41 @@ async fn send_with_selected_transport(email: Message) -> EmptyResult { } } } - +pub fn check_dkim() -> Result, String> { + match (CONFIG.dkim_signature(), CONFIG.dkim_infos()) { + (Some(sig), Some(infos)) => { + let config = { + let algo = if CONFIG.dkim_use_rsa() {DkimSigningAlgorithm::Rsa } else { DkimSigningAlgorithm::Ed25519 }; + let sig = match std::fs::read_to_string(sig) { + Err(e) => { + return Err(format!("Cannot read DKIM key. Err is {:?}", e)); + } + Ok(key) => match DkimSigningKey::new(&key, algo) { + Ok(d) => d, + Err(e) => { + return Err(format!("DKIM key is invalid. Err is {:?}", e)); + } + }, + }; + match (sig, infos.split(':').collect::>()) { + (sig, split2) if split2.len() == 2 => { + let (selector, domain, sig) = + (String::from(*split2.first().unwrap()), String::from(*split2.last().unwrap()), sig); + (selector, domain, sig) + } + _ => { + return Err("DKIM issue, invalid domain, selector.".to_string()); + } + } + }; + Ok(Some(DkimConfig::default_config(config.0, config.1, config.2))) + } + (None, None) => Ok(None), + _ => { + Err("DKIM setting is badly implemented. One config is missing (DKIM signature or DKIM infos).".to_string()) + } + } +} async fn send_email(address: &str, subject: &str, body_html: String, body_text: String) -> EmptyResult { let smtp_from = Address::from_str(&CONFIG.smtp_from())?; @@ -722,12 +763,14 @@ async fn send_email(address: &str, subject: &str, body_html: String, body_text: MultiPart::alternative_plain_html(body_text, body_html) }; - let email = Message::builder() + let mut email = Message::builder() .message_id(Some(format!("<{}@{}>", crate::util::get_uuid(), smtp_from.domain()))) .to(Mailbox::new(None, Address::from_str(address)?)) .from(Mailbox::new(Some(CONFIG.smtp_from_name()), smtp_from)) .subject(subject) .multipart(body)?; - + if let Ok(Some(sig)) = check_dkim() { + dkim_sign(&mut email, &sig); + } send_with_selected_transport(email).await } From eac74fa0d14425d32a78f93299b4ebfa4713b5f2 Mon Sep 17 00:00:00 2001 From: Guilhem Zeitoun Date: Tue, 14 Jul 2026 22:35:14 +0200 Subject: [PATCH 2/7] changes for review --- .env.template | 9 +++++++++ src/config.rs | 13 ++++++++----- src/mail.rs | 51 +++++++++++++++++++++------------------------------ 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/.env.template b/.env.template index 0d922774..76652aa7 100644 --- a/.env.template +++ b/.env.template @@ -640,6 +640,15 @@ ## Embed images as email attachments # SMTP_EMBED_IMAGES=true +## Dkim signature (type:privatekey). |> Private must be base64-encoded ed key or PKCS#1 format RSA key. +# dkim_signing_key=rsa_key.pem +## Dkim algo (true if RSA else ed25519) +# dkim_use_rsa=true +## Dkim selector +# dkim_selector="dkim_key" +## Dkim domain +#dkim_domain="example.com" + ## SMTP debugging ## When set to true this will output very detailed SMTP messages. ## WARNING: This could contain sensitive information like passwords and usernames! Only enable this during troubleshooting! diff --git a/src/config.rs b/src/config.rs index 85696b83..547de889 100644 --- a/src/config.rs +++ b/src/config.rs @@ -15,6 +15,7 @@ use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor}; use crate::{ error::Error, mail::check_dkim, + storage, util::{ FeatureFlagFilter, get_active_web_release, get_env, get_env_bool, is_valid_email, parse_experimental_client_feature_flags, @@ -885,12 +886,14 @@ make_config! { smtp_username: String, true, option; /// Password smtp_password: Pass, true, option; - /// Dkim signature (type:privatekey). Private must be base64-encoded ed key or PKCS#1 format RSA key. - dkim_signature: String, true, option; - /// Dkim algo (true if RSA else ed25519) + /// Dkim signature (private key). |> Private must be base64-encoded ed key or PKCS#1 format RSA key. If set, dkim_selector and dkim_domain must be set as well. + dkim_signing_key: String, true, option; + /// Dkim algorithm (true if RSA else ed25519) dkim_use_rsa: bool, true, def, false; - /// Dkim infos (selector:domain) - dkim_infos: String, true, option; + /// Dkim selector + dkim_selector: String, true, option; + /// Dkim domain + dkim_domain: String, true, option; /// SMTP Auth mechanism |> Defaults for SSL is "Plain" and "Login" and nothing for Non-SSL connections. Possible values: ["Plain", "Login", "Xoauth2"]. Multiple options need to be separated by a comma ','. smtp_auth_mechanism: String, true, option; /// SMTP connection timeout |> Number of seconds when to stop trying to connect to the SMTP server diff --git a/src/mail.rs b/src/mail.rs index 73c1ded4..abe96229 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -2,15 +2,12 @@ use std::{env::consts::EXE_SUFFIX, str::FromStr}; use chrono::NaiveDateTime; use lettre::{ -<<<<<<< HEAD Address, AsyncSendmailTransport, AsyncSmtpTransport, AsyncTransport, Tokio1Executor, message::{Attachment, Body, Mailbox, Message, MultiPart, SinglePart}, -======= message::{ dkim::{DkimConfig, DkimSigningAlgorithm, DkimSigningKey}, - dkim_sign, Attachment, Body, Mailbox, Message, MultiPart, SinglePart, + dkim_sign, }, ->>>>>>> daa9e075 (corrections on config parsing) transport::smtp::authentication::{Credentials, Mechanism as SmtpAuthMechanism}, transport::smtp::client::{Tls, TlsParameters}, transport::smtp::extension::ClientId, @@ -26,7 +23,7 @@ use crate::{ }, db::models::{Device, DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId}, error::Error, - util::upcase_first, + util::{get_env_str_value, upcase_first}, }; fn sendmail_transport() -> AsyncSendmailTransport { @@ -707,38 +704,32 @@ async fn send_with_selected_transport(email: Message) -> EmptyResult { } } pub fn check_dkim() -> Result, String> { - match (CONFIG.dkim_signature(), CONFIG.dkim_infos()) { - (Some(sig), Some(infos)) => { + match ( + CONFIG.dkim_signing_key().and_then(|a| get_env_str_value(&a)), + CONFIG.dkim_domain().and_then(|a| get_env_str_value(&a)), + CONFIG.dkim_selector().and_then(|a| get_env_str_value(&a)), //get_env_str should return None only if variables are not set, which is already checked + ) { + (Some(sig), Some(domain), Some(selector)) => { let config = { - let algo = if CONFIG.dkim_use_rsa() {DkimSigningAlgorithm::Rsa } else { DkimSigningAlgorithm::Ed25519 }; - let sig = match std::fs::read_to_string(sig) { + let algo = if CONFIG.dkim_use_rsa() { + DkimSigningAlgorithm::Rsa + } else { + DkimSigningAlgorithm::Ed25519 + }; + let sig = match DkimSigningKey::new(&sig, algo) { + Ok(d) => d, Err(e) => { - return Err(format!("Cannot read DKIM key. Err is {:?}", e)); + return Err(format!("DKIM key is invalid. Err is {e:?}")); } - Ok(key) => match DkimSigningKey::new(&key, algo) { - Ok(d) => d, - Err(e) => { - return Err(format!("DKIM key is invalid. Err is {:?}", e)); - } - }, }; - match (sig, infos.split(':').collect::>()) { - (sig, split2) if split2.len() == 2 => { - let (selector, domain, sig) = - (String::from(*split2.first().unwrap()), String::from(*split2.last().unwrap()), sig); - (selector, domain, sig) - } - _ => { - return Err("DKIM issue, invalid domain, selector.".to_string()); - } - } + (selector, domain, sig) }; Ok(Some(DkimConfig::default_config(config.0, config.1, config.2))) } - (None, None) => Ok(None), - _ => { - Err("DKIM setting is badly implemented. One config is missing (DKIM signature or DKIM infos).".to_string()) - } + (None, None, None) => Ok(None), + _ => Err( + "DKIM setting is badly implemented. One config is missing or invalid (DKIM signature or DKIM infos or DKIM signing key).".to_owned(), + ), } } async fn send_email(address: &str, subject: &str, body_html: String, body_text: String) -> EmptyResult { From b9166502cb51fb8027617f392a4016167e203666 Mon Sep 17 00:00:00 2001 From: Guilhem Zeitoun Date: Sun, 26 Apr 2026 17:41:34 +0200 Subject: [PATCH 3/7] Corrections on env and naming. --- src/config.rs | 6 ++++++ src/mail.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/config.rs b/src/config.rs index 547de889..06977c3a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -886,9 +886,15 @@ make_config! { smtp_username: String, true, option; /// Password smtp_password: Pass, true, option; +<<<<<<< HEAD /// Dkim signature (private key). |> Private must be base64-encoded ed key or PKCS#1 format RSA key. If set, dkim_selector and dkim_domain must be set as well. dkim_signing_key: String, true, option; /// Dkim algorithm (true if RSA else ed25519) +======= + /// Dkim private key (type:privatekey). Private must be base64-encoded ed key or PKCS#1 format RSA key. + dkim_privatekey: String, true, option; + /// Dkim algo (true if RSA else ed25519) +>>>>>>> f829426d (Corrections on env and naming.) dkim_use_rsa: bool, true, def, false; /// Dkim selector dkim_selector: String, true, option; diff --git a/src/mail.rs b/src/mail.rs index abe96229..08ba0fce 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -15,6 +15,7 @@ use lettre::{ use percent_encoding::{NON_ALPHANUMERIC, percent_encode}; use crate::{ +<<<<<<< HEAD CONFIG, api::EmptyResult, auth::{ @@ -24,6 +25,12 @@ use crate::{ db::models::{Device, DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId}, error::Error, util::{get_env_str_value, upcase_first}, +======= + CONFIG, api::EmptyResult, auth::{ + encode_jwt, generate_delete_claims, generate_emergency_access_invite_claims, generate_invite_claims, + generate_verify_email_claims, + }, db::models::{Device, DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId}, error::Error, util::get_env +>>>>>>> f829426d (Corrections on env and naming.) }; fn sendmail_transport() -> AsyncSendmailTransport { @@ -704,6 +711,7 @@ async fn send_with_selected_transport(email: Message) -> EmptyResult { } } pub fn check_dkim() -> Result, String> { +<<<<<<< HEAD match ( CONFIG.dkim_signing_key().and_then(|a| get_env_str_value(&a)), CONFIG.dkim_domain().and_then(|a| get_env_str_value(&a)), @@ -730,6 +738,27 @@ pub fn check_dkim() -> Result, String> { _ => Err( "DKIM setting is badly implemented. One config is missing or invalid (DKIM signature or DKIM infos or DKIM signing key).".to_owned(), ), +======= + match (get_env::("dkim_privatekey"), CONFIG.dkim_infos()) { + (Some(pk), Some(infos)) => { + let algo = if CONFIG.dkim_use_rsa() {DkimSigningAlgorithm::Rsa } else { DkimSigningAlgorithm::Ed25519 }; + let (selector, domain, privatekey) = match (DkimSigningKey::new(pk.as_str(), algo), infos.split(':').collect::>()) { + (Ok(sig), split2) if split2.len() == 2 => { + let (selector, domain, sig) = + (String::from(*split2.first().unwrap()), String::from(*split2.last().unwrap()), sig); + (selector, domain, sig) + } + _ => { + return Err("DKIM issue, invalid domain, selector.".to_string()); + } + }; + return Ok(Some(DkimConfig::default_config(selector, domain, privatekey))); + }, + (None, None) => Ok(None), + _ => { + Err("DKIM setting is badly implemented. One config is missing (DKIM signature or DKIM infos).".to_string()) + } +>>>>>>> f829426d (Corrections on env and naming.) } } async fn send_email(address: &str, subject: &str, body_html: String, body_text: String) -> EmptyResult { From 29d76b5451573416795d3662d34a42ba8645baa1 Mon Sep 17 00:00:00 2001 From: Guilhem Zeitoun Date: Tue, 14 Jul 2026 22:39:28 +0200 Subject: [PATCH 4/7] rebase fix --- src/config.rs | 6 ------ src/mail.rs | 29 ----------------------------- 2 files changed, 35 deletions(-) diff --git a/src/config.rs b/src/config.rs index 06977c3a..547de889 100644 --- a/src/config.rs +++ b/src/config.rs @@ -886,15 +886,9 @@ make_config! { smtp_username: String, true, option; /// Password smtp_password: Pass, true, option; -<<<<<<< HEAD /// Dkim signature (private key). |> Private must be base64-encoded ed key or PKCS#1 format RSA key. If set, dkim_selector and dkim_domain must be set as well. dkim_signing_key: String, true, option; /// Dkim algorithm (true if RSA else ed25519) -======= - /// Dkim private key (type:privatekey). Private must be base64-encoded ed key or PKCS#1 format RSA key. - dkim_privatekey: String, true, option; - /// Dkim algo (true if RSA else ed25519) ->>>>>>> f829426d (Corrections on env and naming.) dkim_use_rsa: bool, true, def, false; /// Dkim selector dkim_selector: String, true, option; diff --git a/src/mail.rs b/src/mail.rs index 08ba0fce..abe96229 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -15,7 +15,6 @@ use lettre::{ use percent_encoding::{NON_ALPHANUMERIC, percent_encode}; use crate::{ -<<<<<<< HEAD CONFIG, api::EmptyResult, auth::{ @@ -25,12 +24,6 @@ use crate::{ db::models::{Device, DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId}, error::Error, util::{get_env_str_value, upcase_first}, -======= - CONFIG, api::EmptyResult, auth::{ - encode_jwt, generate_delete_claims, generate_emergency_access_invite_claims, generate_invite_claims, - generate_verify_email_claims, - }, db::models::{Device, DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId}, error::Error, util::get_env ->>>>>>> f829426d (Corrections on env and naming.) }; fn sendmail_transport() -> AsyncSendmailTransport { @@ -711,7 +704,6 @@ async fn send_with_selected_transport(email: Message) -> EmptyResult { } } pub fn check_dkim() -> Result, String> { -<<<<<<< HEAD match ( CONFIG.dkim_signing_key().and_then(|a| get_env_str_value(&a)), CONFIG.dkim_domain().and_then(|a| get_env_str_value(&a)), @@ -738,27 +730,6 @@ pub fn check_dkim() -> Result, String> { _ => Err( "DKIM setting is badly implemented. One config is missing or invalid (DKIM signature or DKIM infos or DKIM signing key).".to_owned(), ), -======= - match (get_env::("dkim_privatekey"), CONFIG.dkim_infos()) { - (Some(pk), Some(infos)) => { - let algo = if CONFIG.dkim_use_rsa() {DkimSigningAlgorithm::Rsa } else { DkimSigningAlgorithm::Ed25519 }; - let (selector, domain, privatekey) = match (DkimSigningKey::new(pk.as_str(), algo), infos.split(':').collect::>()) { - (Ok(sig), split2) if split2.len() == 2 => { - let (selector, domain, sig) = - (String::from(*split2.first().unwrap()), String::from(*split2.last().unwrap()), sig); - (selector, domain, sig) - } - _ => { - return Err("DKIM issue, invalid domain, selector.".to_string()); - } - }; - return Ok(Some(DkimConfig::default_config(selector, domain, privatekey))); - }, - (None, None) => Ok(None), - _ => { - Err("DKIM setting is badly implemented. One config is missing (DKIM signature or DKIM infos).".to_string()) - } ->>>>>>> f829426d (Corrections on env and naming.) } } async fn send_email(address: &str, subject: &str, body_html: String, body_text: String) -> EmptyResult { From 9f09c306230f369ef4430b742733eb43a0fe49c0 Mon Sep 17 00:00:00 2001 From: Guilhem Zeitoun Date: Tue, 14 Jul 2026 23:13:11 +0200 Subject: [PATCH 5/7] test if needed --- src/mail.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/mail.rs b/src/mail.rs index abe96229..d6ed18d4 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -765,3 +765,41 @@ async fn send_email(address: &str, subject: &str, body_html: String, body_text: } send_with_selected_transport(email).await } +#[cfg(test)] +mod tests { + use super::*; + const RSAKEY: &str = "-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAtSROEsCJGYiDsoECpdlv7ufopGp2kaM2ii50Hs/3mKFevuTc +mku0+QSjSZblLsmKwvTmoJyE1r4ztAzSmeYeB66HIfOHu7Fk0b7R5jcraRoZdG5H +ko/vO9fkL6e2Bz1ZhOV/mrD5PMJx9uxqpnibqm2puA3+Q0xmfcgQeYPJm2XgCFHc +sSL+yRu3rLlkv/ZOmLECqheJl7zJAeh1I66LrdS13UHRQOuP7hNeBrWrdGY8e7W6 +p6jiKXloiqgP6vZZnuDx/GGD2TvmqW7Axbhr/lVTW1ogHs0IwSqazF5tvDZC9OjY +auEa86VQI35jvQfbzvpUqEZH5pOaT6f4E12nowIDAQABAoIBABD/773NyPAXAjkR +53Q2JE2ZARnRDgCb/yXXtzkfDl8KIfCrXNK0MS8/kq141lhePMIQJsbC+aqHniWT +IH6l/IJ/DBqRFtd0DgCrNlqzKcVK2EG3icsE7BBDMhyQ0kH6rXiN6zxSyIk9vGFO +jbHC1uUXNprZ4Vdih6ndSUKGLjkBnXu0mSpVMkjsfPFp3GggqdmPoqHU9BKr+Top +IOZ9O4yp1JtX7D928aqEL18tmUTfa+GL/KwWMUKSRhDeHWCZtJ0Zq9hyfDUoYW6J +3VvyMAKtxnwq4JnO06x79q3YbdQOCrhWcJCFyVDQHKqJtpj0UEpWlNCHfrOtWr8N +XzP6Np0CgYEA7LIWohi4Xwv7aa5Zd408C0urI1nV0QCRyQtypqqdL3CIjbPBW4nJ +TUV5/rgB/DQiafYDAiUbVmK5KSFozn7Lla1OYu0LhGGd+Wg+5iX66h9JLG8NTaGt +9wzk8ocz/+56i/E4CwDGLhJsNGz/hlHB2kdON+dAls7lYrlnS1inlIcCgYEAw+pS +QGeT/fJUUVPa3dGudryyc9hhRmTC0pamoJmRzl9+1416ZmHR/Fa7zIKV8okDa+x9 +nzidrl/maPHTAXXcltUx3yhhBX8gSP6JaMtBOVQeus+GFXOtEMaJ6WA8nFv2lCPB +FLcyTZtM0UO55qb8HZkeFuwWugNtxIZpCb3LdwUCgYAlZCjBKKiPk0P/OOS3Rx9y +JVz+s6VcY/ujx+QvwgocwWlBAWGNRWIAi/YusADYR6AcHxnwj84Wwne/sKBu5obg +uUUFya6lFgqvqLEvCFbv/0s+8rgmSGFEAsx0J7mmN5UyYEPbMR8djhl72rAvFuFJ +yzPnDugcKsj/5IwV0gZ/JwKBgHXJqY4DOBzT1xHWYp4+dK/6nye7DjDuX5uQ67le +2yTCkVYzP0XSxhb6Zop8cH6TFbWLR7O0rEisa7Dowz37iJY+s29BraNKXTTFpAOX +QC2hf6A9KJY5J/IQC9Z9/7LaL5O9M1arFdlG55ZhK6Ga/7Uj281YQAmyCgq/7OLo +cy2pAoGAAmkEQRIuoPHRsBMtbybAsKJeYlY6r5V3aA5v7A4bb1gma2LOYvpXV1/L +R7Zsckp3e8q4afGLEbjqQp3HJV9In5xkCsDWfLj+WB6hOUwEXMCVQ6d1RiezsfBw +sK77Q2NwzF97mD+bkq8aVnYAHcc7hKYzgP5ZeJyI3XbilFgQD0Q= +-----END RSA PRIVATE KEY-----"; + const ECDSAKEY: &str = "b3y5uWvqVte+ZThKnUGN97do2zsygO3QMWH85DBoDmg="; + #[test] + fn checkdkim() { + //Dkim is already checked on lettre but we still provide some examples of use + let _a = DkimSigningKey::new(RSAKEY, DkimSigningAlgorithm::Rsa).unwrap(); + let _b = DkimSigningKey::new(ECDSAKEY, DkimSigningAlgorithm::Ed25519).unwrap(); + } +} From 19dd24e24caec28a3afbc2a10ea44f3c9628ba39 Mon Sep 17 00:00:00 2001 From: Guilhem Zeitoun Date: Wed, 15 Jul 2026 07:06:44 +0200 Subject: [PATCH 6/7] bad use of get_env_str --- src/mail.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mail.rs b/src/mail.rs index d6ed18d4..ff8a2e2b 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -705,9 +705,9 @@ async fn send_with_selected_transport(email: Message) -> EmptyResult { } pub fn check_dkim() -> Result, String> { match ( - CONFIG.dkim_signing_key().and_then(|a| get_env_str_value(&a)), - CONFIG.dkim_domain().and_then(|a| get_env_str_value(&a)), - CONFIG.dkim_selector().and_then(|a| get_env_str_value(&a)), //get_env_str should return None only if variables are not set, which is already checked + CONFIG.dkim_signing_key().or_else(|| get_env_str_value("dkim_signing_key")), + CONFIG.dkim_domain().or_else(|| get_env_str_value("dkim_domain")), + CONFIG.dkim_selector().or_else(|| get_env_str_value("dkim_selector")), ) { (Some(sig), Some(domain), Some(selector)) => { let config = { From 0fecadd124de3958916e01225570a49c1a372a88 Mon Sep 17 00:00:00 2001 From: Guilhem Zeitoun Date: Wed, 15 Jul 2026 07:10:04 +0200 Subject: [PATCH 7/7] template correction --- .env.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.template b/.env.template index 76652aa7..e6c78f24 100644 --- a/.env.template +++ b/.env.template @@ -641,9 +641,9 @@ # SMTP_EMBED_IMAGES=true ## Dkim signature (type:privatekey). |> Private must be base64-encoded ed key or PKCS#1 format RSA key. -# dkim_signing_key=rsa_key.pem +# dkim_signing_key="b3y5uWvqVte+ZThKnUGN97do2zsygO3QMWH85DBoDmg=" ## Dkim algo (true if RSA else ed25519) -# dkim_use_rsa=true +# dkim_use_rsa=false ## Dkim selector # dkim_selector="dkim_key" ## Dkim domain