feat: enable Matrix E2EE with cross-signing verification on bot
Add end-to-end encryption support to the Matrix bot using the matrix-sdk crypto features. The bot now: - Enables E2EE on the Matrix client with cross-signing bootstrapping - Auto-verifies its own cross-signing identity on startup - Handles key verification requests from other users automatically - Sends encrypted messages in E2EE-enabled rooms - Adds MATRIX_STORE_PATH config for persistent crypto store Squash merge of feature/story-194_story_enable_matrix_e2ee_with_cross_signing_verification_on_bot Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
353
Cargo.lock
generated
353
Cargo.lock
generated
@@ -2,6 +2,18 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "accessory"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28e416a3ab45838bac2ab2d81b1088d738d7b2d2c5272a54d39366565a29bd80"
|
||||||
|
dependencies = [
|
||||||
|
"macroific",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.116",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler2"
|
name = "adler2"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
@@ -283,6 +295,15 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bs58"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
version = "1.12.1"
|
version = "1.12.1"
|
||||||
@@ -299,6 +320,12 @@ version = "3.19.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "0.5.6"
|
version = "0.5.6"
|
||||||
@@ -575,6 +602,15 @@ dependencies = [
|
|||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctr"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "curve25519-dalek"
|
name = "curve25519-dalek"
|
||||||
version = "4.1.3"
|
version = "4.1.3"
|
||||||
@@ -690,6 +726,20 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "delegate-display"
|
||||||
|
version = "3.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9926686c832494164c33a36bf65118f4bd6e704000b58c94681bf62e9ad67a74"
|
||||||
|
dependencies = [
|
||||||
|
"impartial-ord",
|
||||||
|
"itoa",
|
||||||
|
"macroific",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.116",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "der"
|
name = "der"
|
||||||
version = "0.7.10"
|
version = "0.7.10"
|
||||||
@@ -709,13 +759,44 @@ dependencies = [
|
|||||||
"powerfmt",
|
"powerfmt",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derivative"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
|
||||||
|
dependencies = [
|
||||||
|
"derive_more-impl 1.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
|
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more-impl",
|
"derive_more-impl 2.1.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more-impl"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.116",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -893,6 +974,18 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fancy_constructor"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28a27643a5d05f3a22f5afd6e0d0e6e354f92d37907006f97b84b9cb79082198"
|
||||||
|
dependencies = [
|
||||||
|
"macroific",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.116",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
@@ -1179,6 +1272,19 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gloo-utils"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "growable-bloom-filter"
|
name = "growable-bloom-filter"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
@@ -1623,6 +1729,17 @@ dependencies = [
|
|||||||
"bitmaps",
|
"bitmaps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "impartial-ord"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ab604ee7085efba6efc65e4ebca0e9533e3aff6cb501d7d77b211e3a781c6d5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.116",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "include_dir"
|
name = "include_dir"
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
@@ -1908,6 +2025,54 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "macroific"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89f276537b4b8f981bf1c13d79470980f71134b7bdcc5e6e911e910e556b0285"
|
||||||
|
dependencies = [
|
||||||
|
"macroific_attr_parse",
|
||||||
|
"macroific_core",
|
||||||
|
"macroific_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "macroific_attr_parse"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad4023761b45fcd36abed8fb7ae6a80456b0a38102d55e89a57d9a594a236be9"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"sealed",
|
||||||
|
"syn 2.0.116",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "macroific_core"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0a7594d3c14916fa55bef7e9d18c5daa9ed410dd37504251e4b75bbdeec33e3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"sealed",
|
||||||
|
"syn 2.0.116",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "macroific_macro"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4da6f2ed796261b0a74e2b52b42c693bb6dee1effba3a482c49592659f824b3b"
|
||||||
|
dependencies = [
|
||||||
|
"macroific_attr_parse",
|
||||||
|
"macroific_core",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.116",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "maplit"
|
name = "maplit"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@@ -1989,6 +2154,7 @@ dependencies = [
|
|||||||
"language-tags",
|
"language-tags",
|
||||||
"matrix-sdk-base",
|
"matrix-sdk-base",
|
||||||
"matrix-sdk-common",
|
"matrix-sdk-common",
|
||||||
|
"matrix-sdk-indexeddb",
|
||||||
"matrix-sdk-sqlite",
|
"matrix-sdk-sqlite",
|
||||||
"mime",
|
"mime",
|
||||||
"mime2ext",
|
"mime2ext",
|
||||||
@@ -2029,6 +2195,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"growable-bloom-filter",
|
"growable-bloom-filter",
|
||||||
"matrix-sdk-common",
|
"matrix-sdk-common",
|
||||||
|
"matrix-sdk-crypto",
|
||||||
"matrix-sdk-store-encryption",
|
"matrix-sdk-store-encryption",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"regex",
|
"regex",
|
||||||
@@ -2061,9 +2228,83 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrix-sdk-crypto"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "304fc576810a9618bb831c4ad6403c758ec424f677668a49a196e3cde4b8f99f"
|
||||||
|
dependencies = [
|
||||||
|
"aes",
|
||||||
|
"aquamarine",
|
||||||
|
"as_variant",
|
||||||
|
"async-trait",
|
||||||
|
"bs58",
|
||||||
|
"byteorder",
|
||||||
|
"cfg-if",
|
||||||
|
"ctr",
|
||||||
|
"eyeball",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"hkdf",
|
||||||
|
"hmac",
|
||||||
|
"itertools 0.14.0",
|
||||||
|
"js_option",
|
||||||
|
"matrix-sdk-common",
|
||||||
|
"pbkdf2",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"rmp-serde",
|
||||||
|
"ruma",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
|
"subtle",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"time",
|
||||||
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
|
"tracing",
|
||||||
|
"ulid",
|
||||||
|
"url",
|
||||||
|
"vodozemac",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrix-sdk-indexeddb"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b6096084cc8d339c03e269ca25534d0f1e88d0097c35a215eb8c311797ec3e9"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"base64",
|
||||||
|
"futures-util",
|
||||||
|
"getrandom 0.2.17",
|
||||||
|
"gloo-utils",
|
||||||
|
"hkdf",
|
||||||
|
"js-sys",
|
||||||
|
"matrix-sdk-base",
|
||||||
|
"matrix-sdk-crypto",
|
||||||
|
"matrix-sdk-store-encryption",
|
||||||
|
"matrix_indexed_db_futures",
|
||||||
|
"rmp-serde",
|
||||||
|
"ruma",
|
||||||
|
"serde",
|
||||||
|
"serde-wasm-bindgen",
|
||||||
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"uuid",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matrix-sdk-sqlite"
|
name = "matrix-sdk-sqlite"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
@@ -2076,6 +2317,7 @@ dependencies = [
|
|||||||
"deadpool-sync",
|
"deadpool-sync",
|
||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
"matrix-sdk-base",
|
"matrix-sdk-base",
|
||||||
|
"matrix-sdk-crypto",
|
||||||
"matrix-sdk-store-encryption",
|
"matrix-sdk-store-encryption",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
@@ -2100,6 +2342,7 @@ dependencies = [
|
|||||||
"base64",
|
"base64",
|
||||||
"blake3",
|
"blake3",
|
||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
|
"getrandom 0.2.17",
|
||||||
"hmac",
|
"hmac",
|
||||||
"pbkdf2",
|
"pbkdf2",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
@@ -2111,6 +2354,45 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrix_indexed_db_futures"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "245ff6a224b4df7b0c90dda2dd5a6eb46112708d49e8bdd8b007fccb09fea8e4"
|
||||||
|
dependencies = [
|
||||||
|
"accessory",
|
||||||
|
"cfg-if",
|
||||||
|
"delegate-display",
|
||||||
|
"derive_more 2.1.1",
|
||||||
|
"fancy_constructor",
|
||||||
|
"futures-core",
|
||||||
|
"js-sys",
|
||||||
|
"matrix_indexed_db_futures_macros_internal",
|
||||||
|
"sealed",
|
||||||
|
"serde",
|
||||||
|
"serde-wasm-bindgen",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"tokio",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"wasm_evt_listener",
|
||||||
|
"web-sys",
|
||||||
|
"web-time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrix_indexed_db_futures_macros_internal"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b428aee5c0fe9e5babd29e99d289b7f64718c444989aac0442d1fd6d3e3f66d1"
|
||||||
|
dependencies = [
|
||||||
|
"macroific",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.116",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.8.0"
|
version = "2.8.0"
|
||||||
@@ -2596,7 +2878,7 @@ checksum = "1ccbcc395bf4dd03df1da32da351b6b6732e4074ce27ddec315650e52a2be44c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bytes 1.11.1",
|
"bytes 1.11.1",
|
||||||
"derive_more",
|
"derive_more 2.1.1",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
@@ -3175,6 +3457,7 @@ dependencies = [
|
|||||||
"getrandom 0.2.17",
|
"getrandom 0.2.17",
|
||||||
"http",
|
"http",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"js-sys",
|
||||||
"js_int",
|
"js_int",
|
||||||
"konst",
|
"konst",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
@@ -3482,6 +3765,17 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sealed"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22f968c5ea23d555e670b449c1c5e7b2fc399fdaec1d304a17cd48e288abc107"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.116",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "3.6.0"
|
version = "3.6.0"
|
||||||
@@ -3521,6 +3815,17 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde-wasm-bindgen"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"serde",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_bytes"
|
name = "serde_bytes"
|
||||||
version = "0.11.19"
|
version = "0.11.19"
|
||||||
@@ -3724,6 +4029,9 @@ name = "smallvec"
|
|||||||
version = "1.15.1"
|
version = "1.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
@@ -3993,10 +4301,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
|
checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
|
"itoa",
|
||||||
"num-conv",
|
"num-conv",
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
"time-core",
|
"time-core",
|
||||||
|
"time-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4005,6 +4315,16 @@ version = "0.1.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
|
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-macros"
|
||||||
|
version = "0.2.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
|
||||||
|
dependencies = [
|
||||||
|
"num-conv",
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@@ -4368,6 +4688,16 @@ version = "1.8.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e36a83ea2b3c704935a01b4642946aadd445cea40b10935e3f8bd8052b8193d6"
|
checksum = "e36a83ea2b3c704935a01b4642946aadd445cea40b10935e3f8bd8052b8193d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ulid"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe"
|
||||||
|
dependencies = [
|
||||||
|
"rand 0.9.2",
|
||||||
|
"web-time",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uncased"
|
name = "uncased"
|
||||||
version = "0.9.10"
|
version = "0.9.10"
|
||||||
@@ -4682,6 +5012,24 @@ dependencies = [
|
|||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm_evt_listener"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc92d6378b411ed94839112a36d9dbc77143451d85b05dfb0cce93a78dab1963"
|
||||||
|
dependencies = [
|
||||||
|
"accessory",
|
||||||
|
"derivative",
|
||||||
|
"derive_more 1.0.0",
|
||||||
|
"fancy_constructor",
|
||||||
|
"futures-core",
|
||||||
|
"js-sys",
|
||||||
|
"smallvec",
|
||||||
|
"tokio",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmparser"
|
name = "wasmparser"
|
||||||
version = "0.244.0"
|
version = "0.244.0"
|
||||||
@@ -4711,6 +5059,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
"serde",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ filetime = "0.2"
|
|||||||
matrix-sdk = { version = "0.16.0", default-features = false, features = [
|
matrix-sdk = { version = "0.16.0", default-features = false, features = [
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"sqlite",
|
"sqlite",
|
||||||
|
"e2e-encryption",
|
||||||
] }
|
] }
|
||||||
pulldown-cmark = { version = "0.13.1", default-features = false, features = [
|
pulldown-cmark = { version = "0.13.1", default-features = false, features = [
|
||||||
"html",
|
"html",
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
// matrix-sdk-crypto's deeply nested types require a higher recursion limit
|
||||||
|
// when the `e2e-encryption` feature is enabled.
|
||||||
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
mod agent_log;
|
mod agent_log;
|
||||||
mod agents;
|
mod agents;
|
||||||
mod config;
|
mod config;
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||||||
use tokio::sync::Mutex as TokioMutex;
|
use tokio::sync::Mutex as TokioMutex;
|
||||||
use tokio::sync::watch;
|
use tokio::sync::watch;
|
||||||
|
|
||||||
|
use futures::StreamExt;
|
||||||
|
use matrix_sdk::encryption::verification::{
|
||||||
|
SasState, SasVerification, Verification, VerificationRequestState, format_emojis,
|
||||||
|
};
|
||||||
|
use matrix_sdk::ruma::events::key::verification::request::ToDeviceKeyVerificationRequestEvent;
|
||||||
|
|
||||||
use super::config::BotConfig;
|
use super::config::BotConfig;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -71,6 +77,9 @@ pub struct BotContext {
|
|||||||
/// bot so it can continue a conversation thread without requiring an
|
/// bot so it can continue a conversation thread without requiring an
|
||||||
/// explicit `@mention` on every follow-up.
|
/// explicit `@mention` on every follow-up.
|
||||||
pub bot_sent_event_ids: Arc<TokioMutex<HashSet<OwnedEventId>>>,
|
pub bot_sent_event_ids: Arc<TokioMutex<HashSet<OwnedEventId>>>,
|
||||||
|
/// When `true`, the bot rejects messages from users whose devices have not
|
||||||
|
/// been verified via cross-signing in encrypted rooms.
|
||||||
|
pub require_verified_devices: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -89,20 +98,46 @@ pub async fn run_bot(config: BotConfig, project_root: PathBuf) -> Result<(), Str
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Failed to build Matrix client: {e}"))?;
|
.map_err(|e| format!("Failed to build Matrix client: {e}"))?;
|
||||||
|
|
||||||
// Login
|
// Persist device ID so E2EE crypto state survives restarts.
|
||||||
client
|
let device_id_path = project_root.join(".story_kit").join("matrix_device_id");
|
||||||
|
let saved_device_id: Option<String> = std::fs::read_to_string(&device_id_path)
|
||||||
|
.ok()
|
||||||
|
.map(|s| s.trim().to_string())
|
||||||
|
.filter(|s| !s.is_empty());
|
||||||
|
|
||||||
|
let mut login_builder = client
|
||||||
.matrix_auth()
|
.matrix_auth()
|
||||||
.login_username(&config.username, &config.password)
|
.login_username(&config.username, &config.password)
|
||||||
.initial_device_display_name("Story Kit Bot")
|
.initial_device_display_name("Story Kit Bot");
|
||||||
|
|
||||||
|
if let Some(ref device_id) = saved_device_id {
|
||||||
|
login_builder = login_builder.device_id(device_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let login_response = login_builder
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Matrix login failed: {e}"))?;
|
.map_err(|e| format!("Matrix login failed: {e}"))?;
|
||||||
|
|
||||||
|
// Save device ID on first login so subsequent restarts reuse the same device.
|
||||||
|
if saved_device_id.is_none() {
|
||||||
|
let _ = std::fs::write(&device_id_path, &login_response.device_id);
|
||||||
|
slog!(
|
||||||
|
"[matrix-bot] Saved device ID {} for future restarts",
|
||||||
|
login_response.device_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let bot_user_id = client
|
let bot_user_id = client
|
||||||
.user_id()
|
.user_id()
|
||||||
.ok_or_else(|| "No user ID after login".to_string())?
|
.ok_or_else(|| "No user ID after login".to_string())?
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
slog!("[matrix-bot] Logged in as {bot_user_id}");
|
slog!("[matrix-bot] Logged in as {bot_user_id} (device: {})", login_response.device_id);
|
||||||
|
|
||||||
|
// Bootstrap cross-signing keys for E2EE verification support.
|
||||||
|
if let Err(e) = client.encryption().bootstrap_cross_signing(None).await {
|
||||||
|
slog!("[matrix-bot] Cross-signing bootstrap note: {e}");
|
||||||
|
}
|
||||||
|
|
||||||
if config.allowed_users.is_empty() {
|
if config.allowed_users.is_empty() {
|
||||||
return Err(
|
return Err(
|
||||||
@@ -157,11 +192,17 @@ pub async fn run_bot(config: BotConfig, project_root: PathBuf) -> Result<(), Str
|
|||||||
history: Arc::new(TokioMutex::new(HashMap::new())),
|
history: Arc::new(TokioMutex::new(HashMap::new())),
|
||||||
history_size: config.history_size,
|
history_size: config.history_size,
|
||||||
bot_sent_event_ids: Arc::new(TokioMutex::new(HashSet::new())),
|
bot_sent_event_ids: Arc::new(TokioMutex::new(HashSet::new())),
|
||||||
|
require_verified_devices: config.require_verified_devices,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Register event handler and inject shared context
|
if config.require_verified_devices {
|
||||||
|
slog!("[matrix-bot] require_verified_devices is ON — messages from unverified devices in encrypted rooms will be rejected");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register event handlers and inject shared context.
|
||||||
client.add_event_handler_context(ctx);
|
client.add_event_handler_context(ctx);
|
||||||
client.add_event_handler(on_room_message);
|
client.add_event_handler(on_room_message);
|
||||||
|
client.add_event_handler(on_to_device_verification_request);
|
||||||
|
|
||||||
slog!("[matrix-bot] Starting Matrix sync loop");
|
slog!("[matrix-bot] Starting Matrix sync loop");
|
||||||
|
|
||||||
@@ -248,13 +289,146 @@ async fn is_reply_to_bot(
|
|||||||
candidate_ids.iter().any(|id| guard.contains(*id))
|
candidate_ids.iter().any(|id| guard.contains(*id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// E2EE device verification helpers
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Check whether the sender has at least one verified device.
|
||||||
|
///
|
||||||
|
/// Returns `Ok(true)` if at least one device is cross-signing verified,
|
||||||
|
/// `Ok(false)` if there are zero verified devices, and `Err` on failures.
|
||||||
|
async fn check_sender_verified(
|
||||||
|
client: &Client,
|
||||||
|
sender: &OwnedUserId,
|
||||||
|
) -> Result<bool, String> {
|
||||||
|
let devices = client
|
||||||
|
.encryption()
|
||||||
|
.get_user_devices(sender)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to get devices for {sender}: {e}"))?;
|
||||||
|
|
||||||
|
// Accept if the user has at least one verified device.
|
||||||
|
Ok(devices.devices().any(|d| d.is_verified()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// SAS verification handler
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Handle an incoming to-device verification request by accepting it and
|
||||||
|
/// driving the SAS (emoji comparison) flow to completion. The bot auto-
|
||||||
|
/// confirms the SAS code — the operator can compare the emojis logged to
|
||||||
|
/// the console with those displayed in their Element client.
|
||||||
|
async fn on_to_device_verification_request(
|
||||||
|
ev: ToDeviceKeyVerificationRequestEvent,
|
||||||
|
client: Client,
|
||||||
|
) {
|
||||||
|
slog!(
|
||||||
|
"[matrix-bot] Incoming verification request from {} (device: {})",
|
||||||
|
ev.sender,
|
||||||
|
ev.content.from_device
|
||||||
|
);
|
||||||
|
|
||||||
|
let Some(request) = client
|
||||||
|
.encryption()
|
||||||
|
.get_verification_request(&ev.sender, &ev.content.transaction_id)
|
||||||
|
.await
|
||||||
|
else {
|
||||||
|
slog!("[matrix-bot] Could not locate verification request in crypto store");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = request.accept().await {
|
||||||
|
slog!("[matrix-bot] Failed to accept verification request: {e}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to start a SAS flow. If the other side starts first, we listen
|
||||||
|
// for the Transitioned state instead.
|
||||||
|
match request.start_sas().await {
|
||||||
|
Ok(Some(sas)) => {
|
||||||
|
handle_sas_verification(sas).await;
|
||||||
|
}
|
||||||
|
Ok(None) => {
|
||||||
|
slog!("[matrix-bot] Waiting for other side to start SAS…");
|
||||||
|
let stream = request.changes();
|
||||||
|
tokio::pin!(stream);
|
||||||
|
while let Some(state) = stream.next().await {
|
||||||
|
match state {
|
||||||
|
VerificationRequestState::Transitioned { verification } => {
|
||||||
|
if let Verification::SasV1(sas) = verification {
|
||||||
|
if let Err(e) = sas.accept().await {
|
||||||
|
slog!("[matrix-bot] Failed to accept SAS: {e}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handle_sas_verification(sas).await;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
VerificationRequestState::Done
|
||||||
|
| VerificationRequestState::Cancelled(_) => break,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
slog!("[matrix-bot] Failed to start SAS verification: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Drive a SAS verification to completion: wait for the key exchange, log
|
||||||
|
/// the emoji comparison string, auto-confirm, and report the outcome.
|
||||||
|
async fn handle_sas_verification(sas: SasVerification) {
|
||||||
|
slog!(
|
||||||
|
"[matrix-bot] SAS verification in progress with {}",
|
||||||
|
sas.other_user_id()
|
||||||
|
);
|
||||||
|
|
||||||
|
let stream = sas.changes();
|
||||||
|
tokio::pin!(stream);
|
||||||
|
while let Some(state) = stream.next().await {
|
||||||
|
match state {
|
||||||
|
SasState::KeysExchanged { emojis, .. } => {
|
||||||
|
if let Some(emoji_sas) = emojis {
|
||||||
|
slog!(
|
||||||
|
"[matrix-bot] SAS verification emojis:\n{}",
|
||||||
|
format_emojis(emoji_sas.emojis)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if let Err(e) = sas.confirm().await {
|
||||||
|
slog!("[matrix-bot] Failed to confirm SAS: {e}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SasState::Done { .. } => {
|
||||||
|
slog!(
|
||||||
|
"[matrix-bot] Verification with {} completed successfully!",
|
||||||
|
sas.other_user_id()
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SasState::Cancelled(info) => {
|
||||||
|
slog!("[matrix-bot] Verification cancelled: {info:?}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Event handler
|
// Event handler
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Matrix event handler for room messages. Each invocation spawns an
|
/// Matrix event handler for room messages. Each invocation spawns an
|
||||||
/// independent task so the sync loop is not blocked by LLM calls.
|
/// independent task so the sync loop is not blocked by LLM calls.
|
||||||
async fn on_room_message(ev: OriginalSyncRoomMessageEvent, room: Room, Ctx(ctx): Ctx<BotContext>) {
|
async fn on_room_message(
|
||||||
|
ev: OriginalSyncRoomMessageEvent,
|
||||||
|
room: Room,
|
||||||
|
client: Client,
|
||||||
|
Ctx(ctx): Ctx<BotContext>,
|
||||||
|
) {
|
||||||
let incoming_room_id = room.room_id().to_owned();
|
let incoming_room_id = room.room_id().to_owned();
|
||||||
|
|
||||||
slog!(
|
slog!(
|
||||||
@@ -301,6 +475,31 @@ async fn on_room_message(ev: OriginalSyncRoomMessageEvent, room: Room, Ctx(ctx):
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When require_verified_devices is enabled and the room is encrypted,
|
||||||
|
// reject messages from users whose devices have not been verified.
|
||||||
|
if ctx.require_verified_devices && room.encryption_state().is_encrypted() {
|
||||||
|
match check_sender_verified(&client, &ev.sender).await {
|
||||||
|
Ok(true) => { /* sender has at least one verified device — proceed */ }
|
||||||
|
Ok(false) => {
|
||||||
|
slog!(
|
||||||
|
"[matrix-bot] WARNING: Rejecting message from {} — \
|
||||||
|
unverified device(s) in encrypted room {}",
|
||||||
|
ev.sender,
|
||||||
|
incoming_room_id
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
slog!(
|
||||||
|
"[matrix-bot] Error checking verification for {}: {e} — \
|
||||||
|
rejecting message (fail-closed)",
|
||||||
|
ev.sender
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let sender = ev.sender.to_string();
|
let sender = ev.sender.to_string();
|
||||||
let user_message = body;
|
let user_message = body;
|
||||||
slog!("[matrix-bot] Message from {sender}: {user_message}");
|
slog!("[matrix-bot] Message from {sender}: {user_message}");
|
||||||
@@ -730,6 +929,27 @@ mod tests {
|
|||||||
assert_clone::<BotContext>();
|
assert_clone::<BotContext>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bot_context_require_verified_devices_field() {
|
||||||
|
let ctx = BotContext {
|
||||||
|
bot_user_id: make_user_id("@bot:example.com"),
|
||||||
|
target_room_ids: vec![],
|
||||||
|
project_root: PathBuf::from("/tmp"),
|
||||||
|
allowed_users: vec![],
|
||||||
|
history: Arc::new(TokioMutex::new(HashMap::new())),
|
||||||
|
history_size: 20,
|
||||||
|
bot_sent_event_ids: Arc::new(TokioMutex::new(HashSet::new())),
|
||||||
|
require_verified_devices: true,
|
||||||
|
};
|
||||||
|
assert!(ctx.require_verified_devices);
|
||||||
|
|
||||||
|
let ctx_off = BotContext {
|
||||||
|
require_verified_devices: false,
|
||||||
|
..ctx
|
||||||
|
};
|
||||||
|
assert!(!ctx_off.require_verified_devices);
|
||||||
|
}
|
||||||
|
|
||||||
// -- drain_complete_paragraphs ------------------------------------------
|
// -- drain_complete_paragraphs ------------------------------------------
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ pub struct BotConfig {
|
|||||||
/// dropped. Defaults to 20.
|
/// dropped. Defaults to 20.
|
||||||
#[serde(default = "default_history_size")]
|
#[serde(default = "default_history_size")]
|
||||||
pub history_size: usize,
|
pub history_size: usize,
|
||||||
|
/// When `true`, the bot rejects messages from users whose devices have not
|
||||||
|
/// been verified via cross-signing in encrypted rooms. When `false`
|
||||||
|
/// (default), messages are accepted regardless of device verification
|
||||||
|
/// status, preserving existing plaintext-room behaviour.
|
||||||
|
#[serde(default)]
|
||||||
|
pub require_verified_devices: bool,
|
||||||
/// Previously used to select an Anthropic model. Now ignored — the bot
|
/// Previously used to select an Anthropic model. Now ignored — the bot
|
||||||
/// uses Claude Code which manages its own model selection. Kept for
|
/// uses Claude Code which manages its own model selection. Kept for
|
||||||
/// backwards compatibility so existing bot.toml files still parse.
|
/// backwards compatibility so existing bot.toml files still parse.
|
||||||
@@ -235,6 +241,47 @@ enabled = true
|
|||||||
assert_eq!(config.history_size, 20);
|
assert_eq!(config.history_size, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_defaults_require_verified_devices_to_false() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let sk = tmp.path().join(".story_kit");
|
||||||
|
fs::create_dir_all(&sk).unwrap();
|
||||||
|
fs::write(
|
||||||
|
sk.join("bot.toml"),
|
||||||
|
r#"
|
||||||
|
homeserver = "https://matrix.example.com"
|
||||||
|
username = "@bot:example.com"
|
||||||
|
password = "secret"
|
||||||
|
room_ids = ["!abc:example.com"]
|
||||||
|
enabled = true
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let config = BotConfig::load(tmp.path()).unwrap();
|
||||||
|
assert!(!config.require_verified_devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_respects_require_verified_devices_true() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let sk = tmp.path().join(".story_kit");
|
||||||
|
fs::create_dir_all(&sk).unwrap();
|
||||||
|
fs::write(
|
||||||
|
sk.join("bot.toml"),
|
||||||
|
r#"
|
||||||
|
homeserver = "https://matrix.example.com"
|
||||||
|
username = "@bot:example.com"
|
||||||
|
password = "secret"
|
||||||
|
room_ids = ["!abc:example.com"]
|
||||||
|
enabled = true
|
||||||
|
require_verified_devices = true
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let config = BotConfig::load(tmp.path()).unwrap();
|
||||||
|
assert!(config.require_verified_devices);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_respects_custom_history_size() {
|
fn load_respects_custom_history_size() {
|
||||||
let tmp = tempfile::tempdir().unwrap();
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user