diff options
author | mdecimus <mauro@stalw.art> | 2024-09-19 19:39:35 +0200 |
---|---|---|
committer | mdecimus <mauro@stalw.art> | 2024-09-19 19:39:35 +0200 |
commit | a67f308645ad0873850efc832d72b7575b40f48e (patch) | |
tree | 63547f6925e0cb43b2aa3592e7a283d9ae6d0f65 | |
parent | e9d12aea44930d5136a67fc9536d55d31d9a1ddc (diff) |
Branding + fixes
51 files changed, 514 insertions, 427 deletions
@@ -4,20 +4,14 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -180,9 +174,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "arbitrary" @@ -213,9 +207,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -385,7 +379,7 @@ dependencies = [ "serde", "serde_json", "url", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", ] [[package]] @@ -469,17 +463,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -788,9 +782,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" [[package]] name = "byteorder" @@ -800,9 +794,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "bzip2" @@ -855,9 +849,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.15" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" dependencies = [ "jobserver", "libc", @@ -962,9 +956,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.16" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", @@ -972,9 +966,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", @@ -1042,7 +1036,7 @@ dependencies = [ [[package]] name = "common" -version = "0.9.4" +version = "0.10.0" dependencies = [ "ahash 0.8.11", "arc-swap", @@ -1075,12 +1069,13 @@ dependencies = [ "privdrop", "prometheus", "proxy-header", + "psl", "pwhash", "rcgen 0.12.1", "regex", "reqwest 0.12.7", "ring 0.17.8", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", @@ -1176,9 +1171,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -1437,9 +1432,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "6.0.1" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804c8821570c3f8b70230c2ba75ffa5c0f9a4189b9a432b6656c536712acae28" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if", "crossbeam-utils", @@ -1650,7 +1645,7 @@ dependencies = [ [[package]] name = "directory" -version = "0.9.4" +version = "0.10.0" dependencies = [ "ahash 0.8.11", "argon2", @@ -1670,7 +1665,7 @@ dependencies = [ "proc_macros", "pwhash", "regex", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pki-types", "scrypt", "serde", @@ -1932,11 +1927,11 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.77", @@ -2038,7 +2033,7 @@ checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", "libz-sys", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -2354,9 +2349,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "glob" @@ -2739,20 +2734,20 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", "hyper 1.4.1", "hyper-util", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", "tower-service", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", ] [[package]] @@ -2770,9 +2765,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" dependencies = [ "bytes", "futures-channel", @@ -2790,9 +2785,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2984,7 +2979,7 @@ checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" [[package]] name = "imap" -version = "0.9.4" +version = "0.10.0" dependencies = [ "ahash 0.8.11", "common", @@ -2999,7 +2994,7 @@ dependencies = [ "nlp", "parking_lot", "rand", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pemfile 2.1.3", "store", "tokio", @@ -3096,9 +3091,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "is-terminal" @@ -3196,7 +3191,7 @@ dependencies = [ [[package]] name = "jmap" -version = "0.9.4" +version = "0.10.0" dependencies = [ "aes", "aes-gcm", @@ -3549,9 +3544,9 @@ dependencies = [ [[package]] name = "lz4-sys" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109de74d5d2353660401699a4174a4ff23fcc649caf553df71933c7fb45ad868" +checksum = "fcb44a01837a858d47e5a630d2ccf304c8efcc4b83b8f9f75b7a9ee4fcc6e57d" dependencies = [ "cc", "libc", @@ -3575,9 +3570,9 @@ dependencies = [ [[package]] name = "mail-auth" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd9d657de66a3d5ac360c3eab8c9f5cac2565f2b97cc032d5de4c900ef470de" +checksum = "aaee4c38f4df428c6732f3d5472a013fa248d2772f48c8932295b32c683a23c4" dependencies = [ "ahash 0.8.11", "flate2", @@ -3586,7 +3581,7 @@ dependencies = [ "mail-builder", "mail-parser", "parking_lot", - "quick-xml 0.32.0", + "quick-xml 0.36.1", "rand", "ring 0.17.8", "rsa", @@ -3607,9 +3602,9 @@ dependencies = [ [[package]] name = "mail-parser" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5a1335c3a964788c90cb42ae04a34b5f2628e89566949ce3bd4ada695c0bcd" +checksum = "93c3b9e5d8b17faf573330bbc43b37d6e918c0a3bf8a88e7d0a220ebc84af9fc" dependencies = [ "encoding_rs", "serde", @@ -3624,17 +3619,17 @@ dependencies = [ "base64 0.22.1", "gethostname", "md5", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pki-types", "smtp-proto", "tokio", "tokio-rustls 0.26.0", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", ] [[package]] name = "mail-server" -version = "0.9.4" +version = "0.10.0" dependencies = [ "common", "directory", @@ -3653,7 +3648,7 @@ dependencies = [ [[package]] name = "managesieve" -version = "0.9.4" +version = "0.10.0" dependencies = [ "ahash 0.8.11", "bincode", @@ -3667,7 +3662,7 @@ dependencies = [ "mail-send", "md5", "parking_lot", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pemfile 2.1.3", "sieve-rs", "store", @@ -3788,15 +3783,6 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - -[[package]] -name = "miniz_oxide" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" @@ -3880,7 +3866,7 @@ dependencies = [ "twox-hash", "url", "webpki", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", ] [[package]] @@ -3952,7 +3938,7 @@ dependencies = [ [[package]] name = "nlp" -version = "0.9.4" +version = "0.10.0" dependencies = [ "ahash 0.8.11", "bincode", @@ -3962,12 +3948,12 @@ dependencies = [ "nohash", "parking_lot", "phf", + "psl", "rust-stemmers", "serde", "siphasher 1.0.1", "tinysegmenter", "tokio", - "utils", "whatlang", "xxhash-rust", ] @@ -4300,7 +4286,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -4503,7 +4489,7 @@ dependencies = [ [[package]] name = "pop3" -version = "0.9.4" +version = "0.10.0" dependencies = [ "common", "directory", @@ -4512,7 +4498,7 @@ dependencies = [ "jmap_proto", "mail-parser", "mail-send", - "rustls 0.23.12", + "rustls 0.23.13", "store", "tokio", "tokio-rustls 0.26.0", @@ -4546,9 +4532,9 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02048d9e032fb3cc3413bbf7b83a15d84a5d419778e2628751896d856498eee9" +checksum = "f66ea23a2d0e5734297357705193335e0a957696f34bed2f2faefacb2fec336f" dependencies = [ "bytes", "fallible-iterator 0.2.0", @@ -4718,6 +4704,21 @@ dependencies = [ ] [[package]] +name = "psl" +version = "2.1.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce9398ad066421139b2e3afe16ea46772ffda30bd9ba57554dc035df5e26edc8" +dependencies = [ + "psl-types", +] + +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] name = "ptr_meta" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4779,16 +4780,16 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.12", + "rustls 0.23.13", "socket2", "thiserror", "tokio", @@ -4797,15 +4798,15 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.12", + "rustls 0.23.13", "slab", "thiserror", "tinyvec", @@ -4814,15 +4815,15 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5011,7 +5012,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rand", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-native-certs 0.7.3", "rustls-pemfile 2.1.3", "rustls-pki-types", @@ -5022,23 +5023,14 @@ dependencies = [ "tokio-rustls 0.26.0", "tokio-util", "url", - "webpki-roots 0.26.5", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", + "webpki-roots 0.26.6", ] [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags 2.6.0", ] @@ -5152,7 +5144,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper-rustls 0.27.3", "hyper-util", "ipnet", "js-sys", @@ -5163,7 +5155,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", @@ -5177,7 +5169,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", "windows-registry", ] @@ -5480,9 +5472,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.35" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -5512,21 +5504,21 @@ dependencies = [ "log", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.7", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.7", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -5593,9 +5585,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.7" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -5640,20 +5632,20 @@ checksum = "ece8e78b2f38ec51c51f5d475df0a7187ba5111b2a28bdc761ee05b075d40a71" [[package]] name = "scc" -version = "2.1.16" +version = "2.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeb7ac86243095b70a7920639507b71d51a63390d1ba26c4f60a552fbb914a37" +checksum = "0c947adb109a8afce5fc9c7bf951f87f146e9147b3a6a58413105628fb1d1e66" dependencies = [ "sdd", ] [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5695,9 +5687,9 @@ dependencies = [ [[package]] name = "sdd" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0495e4577c672de8254beb68d01a9b62d0e8a13c099edecdbedccce3223cd29f" +checksum = "60a7b59a5d9b0099720b417b6325d91a52cbf5b3dcb5041d864be53eefa58abc" [[package]] name = "seahash" @@ -5821,9 +5813,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -5839,9 +5831,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -5850,9 +5842,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -6065,7 +6057,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smtp" -version = "0.9.4" +version = "0.10.0" dependencies = [ "ahash 0.8.11", "bincode", @@ -6091,7 +6083,7 @@ dependencies = [ "rayon", "regex", "reqwest 0.12.7", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", @@ -6105,7 +6097,7 @@ dependencies = [ "tokio-rustls 0.26.0", "trc", "utils", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", "x509-parser 0.16.0", ] @@ -6181,7 +6173,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stalwart-cli" -version = "0.9.4" +version = "0.10.0" dependencies = [ "clap", "console", @@ -6212,7 +6204,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "store" -version = "0.9.4" +version = "0.10.0" dependencies = [ "ahash 0.8.11", "arc-swap", @@ -6244,7 +6236,7 @@ dependencies = [ "rocksdb", "rusqlite", "rust-s3", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pki-types", "serde", "serde_json", @@ -6462,7 +6454,7 @@ dependencies = [ "rayon", "reqwest 0.12.7", "ring 0.17.8", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", @@ -6604,9 +6596,9 @@ dependencies = [ [[package]] name = "tokio-postgres" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03adcf0147e203b6032c0b2d30be1415ba03bc348901f3ff1cc0df6a733e60c3" +checksum = "3b5d3742945bc7d7f210693b0c58ae542c6fd47b17adbbda0885f3dcb34a6bdb" dependencies = [ "async-trait", "byteorder", @@ -6655,16 +6647,16 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -6684,7 +6676,7 @@ dependencies = [ "tokio", "tokio-rustls 0.25.0", "tungstenite 0.21.0", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", ] [[package]] @@ -6701,9 +6693,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -6720,9 +6712,9 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" dependencies = [ "indexmap 2.5.0", "toml_datetime", @@ -6839,7 +6831,7 @@ dependencies = [ [[package]] name = "trc" -version = "0.9.4" +version = "0.10.0" dependencies = [ "ahash 0.8.11", "base64 0.22.1", @@ -6970,15 +6962,15 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -6997,9 +6989,9 @@ checksum = "ad8d71f5726e5f285a935e9fe8edfd53f0491eb6e9a5774097fdabee7cd8c9cd" [[package]] name = "unicode-security" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee9e13753df674873f3c4693b240ae5c03245ddc157dfccf7c26db9329af3a11" +checksum = "2e4ddba1535dd35ed8b61c52166b7155d7f4e4b8847cec6f48e71dc66d8b5e50" dependencies = [ "unicode-normalization", "unicode-script", @@ -7013,9 +7005,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" @@ -7082,7 +7074,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "utils" -version = "0.9.4" +version = "0.10.0" dependencies = [ "ahash 0.8.11", "base64 0.22.1", @@ -7103,7 +7095,7 @@ dependencies = [ "regex", "reqwest 0.12.7", "ring 0.17.8", - "rustls 0.23.12", + "rustls 0.23.13", "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", @@ -7112,7 +7104,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.0", "trc", - "webpki-roots 0.26.5", + "webpki-roots 0.26.6", "x509-parser 0.16.0", ] @@ -7282,9 +7274,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.5" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -7313,11 +7305,11 @@ dependencies = [ [[package]] name = "whoami" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall", "wasite", "web-sys", ] @@ -7643,9 +7635,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a77ee7c0de333dcc6da69b177380a0b81e0dacfa4f7344c465a36871ee601" +checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" [[package]] name = "xxhash-rust" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 23269160..c599a0ec 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Stalwart Labs Ltd. <hello@stalw.art>"] license = "AGPL-3.0-only OR LicenseRef-SEL" repository = "https://github.com/stalwartlabs/cli" homepage = "https://github.com/stalwartlabs/cli" -version = "0.9.4" +version = "0.10.0" edition = "2021" readme = "README.md" resolver = "2" @@ -29,4 +29,4 @@ human-size = "0.4.2" futures = "0.3.28" pwhash = "1.0.0" rand = "0.8.5" -mail-auth = { version = "0.4" } +mail-auth = { version = "0.5" } diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 8da26622..3e94714e 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -88,7 +88,7 @@ async fn oauth(url: &str) -> Credentials { .danger_accept_invalid_certs(is_localhost(url)) .build() .unwrap_or_default() - .get(&format!("{}/.well-known/oauth-authorization-server", url)) + .get(format!("{}/.well-known/oauth-authorization-server", url)) .send() .await .unwrap_result("send OAuth GET request") diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 515991ce..253424eb 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "common" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" @@ -14,7 +14,7 @@ jmap_proto = { path = "../jmap-proto" } sieve-rs = { version = "0.5" } mail-parser = { version = "0.9", features = ["full_encoding", "ludicrous_mode"] } mail-builder = { version = "0.3", features = ["ludicrous_mode"] } -mail-auth = { version = "0.4" } +mail-auth = { version = "0.5" } mail-send = { version = "0.4", default-features = false, features = ["cram-md5", "ring", "tls12"] } smtp-proto = { version = "0.1", features = ["serde_support"] } dns-update = { version = "0.1" } @@ -58,6 +58,7 @@ hostname = "0.4.0" zip = "2.1" pwhash = "1.0.0" xxhash-rust = { version = "0.8.5", features = ["xxh3"] } +psl = "2" [target.'cfg(unix)'.dependencies] privdrop = "0.5.3" diff --git a/crates/common/src/config/mod.rs b/crates/common/src/config/mod.rs index 538e35f1..edd5ed29 100644 --- a/crates/common/src/config/mod.rs +++ b/crates/common/src/config/mod.rs @@ -175,6 +175,7 @@ impl Core { 32, ), permissions_version: Default::default(), + logos: Default::default(), }, storage: Storage { data, diff --git a/crates/common/src/config/smtp/resolver.rs b/crates/common/src/config/smtp/resolver.rs index f28f2a7c..ffe43328 100644 --- a/crates/common/src/config/smtp/resolver.rs +++ b/crates/common/src/config/smtp/resolver.rs @@ -22,10 +22,7 @@ use mail_auth::{ Resolver, }; use parking_lot::Mutex; -use utils::{ - config::{utils::ParseValue, Config}, - suffixlist::PublicSuffix, -}; +use utils::config::{utils::ParseValue, Config}; use crate::Core; @@ -33,7 +30,6 @@ pub struct Resolvers { pub dns: Resolver, pub dnssec: DnssecResolver, pub cache: DnsRecordCache, - pub psl: PublicSuffix, } #[derive(Clone)] @@ -237,7 +233,6 @@ impl Resolvers { .unwrap_or(1024), ), }, - psl: PublicSuffix::parse(config, "resolver.public-suffix").await, } } } @@ -356,7 +351,6 @@ impl Default for Resolvers { tlsa: LruCache::with_capacity(1024), mta_sts: LruCache::with_capacity(1024), }, - psl: PublicSuffix::default(), } } } @@ -402,7 +396,6 @@ impl Clone for Resolvers { dns: self.dns.clone(), dnssec: self.dnssec.clone(), cache: self.cache.clone(), - psl: self.psl.clone(), } } } diff --git a/crates/common/src/enterprise/config.rs b/crates/common/src/enterprise/config.rs index a822c792..b076ab65 100644 --- a/crates/common/src/enterprise/config.rs +++ b/crates/common/src/enterprise/config.rs @@ -117,6 +117,7 @@ impl Enterprise { .property_or_default::<Option<Duration>>("storage.undelete.retention", "false") .unwrap_or_default() .map(|retention| Undelete { retention }), + logo_url: config.value("enterprise.logo-url").map(|s| s.to_string()), trace_store, metrics_store, metrics_alerts: parse_metric_alerts(config), diff --git a/crates/common/src/enterprise/mod.rs b/crates/common/src/enterprise/mod.rs index 0f0ac995..e4a2230e 100644 --- a/crates/common/src/enterprise/mod.rs +++ b/crates/common/src/enterprise/mod.rs @@ -15,17 +15,22 @@ pub mod undelete; use std::time::Duration; +use directory::{ + backend::internal::{lookup::DirectoryStore, PrincipalField}, + QueryBy, Type, +}; use license::LicenseKey; use mail_parser::DateTime; use store::Store; -use trc::{EventType, MetricType}; +use trc::{AddContext, EventType, MetricType}; use utils::config::cron::SimpleCron; -use crate::{expr::Expression, Core}; +use crate::{expr::Expression, manager::webadmin::Resource, Core}; #[derive(Clone)] pub struct Enterprise { pub license: LicenseKey, + pub logo_url: Option<String>, pub undelete: Option<Undelete>, pub trace_store: Option<TraceStore>, pub metrics_store: Option<MetricStore>, @@ -114,4 +119,95 @@ impl Core { ); } } + + pub async fn logo_resource(&self, domain: &str) -> trc::Result<Option<Resource<Vec<u8>>>> { + if self.is_enterprise_edition() { + let domain = psl::domain_str(domain).unwrap_or(domain); + let logo = { self.security.logos.lock().get(domain).cloned() }; + + if let Some(logo) = logo { + Ok(logo) + } else { + // Try fetching the logo for the domain + let logo_url = if let Some(mut principal) = self + .storage + .data + .query(QueryBy::Name(domain), false) + .await + .caused_by(trc::location!())? + .filter(|p| p.typ() == Type::Domain) + { + if let Some(logo) = principal + .take_str(PrincipalField::Picture) + .filter(|l| l.starts_with("http")) + { + logo.into() + } else if let Some(tenant_id) = principal.get_int(PrincipalField::Tenant) { + if let Some(logo) = self + .storage + .data + .query(QueryBy::Id(tenant_id as u32), false) + .await + .caused_by(trc::location!())? + .and_then(|mut p| p.take_str(PrincipalField::Picture)) + .filter(|l| l.starts_with("http")) + { + logo.into() + } else { + self.default_logo_url() + } + } else { + self.default_logo_url() + } + } else { + self.default_logo_url() + }; + + let mut logo = None; + if let Some(logo_url) = logo_url { + let response = reqwest::get(&logo_url).await.map_err(|err| { + trc::ResourceEvent::DownloadExternal + .into_err() + .details("Failed to download logo") + .reason(err) + })?; + + let content_type = response + .headers() + .get(reqwest::header::CONTENT_TYPE) + .and_then(|ct| ct.to_str().ok()) + .unwrap_or("image/svg+xml") + .to_string(); + + let contents = response + .bytes() + .await + .map_err(|err| { + trc::ResourceEvent::DownloadExternal + .into_err() + .details("Failed to download logo") + .reason(err) + })? + .to_vec(); + + logo = Resource::new(content_type, contents).into(); + } + + self.security + .logos + .lock() + .insert(domain.to_string(), logo.clone()); + + Ok(logo) + } + } else { + Ok(None) + } + } + + fn default_logo_url(&self) -> Option<String> { + self.enterprise + .as_ref() + .and_then(|e| e.logo_url.as_ref().map(|l| l.to_string())) + } } diff --git a/crates/common/src/expr/tokenizer.rs b/crates/common/src/expr/tokenizer.rs index e3366c51..7e7a6e0a 100644 --- a/crates/common/src/expr/tokenizer.rs +++ b/crates/common/src/expr/tokenizer.rs @@ -91,14 +91,14 @@ impl<'x> Tokenizer<'x> { _ => { let (prev_token, ch) = if ch == b'(' && self.buf.eq(b"matches") { // Parse regular expressions - let stop_ch = self.find_char(&[b'\"', b'\''])?; + let stop_ch = self.find_char(b"\"'")?; let regex_str = self.parse_string(stop_ch)?; let regex = Regex::new(®ex_str).map_err(|e| { format!("Invalid regular expression {:?}: {}", regex_str, e) })?; self.has_alpha = false; self.buf.clear(); - self.find_char(&[b','])?; + self.find_char(b",")?; (Token::Regex(regex).into(), b'(') } else if !self.buf.is_empty() { self.is_start = false; diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index a5c6df41..d602a1ca 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -10,6 +10,7 @@ use std::{ sync::{atomic::AtomicU8, Arc}, }; +use ahash::AHashMap; use arc_swap::ArcSwap; use auth::{roles::RolePermissions, AccessToken}; use config::{ @@ -35,6 +36,8 @@ use listener::{ }; use mail_send::Credentials; +use manager::webadmin::Resource; +use parking_lot::Mutex; use sieve::Sieve; use store::{ write::{QueueClass, ValueClass}, @@ -58,6 +61,8 @@ pub mod manager; pub mod scripts; pub mod telemetry; +pub use psl; + pub static USER_AGENT: &str = concat!("Stalwart/", env!("CARGO_PKG_VERSION"),); pub static DAEMON_NAME: &str = concat!("Stalwart Mail Server v", env!("CARGO_PKG_VERSION"),); @@ -83,6 +88,7 @@ pub struct Core { //TODO: temporary hack until OIDC is implemented #[derive(Default)] pub struct Security { + pub logos: Mutex<AHashMap<String, Option<Resource<Vec<u8>>>>>, pub access_tokens: TtlDashMap<u32, Arc<AccessToken>>, pub permissions: ADashMap<u32, Arc<RolePermissions>>, pub permissions_version: AtomicU8, @@ -405,6 +411,7 @@ impl Clone for Security { self.permissions_version .load(std::sync::atomic::Ordering::Relaxed), ), + logos: Mutex::new(self.logos.lock().clone()), } } } diff --git a/crates/common/src/listener/acme/order.rs b/crates/common/src/listener/acme/order.rs index 83e8e7ac..983198ea 100644 --- a/crates/common/src/listener/acme/order.rs +++ b/crates/common/src/listener/acme/order.rs @@ -9,7 +9,6 @@ use rustls::sign::CertifiedKey; use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; use std::sync::Arc; use std::time::{Duration, Instant}; -use utils::suffixlist::DomainPart; use x509_parser::parse_x509_certificate; use crate::listener::acme::directory::Identifier; @@ -241,11 +240,10 @@ impl Core { let domain = domain.strip_prefix("*.").unwrap_or(&domain); let name = format!("_acme-challenge.{}", domain); let origin = origin - .clone() - .or_else(|| { - self.smtp.resolvers.psl.domain_part(domain, DomainPart::Sld) - }) - .unwrap_or_else(|| domain.to_string()); + .as_deref() + .or_else(|| psl::domain_str(domain)) + .unwrap_or(domain) + .to_string(); // First try deleting the record if let Err(err) = updater.delete(&name, &origin).await { diff --git a/crates/common/src/manager/webadmin.rs b/crates/common/src/manager/webadmin.rs index 3bad6b0e..cf52a266 100644 --- a/crates/common/src/manager/webadmin.rs +++ b/crates/common/src/manager/webadmin.rs @@ -5,6 +5,7 @@ */ use std::{ + borrow::Cow, io::{self, Cursor, Read}, path::PathBuf, }; @@ -22,12 +23,21 @@ pub struct WebAdminManager { routes: ArcSwap<AHashMap<String, Resource<PathBuf>>>, } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Resource<T> { - pub content_type: &'static str, + pub content_type: Cow<'static, str>, pub contents: T, } +impl<T> Resource<T> { + pub fn new(content_type: impl Into<Cow<'static, str>>, contents: T) -> Self { + Self { + content_type: content_type.into(), + contents, + } + } +} + impl WebAdminManager { pub fn new() -> Self { Self { @@ -42,7 +52,7 @@ impl WebAdminManager { tokio::fs::read(&resource.contents) .await .map(|contents| Resource { - content_type: resource.content_type, + content_type: resource.content_type.clone(), contents, }) .map_err(|err| { @@ -114,7 +124,8 @@ impl WebAdminManager { "svg" => "image/svg+xml", "ico" => "image/x-icon", _ => "application/octet-stream", - }, + } + .into(), contents: path, }; diff --git a/crates/common/src/scripts/functions/unicode.rs b/crates/common/src/scripts/functions/unicode.rs index d11d09f8..852e3074 100644 --- a/crates/common/src/scripts/functions/unicode.rs +++ b/crates/common/src/scripts/functions/unicode.rs @@ -9,10 +9,10 @@ use unicode_security::MixedScript; pub fn fn_is_ascii<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable { match &v[0] { - Variable::String(s) => s.chars().all(|c| c.is_ascii()), + Variable::String(s) => s.is_ascii(), Variable::Integer(_) | Variable::Float(_) => true, Variable::Array(a) => a.iter().all(|v| match v { - Variable::String(s) => s.chars().all(|c| c.is_ascii()), + Variable::String(s) => s.is_ascii(), _ => true, }), } diff --git a/crates/common/src/scripts/plugins/bayes.rs b/crates/common/src/scripts/plugins/bayes.rs index 67eefeb7..5250cac9 100644 --- a/crates/common/src/scripts/plugins/bayes.rs +++ b/crates/common/src/scripts/plugins/bayes.rs @@ -63,10 +63,7 @@ async fn train(ctx: PluginContext<'_>, is_train: bool) -> trc::Result<Variable> // Train the model let mut model = BayesModel::default(); model.train( - OsbTokenizer::new( - BayesTokenizer::new(text.as_ref(), &ctx.core.smtp.resolvers.psl), - 5, - ), + OsbTokenizer::new(BayesTokenizer::new(text.as_ref()), 5), is_spam, ); if model.weights.is_empty() { @@ -187,10 +184,7 @@ pub async fn exec_classify(ctx: PluginContext<'_>) -> trc::Result<Variable> { // Classify the text let mut tokens = Vec::new(); - for token in OsbTokenizer::<_, TokenHash>::new( - BayesTokenizer::new(text.as_ref(), &ctx.core.smtp.resolvers.psl), - 5, - ) { + for token in OsbTokenizer::<_, TokenHash>::new(BayesTokenizer::new(text.as_ref()), 5) { let weights = bayes_cache.get_or_update(token.inner, store).await?; tokens.push(OsbToken { inner: weights, diff --git a/crates/common/src/scripts/plugins/pyzor.rs b/crates/common/src/scripts/plugins/pyzor.rs index 5202a0de..f5642418 100644 --- a/crates/common/src/scripts/plugins/pyzor.rs +++ b/crates/common/src/scripts/plugins/pyzor.rs @@ -18,7 +18,6 @@ use mail_parser::{decoders::html::add_html_token, Message, PartType}; use nlp::tokenizers::types::{TokenType, TypesTokenizer}; use sha1::{Digest, Sha1}; use tokio::net::UdpSocket; -use utils::suffixlist::PublicSuffix; const MIN_LINE_LENGTH: usize = 8; const ATOMIC_NUM_LINES: usize = 4; @@ -47,9 +46,7 @@ pub async fn exec(ctx: PluginContext<'_>) -> trc::Result<Variable> { } // Hash message - let request = ctx - .message - .pyzor_check_message(&ctx.core.smtp.resolvers.psl); + let request = ctx.message.pyzor_check_message(); #[cfg(feature = "test_mode")] { @@ -161,15 +158,15 @@ async fn pyzor_send_message( } trait PyzorDigest<W: Write> { - fn pyzor_digest(&self, writer: W, psl: &PublicSuffix) -> W; + fn pyzor_digest(&self, writer: W) -> W; } pub trait PyzorCheck { - fn pyzor_check_message(&self, psl: &PublicSuffix) -> String; + fn pyzor_check_message(&self) -> String; } impl<'x, W: Write> PyzorDigest<W> for Message<'x> { - fn pyzor_digest(&self, writer: W, psl: &PublicSuffix) -> W { + fn pyzor_digest(&self, writer: W) -> W { let parts = self .parts .iter() @@ -180,33 +177,27 @@ impl<'x, W: Write> PyzorDigest<W> for Message<'x> { }) .collect::<Vec<Cow<str>>>(); - pyzor_digest(writer, parts.iter().flat_map(|text| text.lines()), psl) + pyzor_digest(writer, parts.iter().flat_map(|text| text.lines())) } } impl<'x> PyzorCheck for Message<'x> { - fn pyzor_check_message(&self, psl: &PublicSuffix) -> String { + fn pyzor_check_message(&self) -> String { let time = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .map_or(0, |d| d.as_secs()); pyzor_create_message( self, - psl, time, (time & 0xFFFF) as u16 ^ ((time >> 16) & 0xFFFF) as u16, ) } } -fn pyzor_create_message( - message: &Message<'_>, - psl: &PublicSuffix, - time: u64, - thread: u16, -) -> String { +fn pyzor_create_message(message: &Message<'_>, time: u64, thread: u16) -> String { // Hash message - let hash = message.pyzor_digest(Sha1::new(), psl).finalize(); + let hash = message.pyzor_digest(Sha1::new()).finalize(); // Hash key let mut hash_key = Sha1::new(); hash_key.update("anonymous:".as_bytes()); @@ -223,13 +214,13 @@ fn pyzor_create_message( // Sign let mut sig = Sha1::new(); sig.update(msg_hash); - sig.update(&format!(":{time}:{hash_key:x}")); + sig.update(format!(":{time}:{hash_key:x}")); let sig = sig.finalize(); format!("{message}\nSig: {sig:x}\n") } -fn pyzor_digest<'x, I, W>(mut writer: W, lines: I, psl: &PublicSuffix) -> W +fn pyzor_digest<'x, I, W>(mut writer: W, lines: I) -> W where I: Iterator<Item = &'x str>, W: Write, @@ -254,7 +245,7 @@ where } }; - for token in TypesTokenizer::new(line, psl) { + for token in TypesTokenizer::new(line) { match token.word { TokenType::Alphabetic(_) | TokenType::Alphanumeric(_) @@ -448,7 +439,6 @@ mod test { use mail_parser::MessageParser; use sha1::Digest; use sha1::Sha1; - use utils::suffixlist::PublicSuffix; use super::pyzor_create_message; use super::pyzor_send_message; @@ -485,11 +475,8 @@ mod test { #[test] fn message_pyzor() { - let mut psl = PublicSuffix::default(); - psl.suffixes.insert("com".to_string()); let message = pyzor_create_message( &MessageParser::new().parse(HTML_TEXT_STYLE_SCRIPT).unwrap(), - &psl, 1697468672, 49005, ); @@ -510,9 +497,6 @@ mod test { #[test] fn digest_pyzor() { - let mut psl = PublicSuffix::default(); - psl.suffixes.insert("com".to_string()); - // HTML stripping assert_eq!(html_to_text(HTML_RAW), HTML_RAW_STRIPED); @@ -531,7 +515,6 @@ mod test { String::from_utf8(pyzor_digest( Vec::new(), format!("Test {strip_me} Test2").lines(), - &psl )) .unwrap(), "TestTest2" @@ -543,7 +526,6 @@ mod test { String::from_utf8(pyzor_digest( Vec::new(), concat!("This line is included\n", "not this\n", "This also").lines(), - &psl )) .unwrap(), "ThislineisincludedThisalso" @@ -554,7 +536,6 @@ mod test { String::from_utf8(pyzor_digest( Vec::new(), "All this message\nShould be included\nIn the digest".lines(), - &psl )) .unwrap(), "AllthismessageShouldbeincludedInthedigest" @@ -570,7 +551,7 @@ mod test { expected += format!("Line{i}testtesttest").as_str(); } assert_eq!( - String::from_utf8(pyzor_digest(Vec::new(), text.lines(), &psl)).unwrap(), + String::from_utf8(pyzor_digest(Vec::new(), text.lines(),)).unwrap(), expected ); @@ -602,7 +583,7 @@ mod test { MessageParser::new() .parse(input) .unwrap() - .pyzor_digest(Vec::new(), &psl) + .pyzor_digest(Vec::new(),) ) .unwrap(), expected, @@ -617,7 +598,7 @@ mod test { MessageParser::new() .parse(HTML_TEXT_STYLE_SCRIPT) .unwrap() - .pyzor_digest(Sha1::new(), &psl) + .pyzor_digest(Sha1::new(),) .finalize() ), "b2c27325a034c581df0c9ef37e4a0d63208a3e7e", diff --git a/crates/common/src/scripts/plugins/text.rs b/crates/common/src/scripts/plugins/text.rs index b4ad9761..922c89b6 100644 --- a/crates/common/src/scripts/plugins/text.rs +++ b/crates/common/src/scripts/plugins/text.rs @@ -6,7 +6,6 @@ use nlp::tokenizers::types::{TokenType, TypesTokenizer}; use sieve::{runtime::Variable, FunctionMap}; -use utils::suffixlist::DomainPart; use crate::scripts::functions::{html::html_to_tokens, text::tokenize_words, ApplyString}; @@ -33,7 +32,7 @@ pub fn exec_tokenize(ctx: PluginContext<'_>) -> trc::Result<Variable> { Ok(match v.remove(0) { v @ (Variable::String(_) | Variable::Array(_)) => { - TypesTokenizer::new(v.to_string().as_ref(), &ctx.core.smtp.resolvers.psl) + TypesTokenizer::new(v.to_string().as_ref()) .tokenize_numbers(false) .tokenize_urls(urls) .tokenize_urls_without_scheme(urls_without_scheme) @@ -53,6 +52,12 @@ pub fn exec_tokenize(ctx: PluginContext<'_>) -> trc::Result<Variable> { }) } +enum DomainPart { + Sld, + Tld, + Host, +} + pub fn exec_domain_part(ctx: PluginContext<'_>) -> trc::Result<Variable> { let v = ctx.arguments; let part = match v[1].to_string().as_ref() { @@ -63,12 +68,12 @@ pub fn exec_domain_part(ctx: PluginContext<'_>) -> trc::Result<Variable> { }; Ok(v[0].transform(|domain| { - ctx.core - .smtp - .resolvers - .psl - .domain_part(domain, part) - .map(Variable::from) - .unwrap_or_default() + match part { + DomainPart::Sld => psl::domain_str(domain), + DomainPart::Tld => domain.rsplit_once('.').map(|(_, tld)| tld), + DomainPart::Host => domain.split_once('.').map(|(host, _)| host), + } + .map(Variable::from) + .unwrap_or_default() })) } diff --git a/crates/directory/Cargo.toml b/crates/directory/Cargo.toml index ac23f369..222114ee 100644 --- a/crates/directory/Cargo.toml +++ b/crates/directory/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "directory" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" diff --git a/crates/directory/src/backend/internal/manage.rs b/crates/directory/src/backend/internal/manage.rs index 89d4c0f8..abc97fa9 100644 --- a/crates/directory/src/backend/internal/manage.rs +++ b/crates/directory/src/backend/internal/manage.rs @@ -405,7 +405,7 @@ impl ManageDirectory for Store { principal_id: MaybeDynamicId::Static(member.id), member_of: MaybeDynamicId::Dynamic(0), }), - vec![member.typ as u8], + vec![principal.typ as u8], ); batch.set( ValueClass::Directory(DirectoryClass::Members { @@ -460,7 +460,15 @@ impl ManageDirectory for Store { .list_principals( None, principal.id().into(), - &[], + &[ + Type::Individual, + Type::Group, + Type::Role, + Type::List, + Type::Resource, + Type::Other, + Type::Location, + ], &[PrincipalField::Name], 0, 0, @@ -742,25 +750,25 @@ impl ManageDirectory for Store { )); } - match principal.inner.tenant() { - Some(old_tenant_id) if old_tenant_id != tenant_info.id => { - // Update quota - if let Some(used_quota) = used_quota { - batch - .add(DirectoryClass::UsedQuota(old_tenant_id), -used_quota) - .add(DirectoryClass::UsedQuota(tenant_info.id), used_quota); - } + if principal.inner.tenant() == Some(tenant_info.id) { + continue; + } - principal.inner.set(PrincipalField::Tenant, tenant_info.id); - pinfo_name = PrincipalInfo::new( - principal_id, - principal.inner.typ, - tenant_info.id.into(), - ) - .serialize(); + // Update quota + if let Some(used_quota) = used_quota { + if let Some(old_tenant_id) = principal.inner.tenant() { + batch.add(DirectoryClass::UsedQuota(old_tenant_id), -used_quota); } - _ => continue, + batch.add(DirectoryClass::UsedQuota(tenant_info.id), used_quota); } + + principal.inner.set(PrincipalField::Tenant, tenant_info.id); + pinfo_name = PrincipalInfo::new( + principal_id, + principal.inner.typ, + tenant_info.id.into(), + ) + .serialize(); } else if let Some(tenant_id) = principal.inner.tenant() { // Update quota if let Some(used_quota) = used_quota { @@ -826,15 +834,13 @@ impl ManageDirectory for Store { } ( PrincipalAction::Set, - PrincipalField::Description, - PrincipalValue::String(description), + PrincipalField::Description | PrincipalField::Picture, + PrincipalValue::String(value), ) => { - if !description.is_empty() { - principal - .inner - .set(PrincipalField::Description, description); + if !value.is_empty() { + principal.inner.set(change.field, value); } else { - principal.inner.remove(PrincipalField::Description); + principal.inner.remove(change.field); } } (PrincipalAction::Set, PrincipalField::Quota, PrincipalValue::Integer(quota)) @@ -1118,7 +1124,7 @@ impl ManageDirectory for Store { principal_id: MaybeDynamicId::Static(member_info.id), member_of: MaybeDynamicId::Static(principal_id), }), - vec![member_info.typ as u8], + vec![principal.inner.typ as u8], ); batch.set( ValueClass::Directory(DirectoryClass::Members { @@ -1180,7 +1186,7 @@ impl ManageDirectory for Store { principal_id: MaybeDynamicId::Static(member_info.id), member_of: MaybeDynamicId::Static(principal_id), }), - vec![member_info.typ as u8], + vec![principal.inner.typ as u8], ); batch.set( ValueClass::Directory(DirectoryClass::Members { @@ -1561,25 +1567,24 @@ impl ManageDirectory for Store { let to_key = ValueKey::from(ValueClass::Directory(DirectoryClass::EmailToId( vec![u8::MAX; 10], ))); - let mut results = Vec::new(); let domain_name = principal.name(); + let mut total: u64 = 0; self.iterate( IterateParams::new(from_key, to_key).no_values(), |key, _| { - let email = std::str::from_utf8(key.get(1..).unwrap_or_default()) - .unwrap_or_default(); - if email + if std::str::from_utf8(key.get(1..).unwrap_or_default()) + .unwrap_or_default() .rsplit_once('@') .map_or(false, |(_, domain)| domain == domain_name) { - results.push(email.to_string()); + total += 1; } Ok(true) }, ) .await .caused_by(trc::location!())?; - principal.set(PrincipalField::Members, results); + principal.set(PrincipalField::Members, total); } Type::Tenant => { let from_key = @@ -1587,25 +1592,23 @@ impl ManageDirectory for Store { let to_key = ValueKey::from(ValueClass::Directory(DirectoryClass::NameToId( vec![u8::MAX; 10], ))); - let mut results = Vec::new(); - self.iterate(IterateParams::new(from_key, to_key), |key, value| { + let mut total: u64 = 0; + + self.iterate(IterateParams::new(from_key, to_key), |_, value| { let pinfo = PrincipalInfo::deserialize(value).caused_by(trc::location!())?; if pinfo.typ == Type::Individual && pinfo.has_tenant_access(Some(principal.id)) { - results.push( - std::str::from_utf8(key.get(1..).unwrap_or_default()) - .unwrap_or_default() - .to_string(), - ); + total += 1; } Ok(true) }) .await .caused_by(trc::location!())?; - principal.set(PrincipalField::Members, results); + + principal.set(PrincipalField::Members, total); } _ => {} } diff --git a/crates/directory/src/backend/internal/mod.rs b/crates/directory/src/backend/internal/mod.rs index b8ad3b7b..cc59fcb9 100644 --- a/crates/directory/src/backend/internal/mod.rs +++ b/crates/directory/src/backend/internal/mod.rs @@ -95,6 +95,7 @@ impl PrincipalInfo { pub fn has_tenant_access(&self, tenant_id: Option<u32>) -> bool { tenant_id.map_or(true, |tenant_id| { self.tenant.map_or(false, |t| tenant_id == t) + || (self.typ == Type::Tenant && self.id == tenant_id) }) } } diff --git a/crates/imap/Cargo.toml b/crates/imap/Cargo.toml index a408942b..a77cb2fb 100644 --- a/crates/imap/Cargo.toml +++ b/crates/imap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "imap" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" diff --git a/crates/jmap/Cargo.toml b/crates/jmap/Cargo.toml index e796e10a..5fcd188b 100644 --- a/crates/jmap/Cargo.toml +++ b/crates/jmap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jmap" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" @@ -17,7 +17,7 @@ smtp-proto = { version = "0.1" } mail-parser = { version = "0.9", features = ["full_encoding", "serde_support", "ludicrous_mode"] } mail-builder = { version = "0.3", features = ["ludicrous_mode"] } mail-send = { version = "0.4", default-features = false, features = ["cram-md5", "ring", "tls12"] } -mail-auth = { version = "0.4", features = ["generate"] } +mail-auth = { version = "0.5", features = ["generate"] } sieve-rs = { version = "0.5" } serde = { version = "1.0", features = ["derive"]} serde_json = "1.0" diff --git a/crates/jmap/src/api/autoconfig.rs b/crates/jmap/src/api/autoconfig.rs index 11d29547..296dd5aa 100644 --- a/crates/jmap/src/api/autoconfig.rs +++ b/crates/jmap/src/api/autoconfig.rs @@ -67,11 +67,10 @@ impl JMAP { ); config.push_str("</clientConfig>\n"); - Ok(Resource { - content_type: "application/xml; charset=utf-8", - contents: config.into_bytes(), - } - .into_http_response()) + Ok( + Resource::new("application/xml; charset=utf-8", config.into_bytes()) + .into_http_response(), + ) } pub async fn handle_autodiscover_request( @@ -147,11 +146,10 @@ impl JMAP { let _ = writeln!(&mut config, "\t</Response>"); let _ = writeln!(&mut config, "</Autodiscover>"); - Ok(Resource { - content_type: "application/xml; charset=utf-8", - contents: config.into_bytes(), - } - .into_http_response()) + Ok( + Resource::new("application/xml; charset=utf-8", config.into_bytes()) + .into_http_response(), + ) } async fn autoconfig_parameters<'x>( diff --git a/crates/jmap/src/api/http.rs b/crates/jmap/src/api/http.rs index 16ad3c39..86943ffe 100644 --- a/crates/jmap/src/api/http.rs +++ b/crates/jmap/src/api/http.rs @@ -223,22 +223,16 @@ impl JMAP { .key_get::<String>(format!("acme:{token}").into_bytes()) .await? { - Some(proof) => Ok(Resource { - content_type: "text/plain", - contents: proof.into_bytes(), - } - .into_http_response()), + Some(proof) => Ok(Resource::new("text/plain", proof.into_bytes()) + .into_http_response()), None => Err(trc::ResourceEvent::NotFound.into_err()), }; } } ("mta-sts.txt", &Method::GET) => { if let Some(policy) = self.core.build_mta_sts_policy() { - return Ok(Resource { - content_type: "text/plain", - contents: policy.to_string().into_bytes(), - } - .into_http_response()); + return Ok(Resource::new("text/plain", policy.to_string().into_bytes()) + .into_http_response()); } else { return Err(trc::ResourceEvent::NotFound.into_err()); } @@ -357,11 +351,10 @@ impl JMAP { } } "robots.txt" => { - return Ok(Resource { - content_type: "text/plain", - contents: b"User-agent: *\nDisallow: /\n".to_vec(), - } - .into_http_response()); + return Ok( + Resource::new("text/plain", b"User-agent: *\nDisallow: /\n".to_vec()) + .into_http_response(), + ); } "healthz" => match path.next().unwrap_or_default() { "live" => { @@ -394,10 +387,10 @@ impl JMAP { } } - return Ok(Resource { - content_type: "text/plain; version=0.0.4", - contents: self.core.export_prometheus_metrics().await?.into_bytes(), - } + return Ok(Resource::new( + "text/plain; version=0.0.4", + self.core.export_prometheus_metrics().await?.into_bytes(), + ) .into_http_response()); } } @@ -406,6 +399,42 @@ impl JMAP { } _ => (), }, + #[cfg(feature = "enterprise")] + "logo.svg" if self.core.is_enterprise_edition() => { + // SPDX-SnippetBegin + // SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art> + // SPDX-License-Identifier: LicenseRef-SEL + + match self + .core + .logo_resource( + req.headers() + .get(header::HOST) + .and_then(|h| h.to_str().ok()) + .map(|h| h.rsplit_once(':').map_or(h, |(h, _)| h)) + .unwrap_or_default(), + ) + .await + { + Ok(Some(resource)) => { + return Ok(resource.into_http_response()); + } + Ok(None) => (), + Err(err) => { + trc::error!(err.span_id(session.session_id)); + } + } + + let resource = self.inner.webadmin.get("logo.svg").await?; + + return if !resource.is_empty() { + Ok(resource.into_http_response()) + } else { + Err(trc::ResourceEvent::NotFound.into_err()) + }; + + // SPDX-SnippetEnd + } _ => { let path = req.uri().path(); let resource = self @@ -895,7 +924,7 @@ impl ToRequestError for trc::Error { }, trc::EventType::Auth(cause) => match cause { trc::AuthEvent::MissingTotp => { - RequestError::blank(403, "TOTP code required", cause.message()) + RequestError::blank(402, "TOTP code required", cause.message()) } trc::AuthEvent::TooManyAttempts => RequestError::too_many_auth_attempts(), _ => RequestError::unauthorized(), diff --git a/crates/jmap/src/api/management/dns.rs b/crates/jmap/src/api/management/dns.rs index d2577007..65e56bb1 100644 --- a/crates/jmap/src/api/management/dns.rs +++ b/crates/jmap/src/api/management/dns.rs @@ -115,10 +115,10 @@ impl JMAP { } for signature_id in signature_ids { if let (Some(algo), Some(pk), Some(selector)) = ( - keys.value(&format!("{signature_id}.algorithm")) + keys.value(format!("{signature_id}.algorithm")) .and_then(|algo| algo.parse::<Algorithm>().ok()), - keys.value(&format!("{signature_id}.private-key")), - keys.value(&format!("{signature_id}.selector")), + keys.value(format!("{signature_id}.private-key")), + keys.value(format!("{signature_id}.selector")), ) { match obtain_dkim_public_key(algo, pk) { Ok(public) => { diff --git a/crates/jmap/src/api/management/principal.rs b/crates/jmap/src/api/management/principal.rs index f3944a81..f661e970 100644 --- a/crates/jmap/src/api/management/principal.rs +++ b/crates/jmap/src/api/management/principal.rs @@ -108,6 +108,7 @@ impl JMAP { let filter = params.get("filter"); let page: usize = params.parse("page").unwrap_or(0); let limit: usize = params.parse("limit").unwrap_or(0); + let count = params.get("count").is_some(); // Parse types let mut types = Vec::new(); @@ -181,13 +182,17 @@ impl JMAP { return Err(manage::enterprise()); } - let principals = self + let mut principals = self .core .storage .data .list_principals(filter, tenant, &types, &fields, page, limit) .await?; + if count { + principals.items.clear(); + } + Ok(JsonResponse::new(json!({ "data": principals, })) @@ -356,9 +361,6 @@ impl JMAP { } else { expire_token = true; } - if change.field == PrincipalField::Roles { - needs_assert = true; - } } } } diff --git a/crates/jmap/src/api/management/stores.rs b/crates/jmap/src/api/management/stores.rs index f4c95ada..78148a93 100644 --- a/crates/jmap/src/api/management/stores.rs +++ b/crates/jmap/src/api/management/stores.rs @@ -69,11 +69,7 @@ impl JMAP { .to_vec() }; - Ok(Resource { - content_type: "application/octet-stream", - contents, - } - .into_http_response()) + Ok(Resource::new("application/octet-stream", contents).into_http_response()) } (Some("purge"), Some("blob"), _, &Method::GET) => { // Validate the access token diff --git a/crates/jmap/src/vacation/set.rs b/crates/jmap/src/vacation/set.rs index b0143c16..604e24f0 100644 --- a/crates/jmap/src/vacation/set.rs +++ b/crates/jmap/src/vacation/set.rs @@ -200,10 +200,9 @@ impl JMAP { Property::Value, ) .await? - .map(|value| { + .inspect(|value| { was_active = value.inner.properties.get(&Property::IsActive) == Some(&Value::Bool(true)); - value }) .ok_or_else(|| { trc::StoreEvent::NotFound diff --git a/crates/main/Cargo.toml b/crates/main/Cargo.toml index d9f93111..a2473ec9 100644 --- a/crates/main/Cargo.toml +++ b/crates/main/Cargo.toml @@ -7,7 +7,7 @@ homepage = "https://stalw.art" keywords = ["imap", "jmap", "smtp", "email", "mail", "server"] categories = ["email"] license = "AGPL-3.0-only OR LicenseRef-SEL" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" diff --git a/crates/managesieve/Cargo.toml b/crates/managesieve/Cargo.toml index 5795fa85..88100fc8 100644 --- a/crates/managesieve/Cargo.toml +++ b/crates/managesieve/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "managesieve" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" diff --git a/crates/nlp/Cargo.toml b/crates/nlp/Cargo.toml index 5541f535..07a39939 100644 --- a/crates/nlp/Cargo.toml +++ b/crates/nlp/Cargo.toml @@ -1,11 +1,10 @@ [package] name = "nlp" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" [dependencies] -utils = { path = "../utils" } xxhash-rust = { version = "0.8.5", features = ["xxh3"] } farmhash = "1.1.5" siphasher = "1.0" @@ -20,6 +19,7 @@ jieba-rs = "0.7" # Chinese stemmer phf = { version = "0.11", features = ["macros"] } lru-cache = "0.1.2" parking_lot = "0.12.1" +psl = "2" [features] test_mode = [] diff --git a/crates/nlp/src/bayes/tokenize.rs b/crates/nlp/src/bayes/tokenize.rs index 2f3ae323..fd59ac90 100644 --- a/crates/nlp/src/bayes/tokenize.rs +++ b/crates/nlp/src/bayes/tokenize.rs @@ -6,8 +6,6 @@ use std::borrow::Cow; -use utils::suffixlist::PublicSuffix; - use crate::{ language::{ detect::{LanguageDetector, MIN_LANGUAGE_SCORE}, @@ -21,9 +19,9 @@ use crate::{ }, }; -pub struct BayesTokenizer<'x, 'y> { +pub struct BayesTokenizer<'x> { text: &'x str, - tokenizer: TypesTokenizer<'x, 'y>, + tokenizer: TypesTokenizer<'x>, stemmer: Stemmer, stop_words: Option<&'static phf::Set<&'static str>>, tokens: Vec<Cow<'x, str>>, @@ -36,8 +34,8 @@ enum Stemmer { None, } -impl<'x, 'y> BayesTokenizer<'x, 'y> { - pub fn new(text: &'x str, suffixes: &'y PublicSuffix) -> Self { +impl<'x> BayesTokenizer<'x> { + pub fn new(text: &'x str) -> Self { // Detect language let (mut language, score) = LanguageDetector::detect_single(text).unwrap_or((Language::English, 1.0)); @@ -47,7 +45,7 @@ impl<'x, 'y> BayesTokenizer<'x, 'y> { Self { text, - tokenizer: TypesTokenizer::new(text, suffixes), + tokenizer: TypesTokenizer::new(text), stemmer: match language { Language::Mandarin => Stemmer::Mandarin, Language::Japanese => Stemmer::Japanese, @@ -61,7 +59,7 @@ impl<'x, 'y> BayesTokenizer<'x, 'y> { } } -impl<'x, 'y> Iterator for BayesTokenizer<'x, 'y> { +impl<'x> Iterator for BayesTokenizer<'x> { type Item = Cow<'x, str>; fn next(&mut self) -> Option<Self::Item> { @@ -1149,8 +1147,6 @@ pub static SYMBOLS: phf::Set<char> = phf::phf_set! { mod tests { use std::borrow::Cow; - use utils::suffixlist::PublicSuffix; - use crate::bayes::tokenize::BayesTokenizer; #[test] @@ -1236,10 +1232,8 @@ mod tests { ("시작이 반이다", vec!["시작이", "반이다"]), ]; - let suffixes = PublicSuffix::default(); - for (input, expect) in inputs.iter() { - let input = BayesTokenizer::new(input, &suffixes).collect::<Vec<_>>(); + let input = BayesTokenizer::new(input).collect::<Vec<_>>(); let expect = expect.iter().copied().map(Cow::from).collect::<Vec<_>>(); assert_eq!(input, expect,); diff --git a/crates/nlp/src/lib.rs b/crates/nlp/src/lib.rs index a5c174e8..68a40005 100644 --- a/crates/nlp/src/lib.rs +++ b/crates/nlp/src/lib.rs @@ -6,8 +6,6 @@ pub mod tokenizers; mod test { use std::fs; - use utils::suffixlist::PublicSuffix; - use crate::{ bayes::{tokenize::BayesTokenizer, BayesClassifier, BayesModel}, tokenizers::osb::{OsbToken, OsbTokenizer}, @@ -19,16 +17,12 @@ mod test { let db = fs::read_to_string("/Users/me/code/mail-server/_ignore/spam_or_not_spam.csv").unwrap(); let mut bayes = BayesModel::default(); - let suffixes = PublicSuffix::default(); for line in db.lines() { let (text, is_spam) = line.rsplit_once(',').unwrap(); let is_spam = is_spam == "1"; - bayes.train( - OsbTokenizer::new(BayesTokenizer::new(text, &suffixes), 5), - is_spam, - ); + bayes.train(OsbTokenizer::new(BayesTokenizer::new(text), 5), is_spam); } println!("Ham: {} Spam: {}", bayes.ham_learns, bayes.spam_learns,); fs::write( @@ -46,7 +40,6 @@ mod test { ) .unwrap(); let bayes = BayesClassifier::new(); - let suffixes = PublicSuffix::default(); for text in [ "i am attaching to this email a presentation to integrate the spreadsheet into our server", @@ -58,7 +51,7 @@ mod test { "{:?} -> {}", text, bayes - .classify(OsbTokenizer::new(BayesTokenizer::new(text, &suffixes), 5).filter_map(|x| model.weights.get(&x.inner).map(|w| { + .classify(OsbTokenizer::new(BayesTokenizer::new(text), 5).filter_map(|x| model.weights.get(&x.inner).map(|w| { OsbToken { idx: x.idx, inner: *w, diff --git a/crates/nlp/src/tokenizers/mod.rs b/crates/nlp/src/tokenizers/mod.rs index bbd5f050..eb449b4c 100644 --- a/crates/nlp/src/tokenizers/mod.rs +++ b/crates/nlp/src/tokenizers/mod.rs @@ -37,7 +37,7 @@ impl<'x> InnerToken<'x> for Cow<'x, str> { } fn is_alphabetic_8bit(&self) -> bool { - !self.chars().all(|c| c.is_ascii()) + !self.is_ascii() } fn unwrap_alphabetic(self) -> Cow<'x, str> { diff --git a/crates/nlp/src/tokenizers/types.rs b/crates/nlp/src/tokenizers/types.rs index f69fe0ab..cb12035e 100644 --- a/crates/nlp/src/tokenizers/types.rs +++ b/crates/nlp/src/tokenizers/types.rs @@ -6,13 +6,10 @@ use std::str::CharIndices; -use utils::suffixlist::PublicSuffix; - use super::Token; -pub struct TypesTokenizer<'x, 'y> { +pub struct TypesTokenizer<'x> { text: &'x str, - suffixes: &'y PublicSuffix, iter: CharIndices<'x>, tokens: Vec<Token<TokenType<&'x str>>>, peek_pos: usize, @@ -45,7 +42,7 @@ pub enum TokenType<T> { impl Copy for Token<TokenType<&'_ str>> {} -impl<'x, 'y> Iterator for TypesTokenizer<'x, 'y> { +impl<'x> Iterator for TypesTokenizer<'x> { type Item = Token<TokenType<&'x str>>; fn next(&mut self) -> Option<Self::Item> { @@ -58,7 +55,7 @@ impl<'x, 'y> Iterator for TypesTokenizer<'x, 'y> { && matches!( token.word, TokenType::Alphabetic(t) | TokenType::Alphanumeric(t) - if t.len() <= 8 && t.chars().all(|c| c.is_ascii())) + if t.len() <= 8 && t.is_ascii()) && self.try_skip_url_scheme() { if let Some(url) = self.try_parse_url(token.into()) { @@ -111,15 +108,14 @@ impl<'x, 'y> Iterator for TypesTokenizer<'x, 'y> { } } -impl<'x, 'y> TypesTokenizer<'x, 'y> { - pub fn new(text: &'x str, suffixes: &'y PublicSuffix) -> Self { +impl<'x> TypesTokenizer<'x> { + pub fn new(text: &'x str) -> Self { Self { text, iter: text.char_indices(), tokens: Vec::new(), eof: false, peek_pos: 0, - suffixes, last_ch_is_space: false, last_token_is_dot: false, tokenize_urls: true, @@ -327,8 +323,13 @@ impl<'x, 'y> TypesTokenizer<'x, 'y> { while let Some(token) = self.peek() { match token.word { TokenType::Alphabetic(text) | TokenType::Alphanumeric(text) => { - last_label_is_tld = - text.len() >= 2 && self.suffixes.contains(&text.to_ascii_lowercase()); + last_label_is_tld = text.len() >= 2 + && psl::Psl::find( + &psl::List, + [text.to_ascii_lowercase().as_bytes()].into_iter(), + ) + .typ + .is_some(); text_count += 1; } TokenType::Integer(text) => { @@ -552,8 +553,13 @@ impl<'x, 'y> TypesTokenizer<'x, 'y> { .map(|(from, to)| (from, to, true)); } TokenType::Alphabetic(text) | TokenType::Alphanumeric(text) if text.len() <= 63 => { - last_label_is_tld = - text.len() >= 2 && self.suffixes.contains(&text.to_ascii_lowercase()); + last_label_is_tld = text.len() >= 2 + && psl::Psl::find( + &psl::List, + [text.to_ascii_lowercase().as_bytes()].into_iter(), + ) + .typ + .is_some(); has_alpha = true; last_ch = 0; } @@ -691,7 +697,7 @@ impl<'x, 'y> TypesTokenizer<'x, 'y> { (TokenType::Punctuation('/'), State::Slash2) => return true, (TokenType::Punctuation('+'), State::None) => State::PlusAlpha, (TokenType::Alphabetic(t) | TokenType::Alphanumeric(t), State::PlusAlpha) - if t.chars().all(|c| c.is_ascii()) => + if t.is_ascii() => { State::Colon } @@ -748,17 +754,10 @@ impl<T> TokenType<T> { #[cfg(test)] mod test { - use utils::suffixlist::PublicSuffix; - use super::{TokenType, TypesTokenizer}; #[test] fn type_tokenizer() { - let mut suffixes = PublicSuffix::default(); - suffixes.suffixes.insert("com".to_string()); - suffixes.suffixes.insert("co".to_string()); - suffixes.suffixes.insert("org".to_string()); - // Credits: test suite from linkify crate for (text, expected) in [ ("", vec![]), @@ -2862,7 +2861,7 @@ mod test { ], ), ] { - let result = TypesTokenizer::new(text, &suffixes) + let result = TypesTokenizer::new(text) .map(|t| t.word) .collect::<Vec<_>>(); diff --git a/crates/pop3/Cargo.toml b/crates/pop3/Cargo.toml index 36bdfa3d..e9fb62bf 100644 --- a/crates/pop3/Cargo.toml +++ b/crates/pop3/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pop3" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" diff --git a/crates/smtp/Cargo.toml b/crates/smtp/Cargo.toml index 77dfbeec..355a22d2 100644 --- a/crates/smtp/Cargo.toml +++ b/crates/smtp/Cargo.toml @@ -7,7 +7,7 @@ homepage = "https://stalw.art/smtp" keywords = ["smtp", "email", "mail", "server"] categories = ["email"] license = "AGPL-3.0-only OR LicenseRef-SEL" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" @@ -18,7 +18,7 @@ nlp = { path = "../nlp" } directory = { path = "../directory" } common = { path = "../common" } trc = { path = "../trc" } -mail-auth = { version = "0.4" } +mail-auth = { version = "0.5" } mail-send = { version = "0.4", default-features = false, features = ["cram-md5", "ring", "tls12"] } mail-parser = { version = "0.9", features = ["full_encoding", "ludicrous_mode"] } mail-builder = { version = "0.3", features = ["ludicrous_mode"] } diff --git a/crates/smtp/src/inbound/data.rs b/crates/smtp/src/inbound/data.rs index 4f089bde..822fc734 100644 --- a/crates/smtp/src/inbound/data.rs +++ b/crates/smtp/src/inbound/data.rs @@ -14,6 +14,7 @@ use std::{ use common::{ config::smtp::{auth::VerifyStrategy, session::Stage}, listener::SessionStream, + psl, scripts::ScriptModification, }; use mail_auth::{ @@ -249,6 +250,7 @@ impl<T: SessionStream> Session<T> { &self.data.helo_domain }, spf_output, + |domain| psl::domain_str(domain).unwrap_or(domain), ) .await; diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index 1eef9a96..3572e774 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "store" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" diff --git a/crates/store/src/backend/mysql/main.rs b/crates/store/src/backend/mysql/main.rs index 2d9e7f0a..c28a271b 100644 --- a/crates/store/src/backend/mysql/main.rs +++ b/crates/store/src/backend/mysql/main.rs @@ -110,7 +110,7 @@ impl MysqlStore { SUBSPACE_TELEMETRY_INDEX, ] { let table = char::from(table); - conn.query_drop(&format!( + conn.query_drop(format!( "CREATE TABLE IF NOT EXISTS {table} ( k TINYBLOB, v MEDIUMBLOB NOT NULL, @@ -121,7 +121,7 @@ impl MysqlStore { .map_err(into_error)?; } - conn.query_drop(&format!( + conn.query_drop(format!( "CREATE TABLE IF NOT EXISTS {} ( k TINYBLOB, v LONGBLOB NOT NULL, @@ -139,7 +139,7 @@ impl MysqlStore { SUBSPACE_BITMAP_TEXT, ] { let table = char::from(table); - conn.query_drop(&format!( + conn.query_drop(format!( "CREATE TABLE IF NOT EXISTS {table} ( k BLOB, PRIMARY KEY (k(400)) @@ -150,7 +150,7 @@ impl MysqlStore { } for table in [SUBSPACE_COUNTER, SUBSPACE_QUOTA] { - conn.query_drop(&format!( + conn.query_drop(format!( "CREATE TABLE IF NOT EXISTS {} ( k TINYBLOB, v BIGINT NOT NULL DEFAULT 0, diff --git a/crates/store/src/backend/mysql/read.rs b/crates/store/src/backend/mysql/read.rs index 24a929f8..0b1f573d 100644 --- a/crates/store/src/backend/mysql/read.rs +++ b/crates/store/src/backend/mysql/read.rs @@ -22,7 +22,7 @@ impl MysqlStore { { let mut conn = self.conn_pool.get_conn().await.map_err(into_error)?; let s = conn - .prep(&format!( + .prep(format!( "SELECT v FROM {} WHERE k = ?", char::from(key.subspace()) )) @@ -54,7 +54,7 @@ impl MysqlStore { let mut bm = RoaringBitmap::new(); let s = conn - .prep(&format!("SELECT k FROM {table} WHERE k >= ? AND k <= ?")) + .prep(format!("SELECT k FROM {table} WHERE k >= ? AND k <= ?")) .await .map_err(into_error)?; let mut rows = conn @@ -147,7 +147,7 @@ impl MysqlStore { let key = key.serialize(0); let mut conn = self.conn_pool.get_conn().await.map_err(into_error)?; let s = conn - .prep(&format!("SELECT v FROM {table} WHERE k = ?")) + .prep(format!("SELECT v FROM {table} WHERE k = ?")) .await .map_err(into_error)?; match conn.exec_first::<i64, _, _>(&s, (key,)).await { diff --git a/crates/store/src/backend/mysql/write.rs b/crates/store/src/backend/mysql/write.rs index 7d570ae1..31c6e40f 100644 --- a/crates/store/src/backend/mysql/write.rs +++ b/crates/store/src/backend/mysql/write.rs @@ -108,10 +108,10 @@ impl MysqlStore { let exists = asserted_values.get(&key); let s = if let Some(exists) = exists { if *exists { - trx.prep(&format!("UPDATE {} SET v = :v WHERE k = :k", table)) + trx.prep(format!("UPDATE {} SET v = :v WHERE k = :k", table)) .await? } else { - trx.prep(&format!( + trx.prep(format!( "INSERT INTO {} (k, v) VALUES (:k, :v)", table )) @@ -120,7 +120,7 @@ impl MysqlStore { } else { trx .prep( - &format!("INSERT INTO {} (k, v) VALUES (:k, :v) ON DUPLICATE KEY UPDATE v = VALUES(v)", table), + format!("INSERT INTO {} (k, v) VALUES (:k, :v) ON DUPLICATE KEY UPDATE v = VALUES(v)", table), ) .await? }; @@ -149,7 +149,7 @@ impl MysqlStore { ValueOp::AtomicAdd(by) => { if *by >= 0 { let s = trx - .prep(&format!( + .prep(format!( concat!( "INSERT INTO {} (k, v) VALUES (?, ?) ", "ON DUPLICATE KEY UPDATE v = v + VALUES(v)" @@ -160,14 +160,14 @@ impl MysqlStore { trx.exec_drop(&s, (key, by)).await?; } else { let s = trx - .prep(&format!("UPDATE {table} SET v = v + ? WHERE k = ?")) + .prep(format!("UPDATE {table} SET v = v + ? WHERE k = ?")) .await?; trx.exec_drop(&s, (by, key)).await?; } } ValueOp::AddAndGet(by) => { let s = trx - .prep(&format!( + .prep(format!( concat!( "INSERT INTO {} (k, v) VALUES (:k, LAST_INSERT_ID(:v)) ", "ON DUPLICATE KEY UPDATE v = LAST_INSERT_ID(v + :v)" @@ -190,7 +190,7 @@ impl MysqlStore { } ValueOp::Clear => { let s = trx - .prep(&format!("DELETE FROM {} WHERE k = ?", table)) + .prep(format!("DELETE FROM {} WHERE k = ?", table)) .await?; trx.exec_drop(&s, (key,)).await?; } @@ -256,11 +256,11 @@ impl MysqlStore { if is_document_id { trx.prep("INSERT INTO b (k) VALUES (?)").await? } else { - trx.prep(&format!("INSERT IGNORE INTO {} (k) VALUES (?)", table)) + trx.prep(format!("INSERT IGNORE INTO {} (k) VALUES (?)", table)) .await? } } else { - trx.prep(&format!("DELETE FROM {} WHERE k = ?", table)) + trx.prep(format!("DELETE FROM {} WHERE k = ?", table)) .await? }; @@ -301,7 +301,7 @@ impl MysqlStore { let table = char::from(class.subspace(collection)); let s = trx - .prep(&format!("SELECT v FROM {} WHERE k = ? FOR UPDATE", table)) + .prep(format!("SELECT v FROM {} WHERE k = ? FOR UPDATE", table)) .await?; let (exists, matches) = trx .exec_first::<Vec<u8>, _, _>(&s, (&key,)) @@ -324,7 +324,7 @@ impl MysqlStore { let mut conn = self.conn_pool.get_conn().await.map_err(into_error)?; for subspace in [SUBSPACE_QUOTA, SUBSPACE_COUNTER] { let s = conn - .prep(&format!("DELETE FROM {} WHERE v = 0", char::from(subspace),)) + .prep(format!("DELETE FROM {} WHERE v = 0", char::from(subspace),)) .await .map_err(into_error)?; conn.exec_drop(&s, ()).await.map_err(into_error)?; @@ -337,7 +337,7 @@ impl MysqlStore { let mut conn = self.conn_pool.get_conn().await.map_err(into_error)?; let s = conn - .prep(&format!( + .prep(format!( "DELETE FROM {} WHERE k >= ? AND k < ?", char::from(from.subspace()), )) diff --git a/crates/trc/Cargo.toml b/crates/trc/Cargo.toml index 5bf0dc45..65e073b1 100644 --- a/crates/trc/Cargo.toml +++ b/crates/trc/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "trc" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" [dependencies] event_macro = { path = "./event-macro" } -mail-auth = { version = "0.4" } +mail-auth = { version = "0.5" } mail-parser = { version = "0.9", features = ["full_encoding", "ludicrous_mode"] } base64 = "0.22.1" serde = "1.0" diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index 5344433a..b5ad2d52 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "utils" -version = "0.9.4" +version = "0.10.0" edition = "2021" resolver = "2" @@ -12,7 +12,7 @@ rustls-pki-types = { version = "1" } tokio = { version = "1.23", features = ["net", "macros"] } tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] } serde = { version = "1.0", features = ["derive"]} -mail-auth = { version = "0.4" } +mail-auth = { version = "0.5" } smtp-proto = { version = "0.1" } mail-send = { version = "0.4", default-features = false, features = ["cram-md5", "ring", "tls12"] } dashmap = "6.0" diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 3aef7ba0..4e92531a 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -12,7 +12,6 @@ pub mod glob; pub mod lru_cache; pub mod map; pub mod snowflake; -pub mod suffixlist; pub mod url_params; use rustls::{ diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 51d2d81b..07a578f5 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -31,7 +31,7 @@ trc = { path = "../crates/trc" } managesieve = { path = "../crates/managesieve", features = ["test_mode"] } smtp-proto = { version = "0.1" } mail-send = { version = "0.4", default-features = false, features = ["cram-md5", "ring", "tls12"] } -mail-auth = { version = "0.4", features = ["test"] } +mail-auth = { version = "0.5", features = ["test"] } sieve-rs = { version = "0.5" } utils = { path = "../crates/utils", features = ["test_mode"] } jmap-client = { version = "0.3", features = ["websockets", "debug", "async"] } diff --git a/tests/src/jmap/enterprise.rs b/tests/src/jmap/enterprise.rs index fc6fc491..ddf8d809 100644 --- a/tests/src/jmap/enterprise.rs +++ b/tests/src/jmap/enterprise.rs @@ -104,6 +104,7 @@ pub async fn test(params: &mut JMAPTest) { } .into(), metrics_alerts: parse_metric_alerts(&mut config), + logo_url: None, } .into(); config.assert_no_errors(); @@ -160,6 +161,7 @@ impl EnterpriseCore for Core { trace_store: None, metrics_store: None, metrics_alerts: vec![], + logo_url: None, } .into(); self diff --git a/tests/src/jmap/permissions.rs b/tests/src/jmap/permissions.rs index 236fc153..37eb1e64 100644 --- a/tests/src/jmap/permissions.rs +++ b/tests/src/jmap/permissions.rs @@ -13,8 +13,6 @@ use directory::{ backend::internal::{PrincipalField, PrincipalUpdate, PrincipalValue}, Permission, Principal, Type, }; -use hyper::header::TE; -use rayon::vec; use utils::BlobHash; use crate::jmap::assert_is_empty; @@ -360,12 +358,12 @@ pub async fn test(params: &JMAPTest) { ) .await .unwrap() - .expect_error("notFound"); + .expect_request_error("Forbidden"); tenant_api .get::<()>("/api/principal/foobar") .await .unwrap() - .expect_error("notFound"); + .expect_request_error("Forbidden"); tenant_api .get::<()>("/api/principal?type=tenant") .await diff --git a/tests/src/jmap/webhooks.rs b/tests/src/jmap/webhooks.rs index 8119bb29..3988cdfe 100644 --- a/tests/src/jmap/webhooks.rs +++ b/tests/src/jmap/webhooks.rs @@ -131,10 +131,7 @@ pub fn spawn_mock_webhook_endpoint() -> Arc<MockWebhookEndpoint> { endpoint.events.lock().extend(request.events); Ok::<_, hyper::Error>( - Resource { - content_type: "application/json", - contents: "[]".to_string().into_bytes(), - } + Resource::new("application/json", "[]".to_string().into_bytes()) .into_http_response().build(), ) } else { diff --git a/tests/src/smtp/inbound/antispam.rs b/tests/src/smtp/inbound/antispam.rs index c61b33c5..1c3e5eb9 100644 --- a/tests/src/smtp/inbound/antispam.rs +++ b/tests/src/smtp/inbound/antispam.rs @@ -78,8 +78,8 @@ path = "{PATH}/test_antispam.db" #url = "redis://127.0.0.1" [lookup] -"spam-free" = {"gmail.com", "googlemail.com", "yahoomail.com", "*.freemail.org"} -"spam-disposable" = {"guerrillamail.com", "*.disposable.org"} +"spam-free" = {"gmail.com", "googlemail.com", "yahoomail.com", "*freemail.org"} +"spam-disposable" = {"guerrillamail.com", "*disposable.org"} "spam-redirect" = {"bit.ly", "redirect.io", "redirect.me", "redirect.org", "redirect.com", "redirect.net", "t.ly", "tinyurl.com"} "spam-dmarc" = {"dmarc-allow.org"} "spam-spdk" = {"spf-dkim-allow.org"} diff --git a/tests/src/smtp/inbound/milter.rs b/tests/src/smtp/inbound/milter.rs index 1be5f193..ccbac2f5 100644 --- a/tests/src/smtp/inbound/milter.rs +++ b/tests/src/smtp/inbound/milter.rs @@ -809,10 +809,7 @@ pub fn spawn_mock_mta_hook_server() -> watch::Sender<bool> { let response = handle_mta_hook(request, tests); Ok::<_, hyper::Error>( - Resource { - content_type: "application/json", - contents: serde_json::to_string(&response).unwrap().into_bytes(), - } + Resource::new("application/json", serde_json::to_string(&response).unwrap().into_bytes()) .into_http_response().build(), ) } diff --git a/tests/src/smtp/outbound/dane.rs b/tests/src/smtp/outbound/dane.rs index 42e4a717..80c5242a 100644 --- a/tests/src/smtp/outbound/dane.rs +++ b/tests/src/smtp/outbound/dane.rs @@ -35,7 +35,6 @@ use mail_auth::{ Resolver, MX, }; use rustls_pki_types::CertificateDer; -use utils::suffixlist::PublicSuffix; use crate::smtp::{ inbound::{TestMessage, TestQueueEvent, TestReportingEvent}, @@ -260,7 +259,6 @@ async fn dane_test() { tlsa: LruCache::with_capacity(10), mta_sts: LruCache::with_capacity(10), }, - psl: PublicSuffix::default(), }; let r = SMTP { core: core.into(), |