diff --git a/Cargo.lock b/Cargo.lock index 1fd99f6a..49f4705c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,36 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.20" @@ -54,12 +84,33 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "base64ct" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + [[package]] name = "bstr" version = "0.2.17" @@ -75,17 +126,47 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -104,11 +185,20 @@ dependencies = [ "num-integer", "num-traits", "serde", - "time", + "time 0.1.45", "wasm-bindgen", "winapi", ] +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + [[package]] name = "clap" version = "4.1.4" @@ -167,12 +257,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "core-foundation-sys" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam" version = "0.8.2" @@ -240,6 +354,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "cxx" version = "1.0.90" @@ -284,18 +408,56 @@ dependencies = [ "syn", ] +[[package]] +name = "data-encoding" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" + [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "either" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-as-inner" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "erased-serde" version = "0.3.24" @@ -335,12 +497,46 @@ dependencies = [ "instant", ] +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +dependencies = [ + "futures-core", +] + [[package]] name = "futures-core" version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +[[package]] +name = "futures-io" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" + [[package]] name = "futures-macro" version = "0.3.26" @@ -372,6 +568,26 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a329e22866dd78b35d2c639a4a23d7b950aeae300dfd79f4fb19f74055c2404" +dependencies = [ + "libc", + "windows", +] + [[package]] name = "getrandom" version = "0.2.8" @@ -422,6 +638,26 @@ dependencies = [ "rustc-hash", ] +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "iana-time-zone" version = "0.1.53" @@ -446,6 +682,27 @@ dependencies = [ "cxx-build", ] +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "instant" version = "0.1.12" @@ -465,6 +722,24 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "ipconfig" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" +dependencies = [ + "socket2", + "widestring", + "winapi", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" + [[package]] name = "is-terminal" version = "0.4.3" @@ -483,6 +758,15 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.61" @@ -527,6 +811,7 @@ dependencies = [ "clap", "k9", "lazy_static", + "mail-auth", "message", "mlua", "serde", @@ -559,6 +844,12 @@ dependencies = [ "cc", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -584,6 +875,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "lua-src" version = "544.0.1" @@ -602,6 +902,51 @@ dependencies = [ "cc", ] +[[package]] +name = "mail-auth" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b9a954bf000fccf7e21eb9906482f7278b70a64f8dd26c8a649f080e8f926b" +dependencies = [ + "ahash", + "flate2", + "lru-cache", + "mail-builder", + "mail-parser", + "parking_lot", + "quick-xml", + "ring", + "rustls-pemfile", + "serde", + "serde_json", + "trust-dns-resolver", + "zip", +] + +[[package]] +name = "mail-builder" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8390bb0f68168cabc59999706c2199c9b556d7dfd94e65a26e8840fa1d58b238" +dependencies = [ + "gethostname", +] + +[[package]] +name = "mail-parser" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2e03aa1d18528b45d0e79e46790f38cfeece6cce3af17a85912677272f36cd" +dependencies = [ + "encoding_rs", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchers" version = "0.1.0" @@ -611,6 +956,12 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "memchr" version = "2.5.0" @@ -641,6 +992,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.5" @@ -719,6 +1079,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "os_str_bytes" version = "6.4.1" @@ -754,6 +1120,35 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -811,6 +1206,21 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-xml" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc053f057dd768a56f62cd7e434c42c831d296968997e9ac1f76ea7c2d14c41" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.23" @@ -916,6 +1326,31 @@ dependencies = [ "winapi", ] +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -936,6 +1371,27 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +dependencies = [ + "base64", +] + [[package]] name = "ryu" version = "1.0.12" @@ -954,6 +1410,16 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "serde" version = "1.0.152" @@ -985,6 +1451,28 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -1028,6 +1516,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spool" version = "0.1.0" @@ -1047,6 +1541,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.107" @@ -1091,6 +1591,26 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.4" @@ -1111,6 +1631,22 @@ dependencies = [ "winapi", ] +[[package]] +name = "time" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +dependencies = [ + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + [[package]] name = "timeq" version = "0.1.0" @@ -1118,6 +1654,21 @@ dependencies = [ "hierarchical_hash_wheel_timer", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.25.0" @@ -1149,6 +1700,17 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + [[package]] name = "tracing" version = "0.1.37" @@ -1211,18 +1773,109 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "trust-dns-proto" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.2.3", + "ipnet", + "lazy_static", + "rand", + "ring", + "rustls", + "rustls-pemfile", + "smallvec", + "thiserror", + "tinyvec", + "tokio", + "tokio-rustls", + "tracing", + "url", + "webpki", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" +dependencies = [ + "cfg-if", + "futures-util", + "ipconfig", + "lazy_static", + "lru-cache", + "parking_lot", + "resolv-conf", + "rustls", + "smallvec", + "thiserror", + "tokio", + "tokio-rustls", + "tracing", + "trust-dns-proto", + "webpki-roots", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-bidi" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" + [[package]] name = "unicode-ident" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-width" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna 0.3.0", + "percent-encoding", +] + [[package]] name = "uuid" version = "1.3.0" @@ -1311,6 +1964,41 @@ version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + +[[package]] +name = "widestring" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" + [[package]] name = "winapi" version = "0.3.9" @@ -1342,6 +2030,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + [[package]] name = "windows-sys" version = "0.42.0" @@ -1422,3 +2125,62 @@ name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "zip" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0445d0fbc924bb93539b4316c11afb121ea39296f99a3c4c9edad09e3658cdef" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time 0.3.17", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.7+zstd.1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" +dependencies = [ + "cc", + "libc", + "pkg-config", +] diff --git a/crates/kumod/Cargo.toml b/crates/kumod/Cargo.toml index 6bba8376..5b21eed6 100644 --- a/crates/kumod/Cargo.toml +++ b/crates/kumod/Cargo.toml @@ -12,6 +12,7 @@ lazy_static = "1.4" mlua = {version="0.8", features=["vendored", "lua54", "async", "send", "serialize"]} serde = {version="1.0", features=["derive"]} serde_json = "1.0" +mail-auth = "0.3" message = {path="../message"} spool = {path="../spool"} timeq = {path="../timeq"} diff --git a/crates/kumod/src/dest_site.rs b/crates/kumod/src/dest_site.rs new file mode 100644 index 00000000..e35b171e --- /dev/null +++ b/crates/kumod/src/dest_site.rs @@ -0,0 +1,186 @@ +use mail_auth::{Resolver, MX}; +use message::Message; +use std::collections::HashMap; +use std::sync::Arc; +use tokio::sync::mpsc::error::TrySendError; +use tokio::sync::mpsc::{Receiver, Sender}; +use tokio::sync::{Mutex, MutexGuard}; + +lazy_static::lazy_static! { + static ref MANAGER: Mutex = Mutex::new(SiteManager::new()); + static ref RESOLVER: Mutex = Mutex::new(Resolver::new_system_conf().unwrap()); +} + +pub struct SiteManager { + sites: HashMap, +} + +impl SiteManager { + pub fn new() -> Self { + Self { + sites: HashMap::new(), + } + } + + pub async fn get() -> MutexGuard<'static, Self> { + MANAGER.lock().await + } + + pub async fn resolve_domain(name: &str) -> anyhow::Result { + let resolver = RESOLVER.lock().await; + let mx = resolver + .mx_lookup(name) + .await + .map_err(|err| anyhow::anyhow!("MX lookup for {name} failed: {err:#}"))?; + let name = factor_mx_list(&mx); + + let mut manager = Self::get().await; + let handle = manager.sites.entry(name.clone()).or_insert_with(|| { + let (tx, rx) = tokio::sync::mpsc::channel(1024 /* FIXME: configurable */); + SiteHandle(Arc::new(Mutex::new(DestinationSite { + name: name.clone(), + mx, + tx, + rx, + }))) + }); + Ok(handle.clone()) + } +} + +#[derive(Clone)] +pub struct SiteHandle(Arc>); + +impl SiteHandle { + pub async fn lock(&self) -> MutexGuard { + self.0.lock().await + } +} + +pub struct DestinationSite { + name: String, + mx: Arc>, + tx: Sender, + rx: Receiver, +} + +impl DestinationSite { + pub fn name(&self) -> &str { + &self.name + } + + pub fn insert(&self, msg: Message) -> Result<(), TrySendError> { + self.tx.try_send(msg) + } +} + +/// Given a set of MX records, produce a pseudo-regex style alternation +/// list of the underlying hostnames +fn factor_mx_list(mx: &Arc>) -> String { + let mut names = vec![]; + for entry in mx.iter() { + for host in &entry.exchanges { + names.push(host.as_str()); + } + } + + factor_names(&names) +} + +/// Given a list of host names, produce a pseudo-regex style alternation list +/// of the different elements of the hostnames. +/// The goal is to produce a more compact representation of the name list +/// with the common components factored out. +fn factor_names(names: &[&str]) -> String { + let mut max_element_count = 0; + + let mut elements: Vec> = vec![]; + + let mut split_names = vec![]; + for name in names { + let mut fields: Vec<_> = name.split('.').map(|s| s.to_lowercase()).collect(); + fields.reverse(); + max_element_count = max_element_count.max(fields.len()); + split_names.push(fields); + } + + fn add_element<'a>(elements: &mut Vec>, field: &'a str, i: usize) { + match elements.get_mut(i) { + Some(ele) => { + if !ele.contains(&field) { + ele.push(field); + } + } + None => { + elements.push(vec![field]); + } + } + } + + for fields in &split_names { + for (i, field) in fields.iter().enumerate() { + add_element(&mut elements, field, i); + } + for i in fields.len()..max_element_count { + add_element(&mut elements, "?", i); + } + } + + let mut result = vec![]; + for mut ele in elements { + let has_q = ele.contains(&"?"); + ele.retain(|&e| e != "?"); + let mut item_text = if ele.len() == 1 { + ele[0].to_string() + } else { + format!("({})", ele.join("|")) + }; + if has_q { + item_text.push('?'); + } + result.push(item_text); + } + result.reverse(); + + result.join(".") +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn name_factoring() { + assert_eq!( + factor_names(&[ + "mta5.am0.yahoodns.net", + "mta6.am0.yahoodns.net", + "mta7.am0.yahoodns.net" + ]), + "(mta5|mta6|mta7).am0.yahoodns.net".to_string() + ); + + // Verify that the case is normalized to lowercase + assert_eq!( + factor_names(&[ + "mta5.AM0.yahoodns.net", + "mta6.am0.yAHOodns.net", + "mta7.am0.yahoodns.net" + ]), + "(mta5|mta6|mta7).am0.yahoodns.net".to_string() + ); + + // When the names have mismatched lengths, do we produce + // something reasonable? + assert_eq!( + factor_names(&[ + "gmail-smtp-in.l.google.com", + "alt1.gmail-smtp-in.l.google.com", + "alt2.gmail-smtp-in.l.google.com", + "alt3.gmail-smtp-in.l.google.com", + "alt4.gmail-smtp-in.l.google.com", + ]), + "(alt1|alt2|alt3|alt4)?.gmail-smtp-in.l.google.com".to_string() + ); + } +} diff --git a/crates/kumod/src/main.rs b/crates/kumod/src/main.rs index 4495fed5..5a7dff28 100644 --- a/crates/kumod/src/main.rs +++ b/crates/kumod/src/main.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use tracing_subscriber::prelude::*; use tracing_subscriber::{fmt, EnvFilter}; +mod dest_site; mod lua_config; mod mod_kumo; mod queue; diff --git a/crates/kumod/src/queue.rs b/crates/kumod/src/queue.rs index 15dc905b..813746d3 100644 --- a/crates/kumod/src/queue.rs +++ b/crates/kumod/src/queue.rs @@ -1,8 +1,11 @@ +use crate::dest_site::SiteManager; use message::Message; use std::collections::HashMap; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::Arc; use std::time::Duration; use timeq::{TimeQ, TimerError}; +use tokio::sync::mpsc::error::TrySendError; +use tokio::sync::{Mutex, MutexGuard}; use tokio::task::JoinHandle; lazy_static::lazy_static! { @@ -13,8 +16,8 @@ lazy_static::lazy_static! { pub struct QueueHandle(Arc>); impl QueueHandle { - pub fn lock(&self) -> MutexGuard { - self.0.lock().unwrap() + pub async fn lock(&self) -> MutexGuard { + self.0.lock().await } } @@ -33,7 +36,7 @@ impl Drop for Queue { } impl Queue { - pub fn new(name: String) -> QueueHandle { + pub async fn new(name: String) -> QueueHandle { let handle = QueueHandle(Arc::new(Mutex::new(Queue { name: name.clone(), queue: TimeQ::new(), @@ -43,23 +46,49 @@ impl Queue { let queue_clone = handle.clone(); let maintainer = tokio::spawn(async move { if let Err(err) = maintain_named_queue(&queue_clone).await { - tracing::error!("maintain_named_queue {}: {err:#}", queue_clone.lock().name); + tracing::error!( + "maintain_named_queue {}: {err:#}", + queue_clone.lock().await.name + ); } }); - handle.lock().maintainer.replace(maintainer); + handle.lock().await.maintainer.replace(maintainer); handle } - pub fn insert(&mut self, msg: Message) { + pub async fn insert(&mut self, msg: Message) -> anyhow::Result<()> { match self.queue.insert(Arc::new(msg)) { - Ok(_) => {} + Ok(_) => Ok(()), Err(TimerError::Expired(msg)) => { - // TODO: for immediately ready messages, - // immediately instantiate the destination site - // and add to its queue - tracing::error!("queue to destination site"); + let msg = (*msg).clone(); + match SiteManager::resolve_domain(&self.name).await { + Ok(site) => { + let site = site.lock().await; + println!("site is {}", site.name()); + match site.insert(msg) { + Ok(_) => {} + Err(TrySendError::Closed(msg)) | Err(TrySendError::Full(msg)) => { + msg.delay_by(Duration::from_secs(60)); + self.queue + .insert(Arc::new(msg)) + .map_err(|_err| anyhow::anyhow!("failed to insert"))?; + } + } + } + Err(err) => { + tracing::error!("Failed to resolve {}: {err:#}", self.name); + msg.delay_by(Duration::from_secs(60)); + self.queue + .insert(Arc::new(msg)) + .map_err(|_err| anyhow::anyhow!("failed to insert"))?; + } + } + + Ok(()) + } + Err(TimerError::NotFound) => { + anyhow::bail!("queue.insert returned impossible NotFound error") } - Err(TimerError::NotFound) => unreachable!(), } } } @@ -79,17 +108,23 @@ impl QueueManager { /// Note that the queue names are case-insensitive, and /// internally the lowercased version of `name` is used /// to track the queue. - pub fn insert(&mut self, name: &str, msg: Message) { + pub async fn insert(&mut self, name: &str, msg: Message) -> anyhow::Result<()> { let name = name.to_lowercase(); - let queue = self - .named - .entry(name.clone()) - .or_insert_with(|| Queue::new(name)); - queue.lock().insert(msg); + let entry_keeper; + let entry = match self.named.get(&name) { + Some(e) => e, + None => { + entry_keeper = Queue::new(name.clone()).await; + self.named.insert(name, entry_keeper.clone()); + &entry_keeper + } + }; + let mut entry = entry.lock().await; + entry.insert(msg).await } - pub fn get() -> MutexGuard<'static, Self> { - MANAGER.lock().unwrap() + pub async fn get() -> MutexGuard<'static, Self> { + MANAGER.lock().await } } @@ -97,7 +132,7 @@ async fn maintain_named_queue(queue: &QueueHandle) -> anyhow::Result<()> { loop { tokio::time::sleep(Duration::from_secs(60)).await; { - let q = queue.lock(); + let q = queue.lock().await; println!( "maintaining queue {} which has {} entries", q.name, diff --git a/crates/kumod/src/smtp_server.rs b/crates/kumod/src/smtp_server.rs index 2d76f587..0c3115d1 100644 --- a/crates/kumod/src/smtp_server.rs +++ b/crates/kumod/src/smtp_server.rs @@ -1,4 +1,5 @@ use crate::lua_config::{load_config, LuaConfig}; +use crate::queue::QueueManager; use anyhow::anyhow; use message::{EnvelopeAddress, Message}; use std::fmt::Debug; @@ -203,9 +204,10 @@ impl SmtpServer { messages.push(message); } + let mut queue_manager = QueueManager::get().await; for msg in messages { let domain = msg.recipient()?.domain().to_string(); - crate::queue::QueueManager::get().insert(&domain, msg); + queue_manager.insert(&domain, msg).await?; } let ids = ids.join(" "); diff --git a/crates/message/src/message.rs b/crates/message/src/message.rs index 88ae13a5..19a484a6 100644 --- a/crates/message/src/message.rs +++ b/crates/message/src/message.rs @@ -88,6 +88,11 @@ impl Message { inner.due } + pub fn delay_by(&self, duration: Duration) { + let due = Utc::now() + chrono::Duration::milliseconds(duration.as_millis() as _); + self.set_due(Some(due)); + } + pub fn set_due(&self, due: Option>) { let mut inner = self.inner.lock().unwrap(); inner.due = due;