fix: read back sent copies after the sec 5.6 upstream fix, pinned at 2d65d66
This commit is contained in:
parent
52947e153d
commit
d6f4c434fa
36 changed files with 4223 additions and 3118 deletions
738
native/Cargo.lock
generated
Normal file
738
native/Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,738 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes-gcm"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"aes",
|
||||
"cipher",
|
||||
"ctr",
|
||||
"ghash",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f360145194ee8e21db5ee7f3fcd4fe52210864c75c985dae33218202c8bbe040"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
||||
|
||||
[[package]]
|
||||
name = "chacha20"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chacha20poly1305"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"chacha20",
|
||||
"cipher",
|
||||
"poly1305",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctr"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "4.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"curve25519-dalek-derive",
|
||||
"digest",
|
||||
"fiat-crypto",
|
||||
"rustc_version",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek-derive"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06"
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519"
|
||||
version = "2.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||
dependencies = [
|
||||
"pkcs8",
|
||||
"signature",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519-dalek"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"ed25519",
|
||||
"rand_core",
|
||||
"serde",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "fiat-crypto"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484"
|
||||
|
||||
[[package]]
|
||||
name = "fumi-core"
|
||||
version = "0.1.0"
|
||||
source = "git+ssh://git@code.randogoth.com:2222/randogoth/fumi.git?rev=2d65d66#2d65d66012fa40121e4dc3d8d15db9ffc486569a"
|
||||
dependencies = [
|
||||
"chacha20poly1305",
|
||||
"data-encoding",
|
||||
"ed25519-dalek",
|
||||
"hkdf",
|
||||
"hmac",
|
||||
"rand_core",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"snow",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ghash"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
|
||||
dependencies = [
|
||||
"opaque-debug",
|
||||
"polyval",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
|
||||
dependencies = [
|
||||
"hmac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
||||
dependencies = [
|
||||
"der",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548"
|
||||
|
||||
[[package]]
|
||||
name = "poly1305"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
|
||||
dependencies = [
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polyval"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.32.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e"
|
||||
|
||||
[[package]]
|
||||
name = "smol_mail_native"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"data-encoding",
|
||||
"fumi-core",
|
||||
"rand_core",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "snow"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"blake2",
|
||||
"chacha20poly1305",
|
||||
"curve25519-dalek",
|
||||
"rand_core",
|
||||
"rustc_version",
|
||||
"sha2",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "x25519-dalek"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"rand_core",
|
||||
"serde",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6df92bf3d9227be3d53173901ddbffac2babc27ae50f397776ffd6dc33f800cb"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac4f328cf2f05d084e496c3e9c3f33ed0a183656a16e1fcec4d464d8373aec82"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
||||
14
native/Cargo.toml
Normal file
14
native/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "smol_mail_native"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "cdylib"]
|
||||
|
||||
[dependencies]
|
||||
fumi-core = { git = "ssh://git@code.randogoth.com:2222/randogoth/fumi.git", rev = "2d65d66" }
|
||||
rand_core = { version = "0.6", features = ["getrandom"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
data-encoding = "2"
|
||||
17
native/src/bin/dnsprobe.rs
Normal file
17
native/src/bin/dnsprobe.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Device probe: reproduce the app's DNS failure in isolation. Resolves
|
||||
// the given host exactly the way fumi-core's connect does — Rust std's
|
||||
// getaddrinfo — and prints what came back.
|
||||
|
||||
use std::net::ToSocketAddrs;
|
||||
|
||||
fn main() {
|
||||
let host = std::env::args().nth(1).unwrap_or_else(|| "example.com".into());
|
||||
let target = format!("{host}:1961");
|
||||
match target.to_socket_addrs() {
|
||||
Ok(addrs) => {
|
||||
let ips: Vec<String> = addrs.map(|a| a.to_string()).collect();
|
||||
println!("resolved {host}: {ips:?}");
|
||||
}
|
||||
Err(err) => println!("FAILED {host}: {err}"),
|
||||
}
|
||||
}
|
||||
1205
native/src/ffi.rs
Normal file
1205
native/src/ffi.rs
Normal file
File diff suppressed because it is too large
Load diff
450
native/src/lib.rs
Normal file
450
native/src/lib.rs
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
// C ABI over fumi-core for the Dart FFI binding; the app links the cdylib.
|
||||
// One smoke function for the spike; the real surface lives in `ffi`.
|
||||
|
||||
pub mod ffi;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use fumi_core::{account::Identity, message};
|
||||
use rand_core::{OsRng, RngCore};
|
||||
use std::time::Instant;
|
||||
|
||||
#[test]
|
||||
fn store_round_trip() {
|
||||
assert_eq!(crate::ffi::smol_smoke(), 0);
|
||||
}
|
||||
|
||||
/// Spike benchmark: seal/unseal throughput with a 2 KiB body, to compare
|
||||
/// against the Dart core's numbers (test/perf_smoke_test.dart). Print
|
||||
/// only; the assertions pin correctness, not speed.
|
||||
#[test]
|
||||
fn envelope_perf() {
|
||||
let mut seed = [0u8; 32];
|
||||
OsRng.fill_bytes(&mut seed);
|
||||
let sender = Identity::from_seed(seed);
|
||||
OsRng.fill_bytes(&mut seed);
|
||||
let recipient = Identity::from_seed(seed);
|
||||
let body = vec![b'x'; 2048];
|
||||
const N: usize = 100;
|
||||
|
||||
let t0 = Instant::now();
|
||||
let envelopes: Vec<Vec<u8>> = (0..N)
|
||||
.map(|i| message::seal(&sender, &recipient.pk(), &body, i as i64, true).unwrap())
|
||||
.collect();
|
||||
let seal_dt = t0.elapsed();
|
||||
|
||||
let t1 = Instant::now();
|
||||
for (i, envelope) in envelopes.iter().enumerate() {
|
||||
let opened = message::unseal(&[recipient.clone()], envelope, 0).unwrap();
|
||||
assert_eq!(opened.body.len(), 2048);
|
||||
assert_eq!(opened.sender, sender.pk());
|
||||
assert_eq!(opened.time, i as i64);
|
||||
}
|
||||
let open_dt = t1.elapsed();
|
||||
|
||||
println!(
|
||||
"rust: seal {N} in {seal_dt:?} ({:.0} us/msg), unseal {N} in {open_dt:?} ({:.0} us/msg)",
|
||||
seal_dt.as_micros() as f64 / N as f64,
|
||||
open_dt.as_micros() as f64 / N as f64,
|
||||
);
|
||||
}
|
||||
|
||||
/// Spike round-trip against a live bunshin on 127.0.0.1:19619; ignored
|
||||
/// because it needs the server (bunshin serve --key ... --port 19619).
|
||||
/// Covers the embeddable path end to end: pin, REGISTER, SEND, FETCH.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn bunshin_round_trip() {
|
||||
use fumi_core::account::Account;
|
||||
use fumi_core::address::Address;
|
||||
use fumi_core::client::{fetch, register, send, SendDraft};
|
||||
use fumi_core::crypto::unb32;
|
||||
use fumi_core::store::Store;
|
||||
use fumi_core::transport::KEY_LEN;
|
||||
use rand_core::{OsRng, RngCore};
|
||||
|
||||
let server: [u8; KEY_LEN] = unb32(
|
||||
"g5ttsssqjq6j37vso3h7otn33zrk6o6r7c6jjm7guxbbijoa5nqq",
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let mut master = [0u8; 32];
|
||||
let mut identity = || {
|
||||
OsRng.fill_bytes(&mut master);
|
||||
(Store::open_in_memory().unwrap(), Account::new(master, 0).unwrap())
|
||||
};
|
||||
let (alice_store, alice) = identity();
|
||||
let (bob_store, bob) = identity();
|
||||
|
||||
// Random usernames: the server persists registrations, so fixed ones
|
||||
// would collide on the second run of this test.
|
||||
let mut suffix = [0u8; 2];
|
||||
OsRng.fill_bytes(&mut suffix);
|
||||
let run = fumi_core::crypto::b32(&suffix);
|
||||
let alice_addr =
|
||||
Address::parse(&format!("a{run}@127.0.0.1:19619")).unwrap();
|
||||
let bob_addr = Address::parse(&format!("b{run}@127.0.0.1:19619")).unwrap();
|
||||
alice_store.pin_server("127.0.0.1", &server).unwrap();
|
||||
bob_store.pin_server("127.0.0.1", &server).unwrap();
|
||||
|
||||
register(&alice_store, &alice_addr, &alice, None, 5).unwrap();
|
||||
register(&bob_store, &bob_addr, &bob, None, 5).unwrap();
|
||||
|
||||
let draft = SendDraft {
|
||||
address: &bob_addr,
|
||||
text: "spike: hello over fumi".into(),
|
||||
subject: Some("spike"),
|
||||
reply_to: None,
|
||||
headers: &[],
|
||||
anonymous: false,
|
||||
no_pad: false,
|
||||
};
|
||||
let sent = send(&alice_store, &alice, &draft, 5).unwrap();
|
||||
assert_eq!(sent.warning, None);
|
||||
|
||||
let fetched = fetch(&bob_store, &bob, false, false, 5).unwrap();
|
||||
assert_eq!(fetched.stored, 1);
|
||||
// First contact without an accept token lands in the requests tier
|
||||
// (sec 5.8), not the inbox.
|
||||
let stored = &bob_store.mail("requests").unwrap()[0];
|
||||
let opened = fumi_core::client::describe(&bob_store, &bob, stored).unwrap();
|
||||
assert_eq!(opened.text, "spike: hello over fumi");
|
||||
assert_eq!(opened.subject, "spike");
|
||||
assert_eq!(opened.sender, alice.keys()[0].pk());
|
||||
assert_eq!(opened.from, alice_addr.short());
|
||||
|
||||
// sec 5.6, the cross-recipient case self-sends mask: the sent copy
|
||||
// is sealed to the sender's own key, so alice can read back what she
|
||||
// sent to bob even though bob's envelope used a discarded ephemeral.
|
||||
let sent = &alice_store.mail("sent").unwrap()[0];
|
||||
let reread =
|
||||
fumi_core::client::describe(&alice_store, &alice, sent).unwrap();
|
||||
assert_eq!(reread.text, "spike: hello over fumi");
|
||||
assert_eq!(reread.subject, "spike");
|
||||
}
|
||||
|
||||
/// Spike: cancellation and resume, against the same live bunshin. Four
|
||||
/// ~400 KiB envelopes exceed the server's 512 KiB fetch budget, so each
|
||||
/// page carries one message and the between-page cancel check is
|
||||
/// reachable. Phase A is deterministic (flag pre-set); phase B cancels
|
||||
/// from a watcher thread the moment the first message commits — which is
|
||||
/// also the concurrent-reader check, since the store is read while the
|
||||
/// fetch holds it.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn bunshin_cancel_and_resume() {
|
||||
use fumi_core::account::Account;
|
||||
use fumi_core::address::Address;
|
||||
use fumi_core::client::{fetch, fetch_with, register, send, FetchOptions, SendDraft};
|
||||
use fumi_core::crypto::unb32;
|
||||
use fumi_core::store::Store;
|
||||
use fumi_core::transport::KEY_LEN;
|
||||
use rand_core::{OsRng, RngCore};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
let server: [u8; KEY_LEN] = unb32(
|
||||
"g5ttsssqjq6j37vso3h7otn33zrk6o6r7c6jjm7guxbbijoa5nqq",
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let mut master = [0u8; 32];
|
||||
let mut identity = || {
|
||||
OsRng.fill_bytes(&mut master);
|
||||
(Store::open_in_memory().unwrap(), Account::new(master, 0).unwrap())
|
||||
};
|
||||
let (alice_store, alice) = identity();
|
||||
let bob_store = Arc::new(Store::open_in_memory().unwrap());
|
||||
let mut bob_master = [0u8; 32];
|
||||
OsRng.fill_bytes(&mut bob_master);
|
||||
let bob = Account::new(bob_master, 0).unwrap();
|
||||
|
||||
let mut suffix = [0u8; 2];
|
||||
OsRng.fill_bytes(&mut suffix);
|
||||
let run = fumi_core::crypto::b32(&suffix);
|
||||
let alice_addr = Address::parse(&format!("a{run}@127.0.0.1:19619")).unwrap();
|
||||
let bob_addr = Address::parse(&format!("b{run}@127.0.0.1:19619")).unwrap();
|
||||
alice_store.pin_server("127.0.0.1", &server).unwrap();
|
||||
bob_store.pin_server("127.0.0.1", &server).unwrap();
|
||||
register(&alice_store, &alice_addr, &alice, None, 5).unwrap();
|
||||
register(&bob_store, &bob_addr, &bob, None, 5).unwrap();
|
||||
|
||||
let big = "x".repeat(400 * 1024);
|
||||
for i in 0..4 {
|
||||
let draft = SendDraft {
|
||||
address: &bob_addr,
|
||||
text: format!("{i}\n{big}"),
|
||||
subject: None,
|
||||
reply_to: None,
|
||||
headers: &[],
|
||||
anonymous: false,
|
||||
no_pad: false,
|
||||
};
|
||||
send(&alice_store, &alice, &draft, 5).unwrap();
|
||||
}
|
||||
|
||||
// Phase A: the flag is checked before the first page, so nothing is
|
||||
// fetched and nothing is acknowledged.
|
||||
let cancel = AtomicBool::new(true);
|
||||
let a = fetch_with(
|
||||
&bob_store,
|
||||
&bob,
|
||||
FetchOptions {
|
||||
keep: false,
|
||||
reset: false,
|
||||
dial: None,
|
||||
timeout: 5,
|
||||
cancel: Some(&cancel),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
assert!(a.cancelled);
|
||||
assert_eq!(a.stored, 0);
|
||||
|
||||
// Phase B: a reader thread watches the store fill and raises the
|
||||
// flag after the first commit; the fetch stops between pages.
|
||||
cancel.store(false, Ordering::Relaxed);
|
||||
let flag = Arc::new(AtomicBool::new(false));
|
||||
let thread_flag = Arc::clone(&flag);
|
||||
let watcher_store = Arc::clone(&bob_store);
|
||||
let watcher = std::thread::spawn(move || {
|
||||
while watcher_store.mail("all").unwrap().len() < 1 {
|
||||
std::thread::sleep(std::time::Duration::from_millis(1));
|
||||
}
|
||||
thread_flag.store(true, Ordering::Relaxed);
|
||||
});
|
||||
let b = fetch_with(
|
||||
&bob_store,
|
||||
&bob,
|
||||
FetchOptions {
|
||||
keep: false,
|
||||
reset: false,
|
||||
dial: None,
|
||||
timeout: 5,
|
||||
cancel: Some(&flag),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
assert!(b.cancelled, "watcher should have raised the flag mid-fetch");
|
||||
assert!(b.stored >= 1 && b.stored < 4);
|
||||
watcher.join().unwrap();
|
||||
|
||||
// Resume: an uncancelled fetch delivers the rest, and the seen-id
|
||||
// set keeps the acknowledged pages from coming back as duplicates.
|
||||
let c = fetch(&bob_store, &bob, false, false, 5).unwrap();
|
||||
assert_eq!(b.stored + c.stored, 4);
|
||||
assert_eq!(bob_store.mail("all").unwrap().len(), 4);
|
||||
}
|
||||
|
||||
/// The Android regression: a hostname the native resolver cannot
|
||||
/// resolve (the device's getaddrinfo is dead for app processes), pinned
|
||||
/// by name, dialed by the IP the app resolved itself. Registration must
|
||||
/// succeed and the account must keep the hostname identity.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn bunshin_dial_hint_routes_by_ip() {
|
||||
use fumi_core::client::register;
|
||||
use fumi_core::crypto::unb32;
|
||||
use fumi_core::store::Store;
|
||||
use fumi_core::transport::KEY_LEN;
|
||||
use rand_core::{OsRng, RngCore};
|
||||
|
||||
let server: [u8; KEY_LEN] = unb32(
|
||||
"g5ttsssqjq6j37vso3h7otn33zrk6o6r7c6jjm7guxbbijoa5nqq",
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let mut master = [0u8; 32];
|
||||
OsRng.fill_bytes(&mut master);
|
||||
let store = Store::open_in_memory().unwrap();
|
||||
let account = fumi_core::account::Account::new(master, 0).unwrap();
|
||||
|
||||
let mut suffix = [0u8; 2];
|
||||
OsRng.fill_bytes(&mut suffix);
|
||||
let run = fumi_core::crypto::b32(&suffix);
|
||||
let host = format!("unresolvable-{run}.invalid");
|
||||
let addr =
|
||||
fumi_core::address::Address::parse(&format!("u{run}@{host}:19619"))
|
||||
.unwrap()
|
||||
.with_dial("127.0.0.1");
|
||||
store.pin_server(&host, &server).unwrap();
|
||||
register(&store, &addr, &account, None, 5).unwrap();
|
||||
assert_eq!(store.account().unwrap().unwrap().short(),
|
||||
format!("u{run}@{host}:19619"));
|
||||
}
|
||||
|
||||
/// Spike: the error variants the onboarding routes on. No pin and a
|
||||
/// wrong pin are distinct and matchable — the two branches that decide
|
||||
/// whether the register step frames itself as "pin the key" (§4) or
|
||||
/// aborts. Needs the live bunshin but changes no server state.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn bunshin_pin_errors() {
|
||||
use fumi_core::address::Address;
|
||||
use fumi_core::client::connect;
|
||||
use fumi_core::error::Error;
|
||||
use fumi_core::store::Store;
|
||||
use fumi_core::transport::KEY_LEN;
|
||||
use rand_core::{OsRng, RngCore};
|
||||
|
||||
let addr = Address::parse("nobody@127.0.0.1:19619").unwrap();
|
||||
|
||||
let unpinned = Store::open_in_memory().unwrap();
|
||||
match connect(&unpinned, &addr, true, 5) {
|
||||
Err(Error::NotPinned { host }) => assert_eq!(host, "127.0.0.1"),
|
||||
Err(err) => panic!("expected NotPinned, got {err}"),
|
||||
Ok(_) => panic!("expected NotPinned, connected"),
|
||||
}
|
||||
|
||||
let mut wrong = [0u8; KEY_LEN];
|
||||
OsRng.fill_bytes(&mut wrong);
|
||||
let mismatched = Store::open_in_memory().unwrap();
|
||||
mismatched.pin_server("127.0.0.1", &wrong).unwrap();
|
||||
match connect(&mismatched, &addr, true, 5) {
|
||||
Err(Error::PinMismatch { .. }) => {}
|
||||
Err(err) => panic!("expected PinMismatch, got {err}"),
|
||||
Ok(_) => panic!("expected PinMismatch, connected"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Spike, bright path: a real rotation validates through the chain and
|
||||
/// surfaces as `TrustChange::Rotated` — a warning, not an error. Carol
|
||||
/// registers, Alice learns her key by sending, Carol rotates, and
|
||||
/// Alice's next resolve walks the chain the server returns.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn bunshin_rotation_bright() {
|
||||
use fumi_core::account::Account;
|
||||
use fumi_core::address::Address;
|
||||
use fumi_core::client::{connect, register, rotate, send, trust_key, SendDraft};
|
||||
use fumi_core::crypto::unb32;
|
||||
use fumi_core::store::Store;
|
||||
use fumi_core::transport::KEY_LEN;
|
||||
use rand_core::{OsRng, RngCore};
|
||||
|
||||
let server: [u8; KEY_LEN] = unb32(
|
||||
"g5ttsssqjq6j37vso3h7otn33zrk6o6r7c6jjm7guxbbijoa5nqq",
|
||||
)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let mut carol_master = [0u8; 32];
|
||||
OsRng.fill_bytes(&mut carol_master);
|
||||
let mut alice_master = [0u8; 32];
|
||||
OsRng.fill_bytes(&mut alice_master);
|
||||
let carol_store = Store::open_in_memory().unwrap();
|
||||
let alice_store = Store::open_in_memory().unwrap();
|
||||
let carol = Account::new(carol_master, 0).unwrap();
|
||||
let alice = Account::new(alice_master, 0).unwrap();
|
||||
|
||||
let mut suffix = [0u8; 2];
|
||||
OsRng.fill_bytes(&mut suffix);
|
||||
let run = fumi_core::crypto::b32(&suffix);
|
||||
let carol_addr = Address::parse(&format!("c{run}@127.0.0.1:19619")).unwrap();
|
||||
let alice_addr = Address::parse(&format!("d{run}@127.0.0.1:19619")).unwrap();
|
||||
carol_store.pin_server("127.0.0.1", &server).unwrap();
|
||||
alice_store.pin_server("127.0.0.1", &server).unwrap();
|
||||
register(&carol_store, &carol_addr, &carol, None, 5).unwrap();
|
||||
register(&alice_store, &alice_addr, &alice, None, 5).unwrap();
|
||||
|
||||
let draft = SendDraft {
|
||||
address: &carol_addr,
|
||||
text: "before the rotation".into(),
|
||||
subject: None,
|
||||
reply_to: None,
|
||||
headers: &[],
|
||||
anonymous: false,
|
||||
no_pad: false,
|
||||
};
|
||||
let sent = send(&alice_store, &alice, &draft, 5).unwrap();
|
||||
assert!(matches!(
|
||||
sent.change,
|
||||
fumi_core::client::TrustChange::New { unverified: false }
|
||||
));
|
||||
|
||||
rotate(&carol_store, &carol, None, 5).unwrap();
|
||||
let carol_next = Account::new(carol_master, 1).unwrap();
|
||||
|
||||
let mut session = connect(&alice_store, &carol_addr, true, 5).unwrap();
|
||||
let (pk, change) = {
|
||||
let transport = session.transport();
|
||||
trust_key(&alice_store, transport, &carol_addr).unwrap()
|
||||
};
|
||||
session.close();
|
||||
assert!(matches!(change, fumi_core::client::TrustChange::Rotated));
|
||||
assert_eq!(pk, carol_next.me().pk());
|
||||
}
|
||||
|
||||
/// Spike, dark twin: RESOLVE returns a key with no chain to the one we
|
||||
/// hold — the state a hijacked or re-registered username produces, and
|
||||
/// the branch the onboarding must treat as terminal until the user
|
||||
/// verifies out of band. A mock transport stands in for the server, so
|
||||
/// this needs no live bunshin.
|
||||
#[test]
|
||||
fn keychanged_dark_twin() {
|
||||
use fumi_core::address::Address;
|
||||
use fumi_core::client::trust_key;
|
||||
use fumi_core::error::Error;
|
||||
use fumi_core::store::Store;
|
||||
use fumi_core::transport::{
|
||||
Response, Transport, TransportBindValues, KEY_LEN, OP_RESOLVE,
|
||||
};
|
||||
use rand_core::{OsRng, RngCore};
|
||||
|
||||
struct MockResolve {
|
||||
offered: [u8; KEY_LEN],
|
||||
bind: TransportBindValues,
|
||||
}
|
||||
impl Transport for MockResolve {
|
||||
fn request(&mut self, op: u8, _body: &[u8]) -> Result<Response, Error> {
|
||||
assert_eq!(op, OP_RESOLVE);
|
||||
let mut body = Vec::with_capacity(KEY_LEN + 1);
|
||||
body.extend_from_slice(&self.offered);
|
||||
body.push(0); // no chain at all
|
||||
Ok(Response { status: 0, body })
|
||||
}
|
||||
fn bind(&self) -> &TransportBindValues {
|
||||
&self.bind
|
||||
}
|
||||
fn pinned(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn close(&mut self) {}
|
||||
}
|
||||
|
||||
let addr = Address::parse("dark@127.0.0.1:19619").unwrap();
|
||||
let mut known = [0u8; KEY_LEN];
|
||||
OsRng.fill_bytes(&mut known);
|
||||
let mut offered = [0u8; KEY_LEN];
|
||||
OsRng.fill_bytes(&mut offered);
|
||||
|
||||
let store = Store::open_in_memory().unwrap();
|
||||
store.save_contact(&addr.short(), &known, false).unwrap();
|
||||
let mut mock = MockResolve {
|
||||
offered,
|
||||
bind: TransportBindValues {
|
||||
h: [0u8; 32],
|
||||
server_static: [0u8; 32],
|
||||
},
|
||||
};
|
||||
match trust_key(&store, &mut mock, &addr) {
|
||||
Err(Error::KeyChanged {
|
||||
address,
|
||||
known: k,
|
||||
offered: o,
|
||||
}) => {
|
||||
assert_eq!(address, addr.short());
|
||||
assert_eq!(k, known);
|
||||
assert_eq!(o, offered);
|
||||
}
|
||||
Err(err) => panic!("expected KeyChanged, got {err}"),
|
||||
Ok(_) => panic!("expected KeyChanged, trusted the new key"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue