DKIM2 tests
This commit is contained in:
401
Cargo.lock
generated
401
Cargo.lock
generated
@@ -93,7 +93,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"serde",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
"zerocopy 0.8.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -122,15 +122,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.102"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||
checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.9.1"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207"
|
||||
checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
@@ -167,9 +167,9 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.7"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe"
|
||||
checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
|
||||
|
||||
[[package]]
|
||||
name = "ascii-canvas"
|
||||
@@ -221,15 +221,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "astral-tokio-tar"
|
||||
version = "0.6.2"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb50a7aae84a03bf55b067832bc376f4961b790c97e64d3eacee97d389b90277"
|
||||
checksum = "08648fef353ab39a9d26f909ad53fc4f071be4c91853b78523f5cc3d9e5ebffd"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"futures-core",
|
||||
"libc",
|
||||
"portable-atomic",
|
||||
"rustc-hash",
|
||||
"rustix 0.38.44",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"xattr",
|
||||
@@ -281,7 +281,7 @@ dependencies = [
|
||||
"memchr",
|
||||
"pin-project",
|
||||
"portable-atomic",
|
||||
"rand 0.10.1",
|
||||
"rand 0.10.2",
|
||||
"regex",
|
||||
"rustls-native-certs",
|
||||
"rustls-pki-types",
|
||||
@@ -390,9 +390,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-rs"
|
||||
version = "1.17.0"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00"
|
||||
checksum = "4342d8937fc7e5dd9b1c60292261c0670c882a2cd1719cfc11b1af41731e32ad"
|
||||
dependencies = [
|
||||
"aws-lc-sys",
|
||||
"untrusted 0.7.1",
|
||||
@@ -401,14 +401,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-sys"
|
||||
version = "0.41.0"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4"
|
||||
checksum = "6d9ceb1da931507a12f4fccea479dccd00da1943e1b4ae72d8e502d707361444"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cmake",
|
||||
"dunce",
|
||||
"fs_extra",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -770,7 +771,7 @@ version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
|
||||
dependencies = [
|
||||
"hybrid-array",
|
||||
"hybrid-array 0.4.13",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -789,7 +790,7 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b"
|
||||
dependencies = [
|
||||
"hybrid-array",
|
||||
"hybrid-array 0.4.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -917,9 +918,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "buffered-reader"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db26bf1f092fd5e05b5ab3be2f290915aeb6f3f20c4e9f86ce0f07f336c2412f"
|
||||
checksum = "c7531a07caf83a3fa3b47a233b437ee7910cccfb688555d224338295a0a64fcc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -1319,7 +1320,7 @@ dependencies = [
|
||||
"proxy-header",
|
||||
"psl",
|
||||
"pwhash",
|
||||
"quick-xml 0.40.1",
|
||||
"quick-xml 0.41.0",
|
||||
"quick_cache",
|
||||
"rasn",
|
||||
"rasn-cms",
|
||||
@@ -1641,7 +1642,8 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
|
||||
dependencies = [
|
||||
"hybrid-array",
|
||||
"hybrid-array 0.4.13",
|
||||
"rand_core 0.10.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1729,8 +1731,8 @@ dependencies = [
|
||||
"crypto-bigint",
|
||||
"elliptic-curve",
|
||||
"rand_core 0.6.4",
|
||||
"sha3",
|
||||
"signature",
|
||||
"sha3 0.10.9",
|
||||
"signature 2.2.0",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -1849,7 +1851,7 @@ dependencies = [
|
||||
"hashify",
|
||||
"hyper",
|
||||
"mail-parser",
|
||||
"quick-xml 0.40.1",
|
||||
"quick-xml 0.41.0",
|
||||
"rkyv",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2170,7 +2172,7 @@ dependencies = [
|
||||
"pkcs8",
|
||||
"rfc6979",
|
||||
"sha2 0.10.9",
|
||||
"signature",
|
||||
"signature 2.2.0",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -2218,7 +2220,7 @@ dependencies = [
|
||||
"digest 0.10.7",
|
||||
"elliptic-curve",
|
||||
"rfc6979",
|
||||
"signature",
|
||||
"signature 2.2.0",
|
||||
"spki",
|
||||
]
|
||||
|
||||
@@ -2247,7 +2249,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||
dependencies = [
|
||||
"pkcs8",
|
||||
"signature",
|
||||
"signature 2.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2488,7 +2490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee93edf3c501f0035bbeffeccfed0b79e14c311f12195ec0e661e114a0f60da4"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
"rand 0.10.1",
|
||||
"rand 0.10.2",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
@@ -2509,16 +2511,6 @@ version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.9"
|
||||
@@ -2626,7 +2618,7 @@ dependencies = [
|
||||
"foundationdb-sys",
|
||||
"foundationdb-tuple",
|
||||
"futures",
|
||||
"rand 0.10.1",
|
||||
"rand 0.10.2",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"serde_json",
|
||||
@@ -2817,7 +2809,7 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"rustix 1.1.4",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
@@ -3072,7 +3064,7 @@ dependencies = [
|
||||
"jni 0.22.4",
|
||||
"lru-cache",
|
||||
"parking_lot",
|
||||
"rand 0.10.1",
|
||||
"rand 0.10.2",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"rustls-platform-verifier 0.7.0",
|
||||
@@ -3099,7 +3091,7 @@ dependencies = [
|
||||
"jni 0.22.4",
|
||||
"once_cell",
|
||||
"prefix-trie",
|
||||
"rand 0.10.1",
|
||||
"rand 0.10.2",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"thiserror 2.0.18",
|
||||
@@ -3126,7 +3118,7 @@ dependencies = [
|
||||
"ndk-context",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"rand 0.10.1",
|
||||
"rand 0.10.2",
|
||||
"resolv-conf",
|
||||
"rustls",
|
||||
"smallvec",
|
||||
@@ -3230,7 +3222,7 @@ dependencies = [
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pkcs8",
|
||||
"quick-xml 0.40.1",
|
||||
"quick-xml 0.41.0",
|
||||
"registry",
|
||||
"rkyv",
|
||||
"rsa",
|
||||
@@ -3334,19 +3326,30 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
|
||||
checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15"
|
||||
|
||||
[[package]]
|
||||
name = "hybrid-array"
|
||||
version = "0.4.12"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da"
|
||||
checksum = "891d15931895091dea5c47afa5b3c9a01ba634b311919fd4d41388fa0e3d76af"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hybrid-array"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c"
|
||||
dependencies = [
|
||||
"ctutils",
|
||||
"typenum",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.10.1"
|
||||
@@ -3730,7 +3733,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7"
|
||||
dependencies = [
|
||||
"block-padding 0.4.2",
|
||||
"hybrid-array",
|
||||
"hybrid-array 0.4.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4034,9 +4037,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.102"
|
||||
version = "0.3.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
|
||||
checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
@@ -4073,7 +4076,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.9",
|
||||
"signature",
|
||||
"signature 2.2.0",
|
||||
"simple_asn1",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -4087,6 +4090,26 @@ dependencies = [
|
||||
"cpufeatures 0.2.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keccak"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kem"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01737161ba802849cfd486b5bd209d38ba4943494c249a8126005170c7621edd"
|
||||
dependencies = [
|
||||
"crypto-common 0.2.2",
|
||||
"rand_core 0.10.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keyed-set"
|
||||
version = "1.1.0"
|
||||
@@ -4134,7 +4157,7 @@ dependencies = [
|
||||
"petgraph",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
"sha3",
|
||||
"sha3 0.10.9",
|
||||
"string_cache",
|
||||
"term",
|
||||
"unicode-xid",
|
||||
@@ -4248,9 +4271,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3"
|
||||
checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -4299,6 +4322,12 @@ version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.12.1"
|
||||
@@ -4390,6 +4419,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mail-auth"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce2a3c0ef3c8f70fc3a2ce043453605b4d5e9501f5ff2318aac92ab8d59fb78b"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"flate2",
|
||||
@@ -4643,6 +4674,47 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ml-dsa"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "add6b9d92e496f16f4526d68ff29da1483aba4b119baeab8bed3b9e3544a6f3d"
|
||||
dependencies = [
|
||||
"crypto-common 0.2.2",
|
||||
"ctutils",
|
||||
"hybrid-array 0.4.13",
|
||||
"module-lattice",
|
||||
"shake",
|
||||
"signature 3.0.0",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ml-kem"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e15f3e5b957493873e396a66914e83e616b6afe335cdef7efe5c6e1216aba66"
|
||||
dependencies = [
|
||||
"hybrid-array 0.4.13",
|
||||
"kem",
|
||||
"module-lattice",
|
||||
"rand_core 0.10.1",
|
||||
"sha3 0.11.0",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "module-lattice"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c61b87c9683ab7cb1c6871d261ad5479b6b10ceb52c4352aaca3b5d35a8febe"
|
||||
dependencies = [
|
||||
"ctutils",
|
||||
"hybrid-array 0.4.13",
|
||||
"num-traits",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moka"
|
||||
version = "0.12.15"
|
||||
@@ -4893,9 +4965,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
checksum = "c863e9ab5e7bf9c99ba75e1050f1e4d624ae87ed3532d6238ffbdc7b585dbbe6"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
@@ -5632,7 +5704,7 @@ dependencies = [
|
||||
"hmac 0.13.0",
|
||||
"md-5 0.11.0",
|
||||
"memchr",
|
||||
"rand 0.10.1",
|
||||
"rand 0.10.2",
|
||||
"sha2 0.11.0",
|
||||
"stringprep",
|
||||
]
|
||||
@@ -5677,7 +5749,7 @@ version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
"zerocopy 0.8.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5844,9 +5916,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "psl"
|
||||
version = "2.1.214"
|
||||
version = "2.1.216"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9124f6ba3f3aea75e4918fc86c76adfba8c9d289ab36f926f0b6ce4987a9e6a9"
|
||||
checksum = "9826c2fe4dade07e9da1af2e18427257877bc8bc27aa810f6fbb52d907a480cc"
|
||||
dependencies = [
|
||||
"psl-types",
|
||||
]
|
||||
@@ -5939,13 +6011,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quick_cache"
|
||||
version = "0.6.23"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a3db184a8b66cfe87f0263a1de147a6b554c864d1767c6f7fa4eb0e5497b565"
|
||||
checksum = "403c1a912fec895cafb223201e368234842acb9220aaf08ab042ae89ba5f135c"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"equivalent",
|
||||
"hashbrown 0.16.1",
|
||||
"foldhash 0.2.0",
|
||||
"hashbrown 0.17.1",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
@@ -6053,9 +6125,9 @@ checksum = "019b4b213425016d7d84a153c4c73afb0946fbb4840e4eece7ba8848b9d6da22"
|
||||
|
||||
[[package]]
|
||||
name = "rancor"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee"
|
||||
checksum = "daff8b7b3ccf5f7ba270b3e7a0a4d4c701c5797e38dec27c7e2c3dbb830fed1c"
|
||||
dependencies = [
|
||||
"ptr_meta",
|
||||
]
|
||||
@@ -6096,9 +6168,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.10.1"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
|
||||
checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
|
||||
dependencies = [
|
||||
"chacha20 0.10.1",
|
||||
"getrandom 0.4.3",
|
||||
@@ -6311,9 +6383,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "1.2.4"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bae41a63fd0b8a5372f82b21e810e09a316f5dd7efd96bf08e678fb240fc1918"
|
||||
checksum = "2fa6f8e4b491d7a8ef3a9550a4d71969bd0064f46e32b8dbbcc7fc60dad94fed"
|
||||
dependencies = [
|
||||
"arcstr",
|
||||
"async-lock",
|
||||
@@ -6327,7 +6399,7 @@ dependencies = [
|
||||
"num-bigint",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rand 0.10.1",
|
||||
"rand 0.10.2",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"ryu",
|
||||
@@ -6429,9 +6501,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rend"
|
||||
version = "0.5.3"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6"
|
||||
checksum = "663ba70707f96e871406fe10d68128412e619b06d1d47cb91c3a4c6501176240"
|
||||
dependencies = [
|
||||
"bytecheck",
|
||||
]
|
||||
@@ -6572,9 +6644,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rkyv"
|
||||
version = "0.8.16"
|
||||
version = "0.8.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3"
|
||||
checksum = "815cc8a37159a463064825246cadb07961e25cd9885908606f6d08a98d8f8874"
|
||||
dependencies = [
|
||||
"bytecheck",
|
||||
"bytes",
|
||||
@@ -6591,9 +6663,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rkyv_derive"
|
||||
version = "0.8.16"
|
||||
version = "0.8.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6"
|
||||
checksum = "c0ed1a78a1b19d184b0daa629dd9a024573173ec7d485b287cb369fb3607cc1c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -6655,7 +6727,7 @@ dependencies = [
|
||||
"pkcs8",
|
||||
"rand_core 0.6.4",
|
||||
"sha2 0.10.9",
|
||||
"signature",
|
||||
"signature 2.2.0",
|
||||
"spki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
@@ -6748,9 +6820,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.2"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
|
||||
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
@@ -6770,6 +6842,19 @@ dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.4"
|
||||
@@ -6779,7 +6864,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"linux-raw-sys 0.12.1",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
@@ -7056,9 +7141,9 @@ checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||
|
||||
[[package]]
|
||||
name = "sequoia-openpgp"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c847f0f148cf238c3aec88d092fd3c4301c21e906829ea9e415ea7531f7ec094"
|
||||
checksum = "e421679c8175ef4674d913af7fdb8ad0078c8a2599db633ad0b4d02a06b2cb3c"
|
||||
dependencies = [
|
||||
"aes 0.8.4",
|
||||
"aes-gcm",
|
||||
@@ -7093,6 +7178,8 @@ dependencies = [
|
||||
"libc",
|
||||
"md-5 0.10.6",
|
||||
"memsec",
|
||||
"ml-dsa",
|
||||
"ml-kem",
|
||||
"num-bigint-dig",
|
||||
"num-integer",
|
||||
"ocb3",
|
||||
@@ -7107,7 +7194,8 @@ dependencies = [
|
||||
"rsa",
|
||||
"sha1collisiondetection",
|
||||
"sha2 0.10.9",
|
||||
"sha3",
|
||||
"sha3 0.10.9",
|
||||
"slh-dsa",
|
||||
"thiserror 2.0.18",
|
||||
"twofish",
|
||||
"typenum",
|
||||
@@ -7431,7 +7519,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874"
|
||||
dependencies = [
|
||||
"digest 0.10.7",
|
||||
"keccak",
|
||||
"keccak 0.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha3"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1"
|
||||
dependencies = [
|
||||
"digest 0.11.3",
|
||||
"keccak 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shake"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09057cb2149ad4cbd2da1e26b351f9a4c354219421229c69c3063e6f61947c4a"
|
||||
dependencies = [
|
||||
"digest 0.11.3",
|
||||
"keccak 0.2.0",
|
||||
"sponge-cursor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7500,6 +7609,15 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5"
|
||||
dependencies = [
|
||||
"digest 0.11.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.9"
|
||||
@@ -7555,6 +7673,25 @@ version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
||||
|
||||
[[package]]
|
||||
name = "slh-dsa"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd2f20f4049197e03db1104a6452f4d9e96665d79f880198dce4a7026ba5f267"
|
||||
dependencies = [
|
||||
"const-oid 0.9.6",
|
||||
"digest 0.10.7",
|
||||
"hmac 0.12.1",
|
||||
"hybrid-array 0.3.1",
|
||||
"pkcs8",
|
||||
"rand_core 0.6.4",
|
||||
"sha2 0.10.9",
|
||||
"sha3 0.10.9",
|
||||
"signature 2.2.0",
|
||||
"typenum",
|
||||
"zerocopy 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.2"
|
||||
@@ -7720,6 +7857,12 @@ dependencies = [
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sponge-cursor"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a0219bd7d979d58245a4f41f695e1ac9f8befdffadd7f61f1bae9e39abc6620"
|
||||
|
||||
[[package]]
|
||||
name = "sqlite-wasm-rs"
|
||||
version = "0.5.5"
|
||||
@@ -8095,7 +8238,7 @@ dependencies = [
|
||||
"nlp",
|
||||
"num_cpus",
|
||||
"pop3",
|
||||
"quick-xml 0.40.1",
|
||||
"quick-xml 0.41.0",
|
||||
"rayon",
|
||||
"rcgen",
|
||||
"registry",
|
||||
@@ -8176,9 +8319,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.51"
|
||||
version = "0.3.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327"
|
||||
checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"js-sys",
|
||||
@@ -8197,9 +8340,9 @@ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.30"
|
||||
version = "0.2.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcef1a61bdb119096e153208ec5cbec23944ce8bca13be5c7f60c634f7403935"
|
||||
checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
@@ -8310,7 +8453,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"postgres-protocol",
|
||||
"postgres-types",
|
||||
"rand 0.10.1",
|
||||
"rand 0.10.2",
|
||||
"socket2 0.6.4",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
@@ -8952,9 +9095,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.23.3"
|
||||
version = "1.23.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7"
|
||||
checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53"
|
||||
dependencies = [
|
||||
"getrandom 0.4.3",
|
||||
"js-sys",
|
||||
@@ -9083,9 +9226,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.125"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
|
||||
checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
@@ -9096,9 +9239,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.75"
|
||||
version = "0.4.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280"
|
||||
checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -9106,9 +9249,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.125"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
|
||||
checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -9116,9 +9259,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.125"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
|
||||
checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
@@ -9129,9 +9272,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.125"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
|
||||
checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -9164,9 +9307,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.102"
|
||||
version = "0.3.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d"
|
||||
checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -9436,6 +9579,15 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
@@ -9716,7 +9868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rustix",
|
||||
"rustix 1.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9742,9 +9894,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xxhash-rust"
|
||||
version = "0.8.15"
|
||||
version = "0.8.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3"
|
||||
checksum = "4d93c89cdc2d3a63c3ec48ffe926931bdc069eafa8e4402fe6d8f790c9d1e576"
|
||||
|
||||
[[package]]
|
||||
name = "yasna"
|
||||
@@ -9907,7 +10059,7 @@ dependencies = [
|
||||
"hmac 0.12.1",
|
||||
"rand 0.8.6",
|
||||
"rand_chacha 0.3.1",
|
||||
"sha3",
|
||||
"sha3 0.10.9",
|
||||
"zenoh-result",
|
||||
]
|
||||
|
||||
@@ -10200,7 +10352,7 @@ dependencies = [
|
||||
"ringbuffer-spsc",
|
||||
"rsa",
|
||||
"serde",
|
||||
"sha3",
|
||||
"sha3 0.10.9",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
@@ -10246,13 +10398,34 @@ dependencies = [
|
||||
"zenoh-result",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
"zerocopy-derive 0.8.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10369,9 +10542,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zlib-rs"
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "977347db8caa080403f6b6b7c1cda9479a8e869316f7e13a59b19076a40f94e3"
|
||||
checksum = "5431d5661c32445236631278f27946e444ddafe4684cac70b185272d4f9c52d5"
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
|
||||
@@ -18,7 +18,7 @@ imap_proto = { path = "../imap-proto" }
|
||||
sieve-rs = { version = "0.7", features = ["rkyv", "serde"] }
|
||||
mail-parser = { version = "0.11", features = ["full_encoding"] }
|
||||
mail-builder = { version = "0.4" }
|
||||
mail-auth = { path = "/Users/me/code/mail-auth", features = ["generate", "arc"] }
|
||||
mail-auth = { version = "0.11", features = ["generate", "arc"] }
|
||||
smtp-proto = { version = "0.2", features = ["rkyv"] }
|
||||
dns-update = { version = "0.5" }
|
||||
calcard = { version = "0.3", features = ["rkyv"] }
|
||||
@@ -78,14 +78,14 @@ compact_str = { version = "0.9.0", features = ["rkyv", "serde"] }
|
||||
lz4_flex = { version = "0.13", features = ["frame"], default-features = false }
|
||||
hickory-proto = "0.26"
|
||||
nohash-hasher = "0.2.0"
|
||||
quick_cache = "0.6.9"
|
||||
quick_cache = "0.7"
|
||||
rasn = "0.28"
|
||||
rasn-cms = "0.28"
|
||||
rasn-pkix = "0.28"
|
||||
sequoia-openpgp = { version = "2.0", default-features = false, features = ["crypto-rust", "allow-experimental-crypto", "allow-variable-time-crypto"] }
|
||||
zxcvbn = "3.1.0"
|
||||
pkcs8 = { version = "0.10.2", features = ["alloc", "std"] }
|
||||
quick-xml = "0.40"
|
||||
quick-xml = "0.41"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
privdrop = "0.5.3"
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2024"
|
||||
trc = { path = "../trc" }
|
||||
types = { path = "../types" }
|
||||
hashify = "0.2.6"
|
||||
quick-xml = "0.40"
|
||||
quick-xml = "0.41"
|
||||
calcard = { version = "0.3", features = ["rkyv"] }
|
||||
mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] }
|
||||
hyper = "1.6.0"
|
||||
|
||||
@@ -23,13 +23,13 @@ registry = { path = "../registry" }
|
||||
smtp-proto = { version = "0.2" }
|
||||
mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] }
|
||||
mail-builder = { version = "0.4" }
|
||||
mail-auth = { path = "/Users/me/code/mail-auth", features = ["generate", "arc"] }
|
||||
mail-auth = { version = "0.11", features = ["generate", "arc"] }
|
||||
tokio = { version = "1.47", features = ["rt"] }
|
||||
hyper = { version = "1.0.1", features = ["server", "http1", "http2"] }
|
||||
hyper-util = { version = "0.1.1", features = ["tokio"] }
|
||||
http-body-util = "0.1.0"
|
||||
async-stream = "0.3.5"
|
||||
quick-xml = "0.40"
|
||||
quick-xml = "0.41"
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde_json = "1.0"
|
||||
x509-parser = "0.18"
|
||||
|
||||
@@ -23,7 +23,7 @@ calcard = { version = "0.3" }
|
||||
smtp-proto = { version = "0.2" }
|
||||
mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] }
|
||||
mail-builder = { version = "0.4" }
|
||||
mail-auth = { path = "/Users/me/code/mail-auth", features = ["generate", "arc"] }
|
||||
mail-auth = { version = "0.11", features = ["generate", "arc"] }
|
||||
sieve-rs = { version = "0.7", features = ["rkyv"] }
|
||||
jmap-tools = { version = "0.1", features = ["rkyv"] }
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
|
||||
@@ -13,7 +13,7 @@ hashify = "0.2.7"
|
||||
ahash = { version = "0.8" }
|
||||
jmap-tools = { version = "0.1" }
|
||||
xxhash-rust = { version = "0.8.5", features = ["xxh3"] }
|
||||
mail-auth = { path = "/Users/me/code/mail-auth" }
|
||||
mail-auth = { version = "0.11" }
|
||||
tokio = { version = "1.47", features = ["fs"] }
|
||||
lz4_flex = { version = "0.13", default-features = false }
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ email = { path = "../email" }
|
||||
registry = { path = "../registry" }
|
||||
spam-filter = { path = "../spam-filter" }
|
||||
trc = { path = "../trc" }
|
||||
mail-auth = { path = "/Users/me/code/mail-auth", features = ["rkyv"] }
|
||||
mail-auth = { version = "0.11", features = ["rkyv"] }
|
||||
mail-parser = { version = "0.11", features = ["full_encoding"] }
|
||||
mail-builder = { version = "0.4" }
|
||||
smtp-proto = { version = "0.2", features = ["rkyv", "serde"] }
|
||||
|
||||
@@ -85,7 +85,7 @@ impl DkimSign for Server {
|
||||
});
|
||||
let instance = MessageInstance::from_message(&modified, original.as_ref());
|
||||
if let Some(instance) = &instance {
|
||||
instance.write(&mut headers);
|
||||
instance.write_header(&mut headers);
|
||||
}
|
||||
|
||||
// Obtain disclosed and undisclosed recipients
|
||||
@@ -104,11 +104,11 @@ impl DkimSign for Server {
|
||||
Ok(signature) => {
|
||||
if envelopes.undisclosed_recipients.is_empty() {
|
||||
// Happy path: no undisclosed recipients, serialize signature straight to blob
|
||||
signature.write(&mut headers);
|
||||
signature.write_header(&mut headers);
|
||||
} else {
|
||||
// Undisclosed recipients present, serialize signature to metadata
|
||||
let mut header = Vec::with_capacity(64);
|
||||
signature.write(&mut header);
|
||||
signature.write_header(&mut header);
|
||||
params.metadata.push(Metadata::Headers {
|
||||
value: header.into_boxed_slice(),
|
||||
id: u64::MAX,
|
||||
@@ -135,7 +135,7 @@ impl DkimSign for Server {
|
||||
Ok(signature) => {
|
||||
// Serialize signature to metadata
|
||||
let mut header = Vec::with_capacity(64);
|
||||
signature.write(&mut header);
|
||||
signature.write_header(&mut header);
|
||||
params.metadata.push(Metadata::Headers {
|
||||
value: header.into_boxed_slice(),
|
||||
id: pos as u64,
|
||||
@@ -251,3 +251,168 @@ impl MessageWrapper {
|
||||
fn sanitize_or_lower(rcpt: &str) -> String {
|
||||
sanitize_email(rcpt).unwrap_or_else(|| rcpt.to_lowercase())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::queue::{Message, QueueId, Recipient};
|
||||
use common::config::smtp::queue::QueueName;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
|
||||
fn wrapper(recipients: &[&str]) -> MessageWrapper {
|
||||
MessageWrapper {
|
||||
queue_id: 0 as QueueId,
|
||||
queue_name: QueueName::default(),
|
||||
is_multi_queue: false,
|
||||
span_id: 0,
|
||||
message: Message {
|
||||
created: 0,
|
||||
blob_hash: Default::default(),
|
||||
return_path: "sender@example.com".into(),
|
||||
recipients: recipients.iter().map(Recipient::new).collect(),
|
||||
received_from_ip: IpAddr::V4(Ipv4Addr::LOCALHOST),
|
||||
received_via_port: 0,
|
||||
flags: 0,
|
||||
env_id: None,
|
||||
priority: 0,
|
||||
size: 0,
|
||||
metadata: Default::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn split(headers: &str, recipients: &[&str]) -> (Vec<String>, Vec<String>) {
|
||||
let raw = format!("{headers}\r\nSubject: test\r\n\r\nbody\r\n");
|
||||
let auth = AuthenticatedMessage::parse(raw.as_bytes()).expect("parse message");
|
||||
let message = wrapper(recipients);
|
||||
let envelopes = message.undisclosed_recipients(&auth);
|
||||
let mut disclosed = envelopes
|
||||
.disclosed_recipients
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
let mut undisclosed = envelopes
|
||||
.undisclosed_recipients
|
||||
.iter()
|
||||
.map(|(_, s)| s.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
disclosed.sort();
|
||||
undisclosed.sort();
|
||||
(disclosed, undisclosed)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_recipient_is_always_disclosed() {
|
||||
let (disclosed, undisclosed) = split("To: someone-else@example.com", &["bcc@example.org"]);
|
||||
assert_eq!(disclosed, vec!["bcc@example.org".to_string()]);
|
||||
assert!(undisclosed.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_recipients_disclosed() {
|
||||
let (disclosed, undisclosed) = split(
|
||||
"To: alice@example.com, bob@example.com\r\nCc: carol@example.com",
|
||||
&["alice@example.com", "bob@example.com", "carol@example.com"],
|
||||
);
|
||||
assert_eq!(
|
||||
disclosed,
|
||||
vec![
|
||||
"alice@example.com".to_string(),
|
||||
"bob@example.com".to_string(),
|
||||
"carol@example.com".to_string(),
|
||||
]
|
||||
);
|
||||
assert!(undisclosed.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed_disclosed_and_undisclosed() {
|
||||
let (disclosed, undisclosed) = split(
|
||||
"To: alice@example.com\r\nCc: bob@example.com",
|
||||
&[
|
||||
"alice@example.com",
|
||||
"bob@example.com",
|
||||
"eve@secret.example.org",
|
||||
"mallory@secret.example.org",
|
||||
],
|
||||
);
|
||||
assert_eq!(
|
||||
disclosed,
|
||||
vec![
|
||||
"alice@example.com".to_string(),
|
||||
"bob@example.com".to_string()
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
undisclosed,
|
||||
vec![
|
||||
"eve@secret.example.org".to_string(),
|
||||
"mallory@secret.example.org".to_string(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_to_or_cc_header_all_undisclosed() {
|
||||
let (disclosed, undisclosed) = split(
|
||||
"From: sender@example.com",
|
||||
&["eve@example.org", "mallory@example.org"],
|
||||
);
|
||||
assert!(disclosed.is_empty());
|
||||
assert_eq!(
|
||||
undisclosed,
|
||||
vec![
|
||||
"eve@example.org".to_string(),
|
||||
"mallory@example.org".to_string()
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_addresses_are_disclosed() {
|
||||
let (disclosed, undisclosed) = split(
|
||||
"To: Team:alice@example.com,bob@example.com;",
|
||||
&["alice@example.com", "bob@example.com", "eve@example.org"],
|
||||
);
|
||||
assert_eq!(
|
||||
disclosed,
|
||||
vec![
|
||||
"alice@example.com".to_string(),
|
||||
"bob@example.com".to_string()
|
||||
]
|
||||
);
|
||||
assert_eq!(undisclosed, vec!["eve@example.org".to_string()]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn header_address_casing_is_ignored() {
|
||||
let (disclosed, undisclosed) = split(
|
||||
"To: Alice@Example.COM, BOB@EXAMPLE.com",
|
||||
&["alice@example.com", "bob@example.com", "eve@example.org"],
|
||||
);
|
||||
assert_eq!(
|
||||
disclosed,
|
||||
vec![
|
||||
"alice@example.com".to_string(),
|
||||
"bob@example.com".to_string()
|
||||
]
|
||||
);
|
||||
assert_eq!(undisclosed, vec!["eve@example.org".to_string()]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_names_and_brackets_are_ignored() {
|
||||
let (disclosed, undisclosed) = split(
|
||||
"To: \"Alice Doe\" <alice@example.com>\r\nCc: Bob <bob@example.com>",
|
||||
&["alice@example.com", "bob@example.com", "eve@example.org"],
|
||||
);
|
||||
assert_eq!(
|
||||
disclosed,
|
||||
vec![
|
||||
"alice@example.com".to_string(),
|
||||
"bob@example.com".to_string()
|
||||
]
|
||||
);
|
||||
assert_eq!(undisclosed, vec!["eve@example.org".to_string()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ pub const SMFIC_UNKNOWN: u8 = b'U'; /* Any unknown command */
|
||||
impl Command<'_> {
|
||||
fn build(command: u8, len: u32) -> Vec<u8> {
|
||||
let mut buf = Vec::with_capacity(len as usize + 1 + std::mem::size_of::<u32>());
|
||||
buf.extend_from_slice((len + 1).to_be_bytes().as_ref());
|
||||
buf.extend_from_slice((len + 1).to_be_bytes().as_slice());
|
||||
buf.push(command);
|
||||
buf
|
||||
}
|
||||
@@ -95,7 +95,7 @@ impl Command<'_> {
|
||||
buf.extend(hostname);
|
||||
buf.push(0x00);
|
||||
buf.push(family);
|
||||
buf.extend(port.to_be_bytes().as_ref());
|
||||
buf.extend(port.to_be_bytes().as_slice());
|
||||
buf.extend(address.as_bytes());
|
||||
buf.push(0x00);
|
||||
buf
|
||||
@@ -168,9 +168,9 @@ impl Command<'_> {
|
||||
}
|
||||
Command::OptionNegotiation(opt) => {
|
||||
let mut buf = Command::build(SMFIC_OPTNEG, 3 * std::mem::size_of::<u32>() as u32);
|
||||
buf.extend(opt.version.to_be_bytes().as_ref());
|
||||
buf.extend(opt.actions.to_be_bytes().as_ref());
|
||||
buf.extend(opt.protocol.to_be_bytes().as_ref());
|
||||
buf.extend(opt.version.to_be_bytes().as_slice());
|
||||
buf.extend(opt.actions.to_be_bytes().as_slice());
|
||||
buf.extend(opt.protocol.to_be_bytes().as_slice());
|
||||
buf
|
||||
}
|
||||
Command::Quit => Command::build(SMFIC_QUIT, 0),
|
||||
@@ -417,7 +417,7 @@ impl Response {
|
||||
+ std::mem::size_of::<u32>() as u32
|
||||
+ 2,
|
||||
);
|
||||
buf.extend(index.to_be_bytes().as_ref());
|
||||
buf.extend(index.to_be_bytes().as_slice());
|
||||
buf.extend(name.as_bytes());
|
||||
buf.push(0x00);
|
||||
buf.extend(value.as_bytes());
|
||||
@@ -432,7 +432,7 @@ impl Response {
|
||||
+ std::mem::size_of::<u32>() as u32
|
||||
+ 2,
|
||||
);
|
||||
buf.extend(index.to_be_bytes().as_ref());
|
||||
buf.extend(index.to_be_bytes().as_slice());
|
||||
buf.extend(name.as_bytes());
|
||||
buf.push(0x00);
|
||||
buf.extend(value.as_bytes());
|
||||
@@ -451,9 +451,9 @@ impl Response {
|
||||
Response::SetSymbols => Command::build(SMFIR_SETSYMLIST, 0),
|
||||
Response::OptionNegotiation(opt) => {
|
||||
let mut buf = Command::build(SMFIC_OPTNEG, 3 * std::mem::size_of::<u32>() as u32);
|
||||
buf.extend(opt.version.to_be_bytes().as_ref());
|
||||
buf.extend(opt.actions.to_be_bytes().as_ref());
|
||||
buf.extend(opt.protocol.to_be_bytes().as_ref());
|
||||
buf.extend(opt.version.to_be_bytes().as_slice());
|
||||
buf.extend(opt.actions.to_be_bytes().as_slice());
|
||||
buf.extend(opt.protocol.to_be_bytes().as_slice());
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ registry = { path = "../registry" }
|
||||
smtp-proto = { version = "0.2", features = ["rkyv"] }
|
||||
mail-parser = { version = "0.11", features = ["full_encoding"] }
|
||||
mail-builder = { version = "0.4" }
|
||||
mail-auth = { path = "/Users/me/code/mail-auth" }
|
||||
mail-auth = { version = "0.11" }
|
||||
tokio = { version = "1.47", features = ["net", "macros"] }
|
||||
psl = "2"
|
||||
hyper = { version = "1.0.1", features = ["server", "http1", "http2"] }
|
||||
|
||||
@@ -5,7 +5,7 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
event_macro = { path = "./event-macro" }
|
||||
mail-auth = { path = "/Users/me/code/mail-auth", features = ["arc"] }
|
||||
mail-auth = { version = "0.11", features = ["arc"] }
|
||||
mail-parser = { version = "0.11", features = ["full_encoding"] }
|
||||
base64 = "0.22.1"
|
||||
serde = "1.0"
|
||||
|
||||
@@ -12,7 +12,7 @@ rustls-platform-verifier = "0.7"
|
||||
tokio = { version = "1.47", features = ["net", "macros", "signal"] }
|
||||
tokio-rustls = { version = "0.26", default-features = false, features = ["aws_lc_rs", "tls12"] }
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
mail-auth = { path = "/Users/me/code/mail-auth" }
|
||||
mail-auth = { version = "0.11" }
|
||||
smtp-proto = { version = "0.2" }
|
||||
ahash = { version = "0.8", features = ["serde"] }
|
||||
chrono = "0.4"
|
||||
@@ -32,7 +32,7 @@ http-body-util = "0.1.0"
|
||||
form_urlencoded = "1.1.0"
|
||||
psl = "2"
|
||||
idna = "1.0"
|
||||
quick_cache = "0.6.9"
|
||||
quick_cache = "0.7"
|
||||
fast-float = "0.2.0"
|
||||
rkyv = { version = "0.8.10", features = ["little_endian"] }
|
||||
compact_str = "0.9.0"
|
||||
|
||||
@@ -19,11 +19,11 @@ use std::{
|
||||
};
|
||||
|
||||
pub struct Cache<K: Eq + Hash + CacheItemWeight, V: Clone + CacheItemWeight>(
|
||||
quick_cache::sync::Cache<K, V, CacheItemWeighter>,
|
||||
quick_cache::sync::Cache<K, V, CacheItemWeighter, ahash::RandomState>,
|
||||
);
|
||||
|
||||
pub struct CacheWithTtl<K: Eq + Hash + CacheItemWeight, V: Clone + CacheItemWeight>(
|
||||
quick_cache::sync::Cache<K, TtlEntry<V>, CacheItemWeighter>,
|
||||
quick_cache::sync::Cache<K, TtlEntry<V>, CacheItemWeighter, ahash::RandomState>,
|
||||
);
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -38,10 +38,12 @@ impl<K: Eq + Hash + CacheItemWeight, V: Clone + CacheItemWeight> Cache<K, V> {
|
||||
}
|
||||
|
||||
pub fn new_estimated(estimated_items_capacity: usize, weight_capacity: u64) -> Self {
|
||||
Self(quick_cache::sync::Cache::with_weighter(
|
||||
Self(quick_cache::sync::Cache::with(
|
||||
estimated_items_capacity,
|
||||
weight_capacity,
|
||||
CacheItemWeighter,
|
||||
ahash::RandomState::default(),
|
||||
DefaultLifecycle::default(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -101,7 +103,7 @@ impl<K: Eq + Hash + CacheItemWeight, V: Clone + CacheItemWeight> Cache<K, V> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn inner(&self) -> &quick_cache::sync::Cache<K, V, CacheItemWeighter> {
|
||||
pub fn inner(&self) -> &quick_cache::sync::Cache<K, V, CacheItemWeighter, ahash::RandomState> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
@@ -112,10 +114,12 @@ impl<K: Eq + Hash + CacheItemWeight, V: Clone + CacheItemWeight> CacheWithTtl<K,
|
||||
}
|
||||
|
||||
pub fn new_estimated(estimated_items_capacity: usize, weight_capacity: u64) -> Self {
|
||||
Self(quick_cache::sync::Cache::with_weighter(
|
||||
Self(quick_cache::sync::Cache::with(
|
||||
estimated_items_capacity,
|
||||
weight_capacity,
|
||||
CacheItemWeighter,
|
||||
ahash::RandomState::default(),
|
||||
DefaultLifecycle::default(),
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ migration = { path = "../crates/migration", features = ["test_mode", "enterprise
|
||||
trc = { path = "../crates/trc", features = ["enterprise"] }
|
||||
managesieve = { path = "../crates/managesieve", features = ["test_mode", "enterprise"] }
|
||||
smtp-proto = { version = "0.2" }
|
||||
mail-auth = { path = "/Users/me/code/mail-auth", features = ["test"] }
|
||||
mail-auth = { version = "0.11", features = ["test"] }
|
||||
mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] }
|
||||
mail-builder = "0.4.4"
|
||||
sieve-rs = { version = "0.7", features = ["rkyv"] }
|
||||
@@ -79,7 +79,7 @@ biscuit = "0.8.0"
|
||||
form_urlencoded = "1.1.0"
|
||||
rkyv = { version = "0.8.10", features = ["little_endian"] }
|
||||
compact_str = "0.9.0"
|
||||
quick-xml = "0.40"
|
||||
quick-xml = "0.41"
|
||||
jmap-tools = { version = "0.1" }
|
||||
dns-update = { version = "0.5", features = ["test_provider"] }
|
||||
x509-parser = "0.18"
|
||||
|
||||
633
tests/src/smtp/inbound/dkim2.rs
Normal file
633
tests/src/smtp/inbound/dkim2.rs
Normal file
@@ -0,0 +1,633 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::{
|
||||
smtp::{inbound::TestMessage, session::TestSession},
|
||||
utils::{account::Account, dns::DnsCache, server::TestServer, server::TestServerBuilder},
|
||||
};
|
||||
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||
use mail_auth::{
|
||||
DnssecStatus, MX,
|
||||
common::{crypto::Ed25519Key, parse::TxtRecordParser, verify::DomainKey},
|
||||
dkim2::{Dkim2Signer, Hop},
|
||||
};
|
||||
use registry::schema::{
|
||||
enums::{DkimCanonicalization, DkimRotationStage},
|
||||
structs::{
|
||||
CertificateManagement, Dkim1Signature, Dkim2Signature, DkimManagement, DkimSignature,
|
||||
DnsManagement, Domain, DsnReportSettings, Expression, SecretText, SecretTextValue,
|
||||
SenderAuth,
|
||||
},
|
||||
};
|
||||
use std::time::{Duration, Instant};
|
||||
use types::id::Id;
|
||||
|
||||
const ED_PRIVATE: &str = concat!(
|
||||
"-----BEGIN PRIVATE KEY-----\n",
|
||||
"MC4CAQAwBQYDK2VwBCIEIIOQVf8MDGvvmIkpUbgoqtyUIxjlzRqaBR6aP12tcGGE\n",
|
||||
"-----END PRIVATE KEY-----\n"
|
||||
);
|
||||
const ED_PUBLIC: &str = "hwjviTXyzUXSCWayBqE17s/4NSynQKxw58jayHudRAI=";
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
async fn dkim2_all_disclosed() {
|
||||
let (mut local, remote) = build_signer_and_verifier(19040, 19041, false).await;
|
||||
|
||||
let delivered = deliver_and_collect(
|
||||
&mut local,
|
||||
&remote,
|
||||
"john@example.com",
|
||||
&["alice@foobar.org", "bob@foobar.org"],
|
||||
&message("To: Alice <alice@foobar.org>, Bob <bob@foobar.org>\r\n"),
|
||||
1,
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(delivered.len(), 1);
|
||||
let msg = &delivered[0];
|
||||
assert_eq!(msg.recipients, vec!["alice@foobar.org", "bob@foobar.org"]);
|
||||
assert!(
|
||||
msg.body.contains("DKIM2-Signature"),
|
||||
"missing DKIM2 signature: {}",
|
||||
msg.body
|
||||
);
|
||||
assert!(
|
||||
without_whitespace(&msg.body).contains("dkim2=pass"),
|
||||
"verifier did not report dkim2=pass: {}",
|
||||
msg.body
|
||||
);
|
||||
|
||||
// Both disclosed recipients belong to the same shared signature
|
||||
let stripped = without_whitespace(&msg.body);
|
||||
assert!(stripped.contains(&rt_token("alice@foobar.org")));
|
||||
assert!(stripped.contains(&rt_token("bob@foobar.org")));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
async fn dkim2_mixed_recipients_do_not_leak_bcc() {
|
||||
let (mut local, remote) = build_signer_and_verifier(19042, 19043, false).await;
|
||||
|
||||
let delivered = deliver_and_collect(
|
||||
&mut local,
|
||||
&remote,
|
||||
"john@example.com",
|
||||
&[
|
||||
"alice@foobar.org",
|
||||
"bob@foobar.org",
|
||||
"eve@foobar.org",
|
||||
"mallory@foobar.org",
|
||||
],
|
||||
&message("To: Alice <alice@foobar.org>\r\nCc: Bob <bob@foobar.org>\r\n"),
|
||||
3,
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(delivered.len(), 3);
|
||||
|
||||
let eve = rt_token("eve@foobar.org");
|
||||
let mallory = rt_token("mallory@foobar.org");
|
||||
|
||||
for msg in &delivered {
|
||||
let stripped = without_whitespace(&msg.body);
|
||||
assert!(
|
||||
stripped.contains("dkim2=pass"),
|
||||
"verifier did not report dkim2=pass for {:?}: {}",
|
||||
msg.recipients,
|
||||
msg.body
|
||||
);
|
||||
|
||||
if msg.recipients == vec!["alice@foobar.org", "bob@foobar.org"] {
|
||||
// Disclosed copy: the two Bcc recipients must not appear anywhere
|
||||
assert!(
|
||||
!stripped.contains(&eve) && !stripped.contains(&mallory),
|
||||
"Bcc recipient leaked into the disclosed signature: {}",
|
||||
msg.body
|
||||
);
|
||||
assert!(!msg.body.contains("eve@foobar.org"));
|
||||
assert!(!msg.body.contains("mallory@foobar.org"));
|
||||
assert!(stripped.contains(&rt_token("alice@foobar.org")));
|
||||
assert!(stripped.contains(&rt_token("bob@foobar.org")));
|
||||
} else if msg.recipients == vec!["eve@foobar.org"] {
|
||||
// Bcc copy: only Eve's address is in this signature
|
||||
assert!(stripped.contains(&eve));
|
||||
assert!(!stripped.contains(&mallory));
|
||||
assert!(!msg.body.contains("mallory@foobar.org"));
|
||||
} else if msg.recipients == vec!["mallory@foobar.org"] {
|
||||
assert!(stripped.contains(&mallory));
|
||||
assert!(!stripped.contains(&eve));
|
||||
assert!(!msg.body.contains("eve@foobar.org"));
|
||||
} else {
|
||||
panic!("unexpected recipient grouping: {:?}", msg.recipients);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
async fn dkim2_all_undisclosed_do_not_leak() {
|
||||
let (mut local, remote) = build_signer_and_verifier(19044, 19045, false).await;
|
||||
|
||||
let rcpts = ["carol@foobar.org", "dave@foobar.org", "frank@foobar.org"];
|
||||
let delivered = deliver_and_collect(
|
||||
&mut local,
|
||||
&remote,
|
||||
"john@example.com",
|
||||
&rcpts,
|
||||
&message("To: undisclosed-recipients:;\r\n"),
|
||||
3,
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(delivered.len(), 3);
|
||||
|
||||
for msg in &delivered {
|
||||
assert_eq!(msg.recipients.len(), 1, "expected one recipient per copy");
|
||||
let own = msg.recipients[0].as_str();
|
||||
let stripped = without_whitespace(&msg.body);
|
||||
assert!(
|
||||
stripped.contains("dkim2=pass"),
|
||||
"verifier did not report dkim2=pass for {own}: {}",
|
||||
msg.body
|
||||
);
|
||||
assert!(stripped.contains(&rt_token(own)));
|
||||
|
||||
// No other recipient may appear in this copy
|
||||
for other in rcpts.iter().filter(|r| **r != own) {
|
||||
assert!(
|
||||
!stripped.contains(&rt_token(other)),
|
||||
"recipient {other} leaked into the copy for {own}: {}",
|
||||
msg.body
|
||||
);
|
||||
assert!(
|
||||
!msg.body.contains(other),
|
||||
"recipient {other} leaked into the copy for {own}: {}",
|
||||
msg.body
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
async fn dkim1_and_dkim2_signed_together() {
|
||||
let (mut local, remote) = build_signer_and_verifier(19046, 19047, true).await;
|
||||
|
||||
let delivered = deliver_and_collect(
|
||||
&mut local,
|
||||
&remote,
|
||||
"john@example.com",
|
||||
&["alice@foobar.org", "bob@foobar.org"],
|
||||
&message("To: Alice <alice@foobar.org>, Bob <bob@foobar.org>\r\n"),
|
||||
1,
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(delivered.len(), 1);
|
||||
let stripped = without_whitespace(&delivered[0].body);
|
||||
assert!(
|
||||
delivered[0].body.contains("DKIM-Signature"),
|
||||
"missing DKIM1 signature: {}",
|
||||
delivered[0].body
|
||||
);
|
||||
assert!(
|
||||
delivered[0].body.contains("DKIM2-Signature"),
|
||||
"missing DKIM2 signature: {}",
|
||||
delivered[0].body
|
||||
);
|
||||
assert!(
|
||||
stripped.contains("dkim=pass"),
|
||||
"DKIM1 did not pass: {}",
|
||||
delivered[0].body
|
||||
);
|
||||
assert!(
|
||||
stripped.contains("dkim2=pass"),
|
||||
"DKIM2 did not pass: {}",
|
||||
delivered[0].body
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
async fn dkim2_dsn_is_signed() {
|
||||
let mut local = TestServerBuilder::new("dkim2_dsn_signer")
|
||||
.await
|
||||
.with_http_listener(19048)
|
||||
.await
|
||||
.disable_services()
|
||||
.capture_queue()
|
||||
.build()
|
||||
.await;
|
||||
|
||||
let admin = local.account("admin");
|
||||
admin.mta_allow_relaying().await;
|
||||
admin.mta_no_auth().await;
|
||||
admin.mta_all_extensions().await;
|
||||
admin.mta_disable_spam_filter().await;
|
||||
admin.mta_add_all_headers().await;
|
||||
let domain_id = admin.create_signing_domain(false).await;
|
||||
admin
|
||||
.registry_create_object(DsnReportSettings {
|
||||
dkim_sign_domain: expr("'example.com'"),
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
let _ = domain_id;
|
||||
admin.reload_settings().await;
|
||||
local.reload_core();
|
||||
local.expect_reload_settings().await;
|
||||
|
||||
// Deliver to a domain with no DNS records: the lookup fails permanently and
|
||||
// a DSN is generated for the sender.
|
||||
let mut session = local.new_mta_session();
|
||||
session.data.remote_ip_str = "10.0.0.1".into();
|
||||
session.eval_session_params().await;
|
||||
session.ehlo("mx.example.com").await;
|
||||
session
|
||||
.send_message(
|
||||
"john@example.com",
|
||||
&["bob@does-not-resolve.invalid"],
|
||||
&message("To: Bob <bob@does-not-resolve.invalid>\r\n"),
|
||||
"250",
|
||||
)
|
||||
.await;
|
||||
|
||||
local
|
||||
.expect_message_then_deliver()
|
||||
.await
|
||||
.try_deliver(local.server.clone());
|
||||
|
||||
let dsn = local.expect_message().await;
|
||||
assert!(
|
||||
dsn.message.return_path.is_empty(),
|
||||
"expected a DSN (null return path)"
|
||||
);
|
||||
let body = dsn.read_message(&local).await;
|
||||
assert!(
|
||||
body.contains("Content-Type: multipart/report"),
|
||||
"not a DSN: {body}"
|
||||
);
|
||||
assert!(
|
||||
body.contains("DKIM2-Signature"),
|
||||
"the generated DSN was not DKIM2 signed: {body}"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
async fn dkim2_inbound_dsn_validation() {
|
||||
let mut server = TestServerBuilder::new("dkim2_dsn_receiver")
|
||||
.await
|
||||
.with_http_listener(19049)
|
||||
.await
|
||||
.disable_services()
|
||||
.capture_queue()
|
||||
.build()
|
||||
.await;
|
||||
|
||||
let admin = server.account("admin");
|
||||
admin.mta_allow_relaying().await;
|
||||
admin.mta_no_auth().await;
|
||||
admin.mta_all_extensions().await;
|
||||
admin.mta_disable_spam_filter().await;
|
||||
admin.mta_add_all_headers().await;
|
||||
admin.configure_sender_auth("''").await;
|
||||
admin.reload_settings().await;
|
||||
server.reload_core();
|
||||
server.expect_reload_settings().await;
|
||||
|
||||
// The returned message is signed by us (example.com); the DSN is signed by
|
||||
// the bouncing domain (foobar.org). Publish both keys.
|
||||
server
|
||||
.server
|
||||
.txt_add("ed._domainkey.example.com", dkim_dns_record(), valid());
|
||||
server
|
||||
.server
|
||||
.txt_add("ed._domainkey.foobar.org", dkim_dns_record(), valid());
|
||||
|
||||
let returned = dkim2_sign(
|
||||
"example.com",
|
||||
"ed",
|
||||
RETURNED_PLAIN.as_bytes(),
|
||||
"john@example.com",
|
||||
&["bob@foobar.org"],
|
||||
);
|
||||
|
||||
// A well-formed, aligned DSN is accepted
|
||||
let dsn_ok = build_dsn(&returned, true);
|
||||
let mut session = server.new_mta_session();
|
||||
session.data.remote_ip_str = "10.0.0.1".into();
|
||||
session.eval_session_params().await;
|
||||
session.ehlo("mx.foobar.org").await;
|
||||
session
|
||||
.send_message(
|
||||
"<>",
|
||||
&["john@example.com"],
|
||||
&String::from_utf8(dsn_ok).unwrap(),
|
||||
"250",
|
||||
)
|
||||
.await;
|
||||
|
||||
// Tampering the returned message body breaks its signature chain, so the DSN
|
||||
// is rejected.
|
||||
let returned_tampered = String::from_utf8(returned)
|
||||
.unwrap()
|
||||
.replace("DKIM2-ORIGINAL-BODY-CONTENT", "DKIM2-TAMPERED-BODY-CONTENT")
|
||||
.into_bytes();
|
||||
let dsn_bad = build_dsn(&returned_tampered, true);
|
||||
session
|
||||
.send_message(
|
||||
"<>",
|
||||
&["john@example.com"],
|
||||
&String::from_utf8(dsn_bad).unwrap(),
|
||||
"550",
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
impl Account {
|
||||
async fn create_signing_domain(&self, with_dkim1: bool) -> Id {
|
||||
let domain_id = self
|
||||
.registry_create_object(Domain {
|
||||
name: "example.com".into(),
|
||||
certificate_management: CertificateManagement::Manual,
|
||||
dns_management: DnsManagement::Manual,
|
||||
dkim_management: DkimManagement::Manual,
|
||||
allow_relaying: true,
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
|
||||
self.registry_create_object(DkimSignature::Dkim2Ed25519Sha256(Dkim2Signature {
|
||||
stage: DkimRotationStage::Active,
|
||||
selector: "ed2".to_string(),
|
||||
domain_id,
|
||||
private_key: SecretText::Text(SecretTextValue {
|
||||
secret: ED_PRIVATE.to_string(),
|
||||
}),
|
||||
..Default::default()
|
||||
}))
|
||||
.await;
|
||||
|
||||
if with_dkim1 {
|
||||
self.registry_create_object(DkimSignature::Dkim1Ed25519Sha256(Dkim1Signature {
|
||||
stage: DkimRotationStage::Active,
|
||||
selector: "ed1".to_string(),
|
||||
canonicalization: DkimCanonicalization::RelaxedRelaxed,
|
||||
domain_id,
|
||||
private_key: SecretText::Text(SecretTextValue {
|
||||
secret: ED_PRIVATE.to_string(),
|
||||
}),
|
||||
..Default::default()
|
||||
}))
|
||||
.await;
|
||||
}
|
||||
|
||||
domain_id
|
||||
}
|
||||
|
||||
async fn configure_sender_auth(&self, dkim_sign_domain: &str) {
|
||||
self.registry_create_object(SenderAuth {
|
||||
dmarc_verify: expr("relaxed"),
|
||||
reverse_ip_verify: expr("relaxed"),
|
||||
spf_ehlo_verify: expr("relaxed"),
|
||||
spf_from_verify: expr("relaxed"),
|
||||
arc_verify: expr("relaxed"),
|
||||
dkim_sign_domain: expr(dkim_sign_domain),
|
||||
dkim_verify: expr("relaxed"),
|
||||
dkim_strict: false,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn build_signer_and_verifier(
|
||||
http_local: u16,
|
||||
http_remote: u16,
|
||||
with_dkim1: bool,
|
||||
) -> (TestServer, TestServer) {
|
||||
let mut local = TestServerBuilder::new("dkim2_signer")
|
||||
.await
|
||||
.with_http_listener(http_local)
|
||||
.await
|
||||
.disable_services()
|
||||
.capture_queue()
|
||||
.build()
|
||||
.await;
|
||||
let mut remote = TestServerBuilder::new("dkim2_verifier")
|
||||
.await
|
||||
.with_http_listener(http_remote)
|
||||
.await
|
||||
.with_smtp_listener(9925)
|
||||
.await
|
||||
.disable_services()
|
||||
.capture_queue()
|
||||
.build()
|
||||
.await;
|
||||
|
||||
// Signer (originating MTA)
|
||||
let admin = local.account("admin");
|
||||
admin.mta_allow_relaying().await;
|
||||
admin.mta_no_auth().await;
|
||||
admin.mta_all_extensions().await;
|
||||
admin.mta_disable_spam_filter().await;
|
||||
admin.mta_add_all_headers().await;
|
||||
admin.create_signing_domain(with_dkim1).await;
|
||||
admin.configure_sender_auth("'example.com'").await;
|
||||
admin.reload_settings().await;
|
||||
local.reload_core();
|
||||
local.expect_reload_settings().await;
|
||||
|
||||
// Verifier (receiving MTA)
|
||||
let remote_admin = remote.account("admin");
|
||||
remote_admin.mta_allow_relaying().await;
|
||||
remote_admin.mta_no_auth().await;
|
||||
remote_admin.mta_all_extensions().await;
|
||||
remote_admin.mta_disable_spam_filter().await;
|
||||
remote_admin.mta_add_all_headers().await;
|
||||
remote_admin.configure_sender_auth("''").await;
|
||||
remote_admin.reload_settings().await;
|
||||
remote.reload_core();
|
||||
remote.expect_reload_settings().await;
|
||||
|
||||
// Publish the signer's public keys in the verifier's DNS
|
||||
remote
|
||||
.server
|
||||
.txt_add("ed2._domainkey.example.com", dkim_dns_record(), valid());
|
||||
if with_dkim1 {
|
||||
remote
|
||||
.server
|
||||
.txt_add("ed1._domainkey.example.com", dkim_dns_record(), valid());
|
||||
}
|
||||
|
||||
// Route foobar.org deliveries back to the local (in-process) receiver
|
||||
local.server.mx_add(
|
||||
"foobar.org",
|
||||
vec![MX {
|
||||
exchanges: vec!["mx.foobar.org".into()].into_boxed_slice(),
|
||||
preference: 10,
|
||||
}],
|
||||
DnssecStatus::Secure,
|
||||
valid(),
|
||||
);
|
||||
local
|
||||
.server
|
||||
.ipv4_add("mx.foobar.org", vec!["127.0.0.1".parse().unwrap()], valid());
|
||||
|
||||
(local, remote)
|
||||
}
|
||||
|
||||
fn message(to_header: &str) -> String {
|
||||
format!(
|
||||
concat!(
|
||||
"From: John Doe <john@example.com>\r\n",
|
||||
"{}",
|
||||
"Subject: DKIM2 privacy test\r\n",
|
||||
"\r\n",
|
||||
"This is a DKIM2 test message.\r\n",
|
||||
),
|
||||
to_header
|
||||
)
|
||||
}
|
||||
|
||||
fn build_dsn(returned: &[u8], sign_dsn: bool) -> Vec<u8> {
|
||||
let mut body = Vec::new();
|
||||
body.extend_from_slice(b"--BOUNDARY\r\nContent-Type: text/plain\r\n\r\n");
|
||||
body.extend_from_slice(b"Delivery to bob@foobar.org failed.\r\n");
|
||||
body.extend_from_slice(b"--BOUNDARY\r\nContent-Type: message/delivery-status\r\n\r\n");
|
||||
body.extend_from_slice(b"Reporting-MTA: dns; foobar.org\r\n\r\n");
|
||||
body.extend_from_slice(b"Final-Recipient: rfc822; bob@foobar.org\r\n");
|
||||
body.extend_from_slice(b"Action: failed\r\nStatus: 5.1.1\r\n");
|
||||
body.extend_from_slice(b"--BOUNDARY\r\nContent-Type: message/rfc822\r\n\r\n");
|
||||
body.extend_from_slice(returned);
|
||||
body.extend_from_slice(b"\r\n--BOUNDARY--\r\n");
|
||||
|
||||
let mut dsn = Vec::new();
|
||||
dsn.extend_from_slice(b"From: postmaster@foobar.org\r\n");
|
||||
dsn.extend_from_slice(b"To: john@example.com\r\n");
|
||||
dsn.extend_from_slice(b"Subject: Delivery Status Notification (Failure)\r\n");
|
||||
dsn.extend_from_slice(b"Date: Sat, 01 Mar 2026 12:05:00 +0000\r\n");
|
||||
dsn.extend_from_slice(b"Message-ID: <dsn@foobar.org>\r\n");
|
||||
dsn.extend_from_slice(
|
||||
b"Content-Type: multipart/report; report-type=delivery-status; boundary=\"BOUNDARY\"\r\n\r\n",
|
||||
);
|
||||
dsn.extend_from_slice(&body);
|
||||
|
||||
if sign_dsn {
|
||||
dkim2_sign("foobar.org", "ed", &dsn, "<>", &["john@example.com"])
|
||||
} else {
|
||||
dsn
|
||||
}
|
||||
}
|
||||
|
||||
fn ed25519_key() -> Ed25519Key {
|
||||
let der = STANDARD
|
||||
.decode("MC4CAQAwBQYDK2VwBCIEIIOQVf8MDGvvmIkpUbgoqtyUIxjlzRqaBR6aP12tcGGE")
|
||||
.unwrap();
|
||||
Ed25519Key::from_pkcs8_maybe_unchecked_der(&der).unwrap()
|
||||
}
|
||||
|
||||
fn dkim2_sign(
|
||||
domain: &str,
|
||||
selector: &str,
|
||||
message: &[u8],
|
||||
mail_from: &str,
|
||||
rcpt_to: &[&str],
|
||||
) -> Vec<u8> {
|
||||
let signed = Dkim2Signer::from_key(ed25519_key())
|
||||
.domain(domain)
|
||||
.selector(selector)
|
||||
.sign(message, Hop::real(mail_from, rcpt_to))
|
||||
.expect("dkim2 sign");
|
||||
let mut out = signed.to_header().into_bytes();
|
||||
out.extend_from_slice(message);
|
||||
out
|
||||
}
|
||||
|
||||
const RETURNED_PLAIN: &str = concat!(
|
||||
"From: John Doe <john@example.com>\r\n",
|
||||
"To: Bob <bob@foobar.org>\r\n",
|
||||
"Subject: Original message\r\n",
|
||||
"Date: Sat, 01 Mar 2026 12:00:00 +0000\r\n",
|
||||
"Message-ID: <original@example.com>\r\n",
|
||||
"\r\n",
|
||||
"DKIM2-ORIGINAL-BODY-CONTENT\r\n",
|
||||
);
|
||||
|
||||
struct Delivered {
|
||||
recipients: Vec<String>,
|
||||
body: String,
|
||||
}
|
||||
|
||||
async fn deliver_and_collect(
|
||||
local: &mut TestServer,
|
||||
remote: &TestServer,
|
||||
from: &str,
|
||||
rcpts: &[&str],
|
||||
raw: &str,
|
||||
expected: usize,
|
||||
) -> Vec<Delivered> {
|
||||
let mut session = local.new_mta_session();
|
||||
session.data.remote_ip_str = "10.0.0.1".into();
|
||||
session.eval_session_params().await;
|
||||
session.ehlo("mx.example.com").await;
|
||||
session.send_message(from, rcpts, raw, "250").await;
|
||||
|
||||
local
|
||||
.expect_message_then_deliver()
|
||||
.await
|
||||
.try_deliver(local.server.clone());
|
||||
|
||||
let mut delivered = Vec::new();
|
||||
for _ in 0..expected {
|
||||
let mut waited = 0;
|
||||
let msg = loop {
|
||||
if let Some(msg) = remote.read_queued_messages().await.into_iter().next() {
|
||||
break msg;
|
||||
}
|
||||
assert!(waited < 100, "timed out waiting for a delivered message");
|
||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||
waited += 1;
|
||||
};
|
||||
let body = msg.read_message(remote).await;
|
||||
let mut recipients = msg
|
||||
.message
|
||||
.recipients
|
||||
.iter()
|
||||
.map(|r| r.address().to_string())
|
||||
.collect::<Vec<_>>();
|
||||
recipients.sort();
|
||||
let due = remote.message_due(msg.queue_id).await;
|
||||
msg.clone().remove(&remote.server, due.into()).await;
|
||||
delivered.push(Delivered { recipients, body });
|
||||
}
|
||||
|
||||
delivered
|
||||
}
|
||||
|
||||
fn rt_token(address: &str) -> String {
|
||||
STANDARD.encode(format!("<{address}>"))
|
||||
}
|
||||
|
||||
fn without_whitespace(value: &str) -> String {
|
||||
value.chars().filter(|c| !c.is_whitespace()).collect()
|
||||
}
|
||||
|
||||
fn dkim_dns_record() -> DomainKey {
|
||||
DomainKey::parse(format!("v=DKIM1; k=ed25519; p={ED_PUBLIC}").as_bytes()).unwrap()
|
||||
}
|
||||
|
||||
fn valid() -> Instant {
|
||||
Instant::now() + Duration::from_secs(300)
|
||||
}
|
||||
|
||||
fn expr(value: &str) -> Expression {
|
||||
Expression {
|
||||
else_: value.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ pub mod asn;
|
||||
pub mod auth;
|
||||
pub mod basic;
|
||||
pub mod data;
|
||||
pub mod dkim2;
|
||||
pub mod dmarc;
|
||||
pub mod ehlo;
|
||||
pub mod limits;
|
||||
|
||||
Reference in New Issue
Block a user