Compare commits
1 Commits
3cc63474a8
...
b22be1627a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b22be1627a |
194
server/Cargo.lock
generated
194
server/Cargo.lock
generated
@@ -47,9 +47,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.102"
|
version = "1.0.101"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arbiter-client"
|
name = "arbiter-client"
|
||||||
@@ -121,13 +121,9 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"arbiter-proto",
|
"arbiter-proto",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
"http",
|
|
||||||
"kameo",
|
"kameo",
|
||||||
"rustls-webpki",
|
|
||||||
"smlang",
|
"smlang",
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
|
||||||
"tonic",
|
"tonic",
|
||||||
"tracing",
|
"tracing",
|
||||||
"x25519-dalek",
|
"x25519-dalek",
|
||||||
@@ -170,7 +166,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -182,7 +178,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -193,7 +189,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -210,9 +206,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-lc-rs"
|
name = "aws-lc-rs"
|
||||||
version = "1.16.0"
|
version = "1.15.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9a7b350e3bb1767102698302bc37256cbd48422809984b98d292c40e2579aa9"
|
checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-sys",
|
"aws-lc-sys",
|
||||||
"untrusted 0.7.1",
|
"untrusted 0.7.1",
|
||||||
@@ -348,18 +344,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
version = "0.12.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be"
|
checksum = "96eb4cdd6cf1b31d671e9efe75c5d1ec614776856cefbe109ca373554a6d514f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hybrid-array",
|
"hybrid-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.20.2"
|
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 = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
@@ -422,9 +418,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.44"
|
version = "0.4.43"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@@ -518,9 +514,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.2.1"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710"
|
checksum = "211f05e03c7d03754740fd9e585de910a095d6b99f8bcfffdef8319fa02a8331"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hybrid-array",
|
"hybrid-array",
|
||||||
]
|
]
|
||||||
@@ -549,7 +545,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures 0.2.17",
|
"cpufeatures 0.2.17",
|
||||||
"curve25519-dalek-derive",
|
"curve25519-dalek-derive",
|
||||||
"digest 0.11.1",
|
"digest 0.11.0",
|
||||||
"fiat-crypto 0.3.0",
|
"fiat-crypto 0.3.0",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"subtle",
|
"subtle",
|
||||||
@@ -564,7 +560,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -588,7 +584,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim",
|
"strsim",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -599,7 +595,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -638,9 +634,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.5.8"
|
version = "0.5.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
]
|
]
|
||||||
@@ -686,7 +682,7 @@ dependencies = [
|
|||||||
"dsl_auto_type",
|
"dsl_auto_type",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -706,7 +702,7 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe2444076b48641147115697648dc743c2c00b61adade0f01ce67133c7babe8c"
|
checksum = "fe2444076b48641147115697648dc743c2c00b61adade0f01ce67133c7babe8c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -722,12 +718,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.11.1"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "285743a676ccb6b3e116bc14cc69319b957867930ae9c4822f8e0f54509d7243"
|
checksum = "f8bf3682cdec91817be507e4aa104314898b95b84d74f3d43882210101a545b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer 0.12.0",
|
"block-buffer 0.11.0",
|
||||||
"crypto-common 0.2.1",
|
"crypto-common 0.2.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -738,7 +734,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -758,7 +754,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -953,7 +949,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1413,9 +1409,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.90"
|
version = "0.3.85"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "14dc6f6450b3f6d4ed5b16327f38fed626d375a886159ca555bd7822c0c3a5a6"
|
checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -1445,7 +1441,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1478,9 +1474,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.12.1"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litemap"
|
name = "litemap"
|
||||||
@@ -1562,7 +1558,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1710,9 +1706,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "owo-colors"
|
name = "owo-colors"
|
||||||
version = "4.3.0"
|
version = "4.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d"
|
checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
@@ -1792,7 +1788,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1852,7 +1848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1924,7 +1920,7 @@ dependencies = [
|
|||||||
"pulldown-cmark",
|
"pulldown-cmark",
|
||||||
"pulldown-cmark-to-cmark",
|
"pulldown-cmark-to-cmark",
|
||||||
"regex",
|
"regex",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1938,7 +1934,7 @@ dependencies = [
|
|||||||
"itertools",
|
"itertools",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1952,9 +1948,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pulldown-cmark"
|
name = "pulldown-cmark"
|
||||||
version = "0.13.1"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83c41efbf8f90ac44de7f3a868f0867851d261b56291732d0cbf7cceaaeb55a6"
|
checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -2060,9 +2056,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.10"
|
version = "0.8.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "relative-path"
|
name = "relative-path"
|
||||||
@@ -2079,7 +2075,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2131,7 +2127,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"relative-path",
|
"relative-path",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2161,9 +2157,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "1.1.4"
|
version = "1.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
@@ -2174,9 +2170,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.37"
|
version = "0.23.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
|
checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-rs",
|
"aws-lc-rs",
|
||||||
"log",
|
"log",
|
||||||
@@ -2271,7 +2267,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2304,7 +2300,7 @@ checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures 0.2.17",
|
"cpufeatures 0.2.17",
|
||||||
"digest 0.11.1",
|
"digest 0.11.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2441,7 +2437,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2484,9 +2480,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.117"
|
version = "2.0.115"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2507,14 +2503,14 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.26.0"
|
version = "3.25.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0"
|
checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.4.1",
|
"getrandom 0.4.1",
|
||||||
@@ -2551,7 +2547,7 @@ checksum = "be35209fd0781c5401458ab66e4f98accf63553e8fae7425503e92fdd319783b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2581,7 +2577,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2660,7 +2656,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2734,18 +2730,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_parser"
|
name = "toml_parser"
|
||||||
version = "1.0.9+spec-1.1.0"
|
version = "1.0.8+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4"
|
checksum = "0742ff5ff03ea7e67c8ae6c93cac239e0d9784833362da3f9a9c1da8dfefcbdc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tonic"
|
name = "tonic"
|
||||||
version = "0.14.5"
|
version = "0.14.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec"
|
checksum = "7f32a6f80051a4111560201420c7885d0082ba9efe2ab61875c587bb6b18b9a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum",
|
"axum",
|
||||||
@@ -2775,21 +2771,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tonic-build"
|
name = "tonic-build"
|
||||||
version = "0.14.5"
|
version = "0.14.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1882ac3bf5ef12877d7ed57aad87e75154c11931c2ba7e6cde5e22d63522c734"
|
checksum = "ce6d8958ed3be404120ca43ffa0fb1e1fc7be214e96c8d33bd43a131b6eebc9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tonic-prost"
|
name = "tonic-prost"
|
||||||
version = "0.14.5"
|
version = "0.14.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309"
|
checksum = "9f86539c0089bfd09b1f8c0ab0239d80392af74c21bc9e0f15e1b4aca4c1647f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"prost",
|
"prost",
|
||||||
@@ -2798,16 +2794,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tonic-prost-build"
|
name = "tonic-prost-build"
|
||||||
version = "0.14.5"
|
version = "0.14.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3144df636917574672e93d0f56d7edec49f90305749c668df5101751bb8f95a"
|
checksum = "65873ace111e90344b8973e94a1fc817c924473affff24629281f90daed1cd2e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"prost-build",
|
"prost-build",
|
||||||
"prost-types",
|
"prost-types",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"tonic-build",
|
"tonic-build",
|
||||||
]
|
]
|
||||||
@@ -2862,7 +2858,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2924,9 +2920,9 @@ checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.24"
|
version = "1.0.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-linebreak"
|
name = "unicode-linebreak"
|
||||||
@@ -3055,9 +3051,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.113"
|
version = "0.2.108"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "60722a937f594b7fde9adb894d7c092fc1bb6612897c46368d18e7a20208eff2"
|
checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -3068,9 +3064,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.113"
|
version = "0.2.108"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fac8c6395094b6b91c4af293f4c79371c163f9a6f56184d2c9a85f5a95f3950"
|
checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -3078,22 +3074,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.113"
|
version = "0.2.108"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab3fabce6159dc20728033842636887e4877688ae94382766e00b180abac9d60"
|
checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.113"
|
version = "0.2.108"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "de0e091bdb824da87dc01d967388880d017a0a9bc4f3bdc0d86ee9f9336e3bb5"
|
checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -3175,7 +3171,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3186,7 +3182,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3417,7 +3413,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
"wasm-metadata",
|
"wasm-metadata",
|
||||||
"wit-bindgen-core",
|
"wit-bindgen-core",
|
||||||
"wit-component",
|
"wit-component",
|
||||||
@@ -3433,7 +3429,7 @@ dependencies = [
|
|||||||
"prettyplease",
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
"wit-bindgen-core",
|
"wit-bindgen-core",
|
||||||
"wit-bindgen-rust",
|
"wit-bindgen-rust",
|
||||||
]
|
]
|
||||||
@@ -3539,7 +3535,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3560,7 +3556,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3581,7 +3577,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3614,7 +3610,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.117",
|
"syn 2.0.115",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -1,81 +1,9 @@
|
|||||||
//! Transport-facing abstractions for protocol/session code.
|
|
||||||
//!
|
|
||||||
//! This module separates three concerns:
|
|
||||||
//!
|
|
||||||
//! - protocol/session logic wants a small duplex interface ([`Bi`])
|
|
||||||
//! - transport adapters push concrete stream items to an underlying IO layer
|
|
||||||
//! - transport boundaries translate between protocol-facing and transport-facing
|
|
||||||
//! item types via direction-specific converters
|
|
||||||
//!
|
|
||||||
//! [`Bi`] is intentionally minimal and transport-agnostic:
|
|
||||||
//! - [`Bi::recv`] yields inbound protocol messages
|
|
||||||
//! - [`Bi::send`] accepts outbound protocol/domain items
|
|
||||||
//!
|
|
||||||
//! # Generic Ordering Rule
|
|
||||||
//!
|
|
||||||
//! This module uses a single convention consistently: when a type or trait is
|
|
||||||
//! parameterized by protocol message directions, the generic parameters are
|
|
||||||
//! declared as `Inbound` first, then `Outbound`.
|
|
||||||
//!
|
|
||||||
//! For [`Bi`], that means `Bi<Inbound, Outbound>`:
|
|
||||||
//! - `recv() -> Option<Inbound>`
|
|
||||||
//! - `send(Outbound)`
|
|
||||||
//!
|
|
||||||
//! For adapter types that are parameterized by direction-specific converters,
|
|
||||||
//! inbound-related converter parameters are declared before outbound-related
|
|
||||||
//! converter parameters.
|
|
||||||
//!
|
|
||||||
//! [`RecvConverter`] and [`SendConverter`] are infallible conversion traits used
|
|
||||||
//! by adapters to map between protocol-facing and transport-facing item types.
|
|
||||||
//! The traits themselves are not result-aware; adapters decide how transport
|
|
||||||
//! errors are handled before (or instead of) conversion.
|
|
||||||
//!
|
|
||||||
//! [`grpc::GrpcAdapter`] combines:
|
|
||||||
//! - a tonic inbound stream
|
|
||||||
//! - a Tokio sender for outbound transport items
|
|
||||||
//! - a [`RecvConverter`] for the receive path
|
|
||||||
//! - a [`SendConverter`] for the send path
|
|
||||||
//!
|
|
||||||
//! [`DummyTransport`] is a no-op implementation useful for tests and local actor
|
|
||||||
//! execution where no real network stream exists.
|
|
||||||
//!
|
|
||||||
//! # Component Interaction
|
|
||||||
//!
|
|
||||||
//! ```text
|
|
||||||
//! inbound (network -> protocol)
|
|
||||||
//! ============================
|
|
||||||
//!
|
|
||||||
//! tonic::Streaming<RecvTransport>
|
|
||||||
//! -> grpc::GrpcAdapter::recv()
|
|
||||||
//! |
|
|
||||||
//! +--> on `Ok(item)`: RecvConverter::convert(RecvTransport) -> Inbound
|
|
||||||
//! +--> on `Err(status)`: log error and close stream (`None`)
|
|
||||||
//! -> Bi::recv()
|
|
||||||
//! -> protocol/session actor
|
|
||||||
//!
|
|
||||||
//! outbound (protocol -> network)
|
|
||||||
//! ==============================
|
|
||||||
//!
|
|
||||||
//! protocol/session actor
|
|
||||||
//! -> Bi::send(Outbound)
|
|
||||||
//! -> grpc::GrpcAdapter::send()
|
|
||||||
//! |
|
|
||||||
//! +--> SendConverter::convert(Outbound) -> SendTransport
|
|
||||||
//! -> Tokio mpsc::Sender<SendTransport>
|
|
||||||
//! -> tonic response stream
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! # Design Notes
|
|
||||||
//!
|
|
||||||
//! - `send()` returns [`Error`] only for transport delivery failures (for
|
|
||||||
//! example, when the outbound channel is closed).
|
|
||||||
//! - [`grpc::GrpcAdapter`] logs tonic receive errors and treats them as stream
|
|
||||||
//! closure (`None`).
|
|
||||||
//! - When protocol-facing and transport-facing types are identical, use
|
|
||||||
//! [`IdentityRecvConverter`] / [`IdentitySendConverter`].
|
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use futures::StreamExt;
|
||||||
|
use tokio::sync::mpsc;
|
||||||
|
use tonic::{Status, Streaming};
|
||||||
|
|
||||||
/// Errors returned by transport adapters implementing [`Bi`].
|
/// Errors returned by transport adapters implementing [`Bi`].
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// The outbound side of the transport is no longer accepting messages.
|
/// The outbound side of the transport is no longer accepting messages.
|
||||||
@@ -84,172 +12,75 @@ pub enum Error {
|
|||||||
|
|
||||||
/// Minimal bidirectional transport abstraction used by protocol code.
|
/// Minimal bidirectional transport abstraction used by protocol code.
|
||||||
///
|
///
|
||||||
/// `Bi<Inbound, Outbound>` models a duplex channel with:
|
/// `Bi<T, U, E>` models a duplex channel with:
|
||||||
/// - inbound items of type `Inbound` read via [`Bi::recv`]
|
/// - inbound items of type `T` read via [`Bi::recv`]
|
||||||
/// - outbound items of type `Outbound` written via [`Bi::send`]
|
/// - outbound success items of type `U` or domain errors of type `E` written via [`Bi::send`]
|
||||||
pub trait Bi<Inbound, Outbound>: Send + Sync + 'static {
|
///
|
||||||
|
/// The trait intentionally exposes only the operations the protocol layer needs,
|
||||||
|
/// allowing it to work with gRPC streams and other transport implementations.
|
||||||
|
///
|
||||||
|
/// # Stream termination and errors
|
||||||
|
///
|
||||||
|
/// [`Bi::recv`] returns:
|
||||||
|
/// - `Some(item)` when a new inbound message is available
|
||||||
|
/// - `None` when the inbound stream ends or the underlying transport reports an error
|
||||||
|
///
|
||||||
|
/// Implementations may collapse transport-specific receive errors into `None`
|
||||||
|
/// when the protocol does not need to distinguish them from normal stream
|
||||||
|
/// termination.
|
||||||
|
pub trait Bi<T, U, E>: Send + Sync + 'static {
|
||||||
|
/// Sends one outbound result to the peer.
|
||||||
fn send(
|
fn send(
|
||||||
&mut self,
|
&mut self,
|
||||||
item: Outbound,
|
item: Result<U, E>,
|
||||||
) -> impl std::future::Future<Output = Result<(), Error>> + Send;
|
) -> impl std::future::Future<Output = Result<(), Error>> + Send;
|
||||||
|
|
||||||
fn recv(&mut self) -> impl std::future::Future<Output = Option<Inbound>> + Send;
|
/// Receives the next inbound item.
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts transport-facing inbound items into protocol-facing inbound items.
|
|
||||||
pub trait RecvConverter: Send + Sync + 'static {
|
|
||||||
type Input;
|
|
||||||
type Output;
|
|
||||||
|
|
||||||
fn convert(&self, item: Self::Input) -> Self::Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts protocol/domain outbound items into transport-facing outbound items.
|
|
||||||
pub trait SendConverter: Send + Sync + 'static {
|
|
||||||
type Input;
|
|
||||||
type Output;
|
|
||||||
|
|
||||||
fn convert(&self, item: Self::Input) -> Self::Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [`RecvConverter`] that forwards values unchanged.
|
|
||||||
pub struct IdentityRecvConverter<T> {
|
|
||||||
_marker: PhantomData<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> IdentityRecvConverter<T> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for IdentityRecvConverter<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> RecvConverter for IdentityRecvConverter<T>
|
|
||||||
where
|
|
||||||
T: Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
type Input = T;
|
|
||||||
type Output = T;
|
|
||||||
|
|
||||||
fn convert(&self, item: Self::Input) -> Self::Output {
|
|
||||||
item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [`SendConverter`] that forwards values unchanged.
|
|
||||||
pub struct IdentitySendConverter<T> {
|
|
||||||
_marker: PhantomData<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> IdentitySendConverter<T> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for IdentitySendConverter<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> SendConverter for IdentitySendConverter<T>
|
|
||||||
where
|
|
||||||
T: Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
type Input = T;
|
|
||||||
type Output = T;
|
|
||||||
|
|
||||||
fn convert(&self, item: Self::Input) -> Self::Output {
|
|
||||||
item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// gRPC-specific transport adapters and helpers.
|
|
||||||
pub mod grpc {
|
|
||||||
use futures::StreamExt;
|
|
||||||
use tokio::sync::mpsc;
|
|
||||||
use tonic::Streaming;
|
|
||||||
|
|
||||||
use super::{Bi, Error, RecvConverter, SendConverter};
|
|
||||||
|
|
||||||
/// [`Bi`] adapter backed by a tonic gRPC bidirectional stream.
|
|
||||||
///
|
///
|
||||||
|
/// Returns `None` when the inbound stream is finished or can no longer
|
||||||
|
/// produce items.
|
||||||
|
fn recv(&mut self) -> impl std::future::Future<Output = Option<T>> + Send;
|
||||||
|
}
|
||||||
|
|
||||||
/// Tonic receive errors are logged and treated as stream closure (`None`).
|
/// [`Bi`] adapter backed by a tonic gRPC bidirectional stream.
|
||||||
/// The receive converter is only invoked for successful inbound transport
|
///
|
||||||
/// items.
|
/// Outbound items are sent through a Tokio MPSC sender, while inbound items are
|
||||||
pub struct GrpcAdapter<InboundConverter, OutboundConverter>
|
/// read from tonic [`Streaming`].
|
||||||
where
|
pub struct GrpcAdapter<Inbound, Outbound, E> {
|
||||||
InboundConverter: RecvConverter,
|
sender: mpsc::Sender<Result<Outbound, Status>>,
|
||||||
OutboundConverter: SendConverter,
|
receiver: Streaming<Inbound>,
|
||||||
{
|
_error: PhantomData<E>,
|
||||||
sender: mpsc::Sender<OutboundConverter::Output>,
|
}
|
||||||
receiver: Streaming<InboundConverter::Input>,
|
|
||||||
inbound_converter: InboundConverter,
|
|
||||||
outbound_converter: OutboundConverter,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
impl<Inbound, Outbound, E> GrpcAdapter<Inbound, Outbound, E> {
|
||||||
|
|
||||||
impl<InboundTransport, Inbound, InboundConverter, OutboundConverter>
|
/// Creates a new gRPC-backed [`Bi`] adapter.
|
||||||
GrpcAdapter<InboundConverter, OutboundConverter>
|
pub fn new(sender: mpsc::Sender<Result<Outbound, Status>>, receiver: Streaming<Inbound>) -> Self {
|
||||||
where
|
Self {
|
||||||
InboundConverter: RecvConverter<Input = InboundTransport, Output = Inbound>,
|
sender,
|
||||||
OutboundConverter: SendConverter,
|
receiver,
|
||||||
{
|
_error: PhantomData,
|
||||||
pub fn new(
|
|
||||||
sender: mpsc::Sender<OutboundConverter::Output>,
|
|
||||||
receiver: Streaming<InboundTransport>,
|
|
||||||
inbound_converter: InboundConverter,
|
|
||||||
outbound_converter: OutboundConverter,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
sender,
|
|
||||||
receiver,
|
|
||||||
inbound_converter,
|
|
||||||
outbound_converter,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Inbound, Outbound, E> Bi<Inbound, Outbound, E> for GrpcAdapter<Inbound, Outbound, E>
|
||||||
|
where
|
||||||
|
Inbound: Send + 'static,
|
||||||
|
Outbound: Send + 'static,
|
||||||
|
E: Into<Status> + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
#[tracing::instrument(level = "trace", skip(self, item))]
|
||||||
|
async fn send(&mut self, item: Result<Outbound, E>) -> Result<(), Error> {
|
||||||
|
self.sender
|
||||||
|
.send(item.map_err(Into::into))
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::ChannelClosed)
|
||||||
|
}
|
||||||
|
|
||||||
impl< InboundConverter, OutboundConverter> Bi<InboundConverter::Output, OutboundConverter::Input>
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
for GrpcAdapter<InboundConverter, OutboundConverter>
|
async fn recv(&mut self) -> Option<Inbound> {
|
||||||
where
|
self.receiver.next().await.transpose().ok().flatten()
|
||||||
InboundConverter: RecvConverter,
|
|
||||||
OutboundConverter: SendConverter,
|
|
||||||
OutboundConverter::Input: Send + 'static,
|
|
||||||
OutboundConverter::Output: Send + 'static,
|
|
||||||
{
|
|
||||||
#[tracing::instrument(level = "trace", skip(self, item))]
|
|
||||||
async fn send(&mut self, item: OutboundConverter::Input) -> Result<(), Error> {
|
|
||||||
let outbound = self.outbound_converter.convert(item);
|
|
||||||
self.sender
|
|
||||||
.send(outbound)
|
|
||||||
.await
|
|
||||||
.map_err(|_| Error::ChannelClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(level = "trace", skip(self))]
|
|
||||||
async fn recv(&mut self) -> Option<InboundConverter::Output> {
|
|
||||||
match self.receiver.next().await {
|
|
||||||
Some(Ok(item)) => Some(self.inbound_converter.convert(item)),
|
|
||||||
Some(Err(error)) => {
|
|
||||||
tracing::error!(error = ?error, "grpc transport recv failed; closing stream");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,11 +88,11 @@ pub mod grpc {
|
|||||||
///
|
///
|
||||||
/// `send` drops all items and succeeds. [`Bi::recv`] never resolves and therefore
|
/// `send` drops all items and succeeds. [`Bi::recv`] never resolves and therefore
|
||||||
/// does not busy-wait or spuriously close the stream.
|
/// does not busy-wait or spuriously close the stream.
|
||||||
pub struct DummyTransport<Inbound, Outbound> {
|
pub struct DummyTransport<T, U, E> {
|
||||||
_marker: PhantomData<(Inbound, Outbound)>,
|
_marker: PhantomData<(T, U, E)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Inbound, Outbound> DummyTransport<Inbound, Outbound> {
|
impl<T, U, E> DummyTransport<T, U, E> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
@@ -269,22 +100,23 @@ impl<Inbound, Outbound> DummyTransport<Inbound, Outbound> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Inbound, Outbound> Default for DummyTransport<Inbound, Outbound> {
|
impl<T, U, E> Default for DummyTransport<T, U, E> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Inbound, Outbound> Bi<Inbound, Outbound> for DummyTransport<Inbound, Outbound>
|
impl<T, U, E> Bi<T, U, E> for DummyTransport<T, U, E>
|
||||||
where
|
where
|
||||||
Inbound: Send + Sync + 'static,
|
T: Send + Sync + 'static,
|
||||||
Outbound: Send + Sync + 'static,
|
U: Send + Sync + 'static,
|
||||||
|
E: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
async fn send(&mut self, _item: Outbound) -> Result<(), Error> {
|
async fn send(&mut self, _item: Result<U, E>) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv(&mut self) -> impl std::future::Future<Output = Option<Inbound>> + Send {
|
fn recv(&mut self) -> impl std::future::Future<Output = Option<T>> + Send {
|
||||||
async {
|
async {
|
||||||
std::future::pending::<()>().await;
|
std::future::pending::<()>().await;
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ use crate::ServerContext;
|
|||||||
|
|
||||||
pub(crate) async fn handle_client(
|
pub(crate) async fn handle_client(
|
||||||
_context: ServerContext,
|
_context: ServerContext,
|
||||||
_bistream: impl Bi<ClientRequest, ClientResponse>,
|
_bistream: impl Bi<ClientRequest, ClientResponse, tonic::Status>,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ use ed25519_dalek::VerifyingKey;
|
|||||||
use kameo::{Actor, error::SendError};
|
use kameo::{Actor, error::SendError};
|
||||||
use memsafe::MemSafe;
|
use memsafe::MemSafe;
|
||||||
use tokio::select;
|
use tokio::select;
|
||||||
|
use tonic::Status;
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
use x25519_dalek::{EphemeralSecret, PublicKey};
|
use x25519_dalek::{EphemeralSecret, PublicKey};
|
||||||
|
|
||||||
@@ -76,9 +77,53 @@ pub enum UserAgentError {
|
|||||||
DatabaseOperationFailed,
|
DatabaseOperationFailed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<UserAgentError> for Status {
|
||||||
|
fn from(value: UserAgentError) -> Self {
|
||||||
|
match value {
|
||||||
|
UserAgentError::MissingRequestPayload | UserAgentError::UnexpectedRequestPayload => {
|
||||||
|
Status::invalid_argument("Expected message with payload")
|
||||||
|
}
|
||||||
|
UserAgentError::InvalidStateForChallengeSolution => {
|
||||||
|
Status::invalid_argument("Invalid state for challenge solution")
|
||||||
|
}
|
||||||
|
UserAgentError::InvalidStateForUnsealEncryptedKey => {
|
||||||
|
Status::failed_precondition("Invalid state for unseal encrypted key")
|
||||||
|
}
|
||||||
|
UserAgentError::InvalidClientPubkeyLength => {
|
||||||
|
Status::invalid_argument("client_pubkey must be 32 bytes")
|
||||||
|
}
|
||||||
|
UserAgentError::InvalidAuthPubkeyLength => {
|
||||||
|
Status::invalid_argument("Expected pubkey to have specific length")
|
||||||
|
}
|
||||||
|
UserAgentError::InvalidAuthPubkeyEncoding => {
|
||||||
|
Status::invalid_argument("Failed to convert pubkey to VerifyingKey")
|
||||||
|
}
|
||||||
|
UserAgentError::InvalidSignatureLength => {
|
||||||
|
Status::invalid_argument("Invalid signature length")
|
||||||
|
}
|
||||||
|
UserAgentError::InvalidBootstrapToken => {
|
||||||
|
Status::invalid_argument("Invalid bootstrap token")
|
||||||
|
}
|
||||||
|
UserAgentError::PublicKeyNotRegistered => {
|
||||||
|
Status::unauthenticated("Public key not registered")
|
||||||
|
}
|
||||||
|
UserAgentError::InvalidChallengeSolution => {
|
||||||
|
Status::unauthenticated("Invalid challenge solution")
|
||||||
|
}
|
||||||
|
UserAgentError::StateTransitionFailed => Status::internal("State machine error"),
|
||||||
|
UserAgentError::BootstrapperActorUnreachable => {
|
||||||
|
Status::internal("Bootstrap token consumption failed")
|
||||||
|
}
|
||||||
|
UserAgentError::KeyHolderActorUnreachable => Status::internal("Vault is not available"),
|
||||||
|
UserAgentError::DatabasePoolUnavailable => Status::internal("Database pool error"),
|
||||||
|
UserAgentError::DatabaseOperationFailed => Status::internal("Database error"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct UserAgentActor<Transport>
|
pub struct UserAgentActor<Transport>
|
||||||
where
|
where
|
||||||
Transport: Bi<UserAgentRequest, Result<UserAgentResponse, UserAgentError>>,
|
Transport: Bi<UserAgentRequest, UserAgentResponse, UserAgentError>,
|
||||||
{
|
{
|
||||||
db: db::DatabasePool,
|
db: db::DatabasePool,
|
||||||
actors: GlobalActors,
|
actors: GlobalActors,
|
||||||
@@ -88,7 +133,7 @@ where
|
|||||||
|
|
||||||
impl<Transport> UserAgentActor<Transport>
|
impl<Transport> UserAgentActor<Transport>
|
||||||
where
|
where
|
||||||
Transport: Bi<UserAgentRequest, Result<UserAgentResponse, UserAgentError>>,
|
Transport: Bi<UserAgentRequest, UserAgentResponse, UserAgentError>,
|
||||||
{
|
{
|
||||||
pub(crate) fn new(context: ServerContext, transport: Transport) -> Self {
|
pub(crate) fn new(context: ServerContext, transport: Transport) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -277,7 +322,7 @@ fn unseal_response(payload: UserAgentResponsePayload) -> UserAgentResponse {
|
|||||||
|
|
||||||
impl<Transport> UserAgentActor<Transport>
|
impl<Transport> UserAgentActor<Transport>
|
||||||
where
|
where
|
||||||
Transport: Bi<UserAgentRequest, Result<UserAgentResponse, UserAgentError>>,
|
Transport: Bi<UserAgentRequest, UserAgentResponse, UserAgentError>,
|
||||||
{
|
{
|
||||||
async fn handle_unseal_request(&mut self, req: UnsealStart) -> Output {
|
async fn handle_unseal_request(&mut self, req: UnsealStart) -> Output {
|
||||||
let secret = EphemeralSecret::random();
|
let secret = EphemeralSecret::random();
|
||||||
@@ -425,7 +470,7 @@ where
|
|||||||
|
|
||||||
impl<Transport> Actor for UserAgentActor<Transport>
|
impl<Transport> Actor for UserAgentActor<Transport>
|
||||||
where
|
where
|
||||||
Transport: Bi<UserAgentRequest, Result<UserAgentResponse, UserAgentError>>,
|
Transport: Bi<UserAgentRequest, UserAgentResponse, UserAgentError>,
|
||||||
{
|
{
|
||||||
type Args = Self;
|
type Args = Self;
|
||||||
|
|
||||||
@@ -476,7 +521,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl UserAgentActor<DummyTransport<UserAgentRequest, Result<UserAgentResponse, UserAgentError>>> {
|
impl UserAgentActor<DummyTransport<UserAgentRequest, UserAgentResponse, UserAgentError>> {
|
||||||
pub fn new_manual(db: db::DatabasePool, actors: GlobalActors) -> Self {
|
pub fn new_manual(db: db::DatabasePool, actors: GlobalActors) -> Self {
|
||||||
Self {
|
Self {
|
||||||
db,
|
db,
|
||||||
|
|||||||
24
server/crates/arbiter-server/src/errors.rs
Normal file
24
server/crates/arbiter-server/src/errors.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
use tonic::Status;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
pub trait GrpcStatusExt<T> {
|
||||||
|
fn to_status(self) -> Result<T, Status>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> GrpcStatusExt<T> for Result<T, diesel::result::Error> {
|
||||||
|
fn to_status(self) -> Result<T, Status> {
|
||||||
|
self.map_err(|e| {
|
||||||
|
error!(error = ?e, "Database error");
|
||||||
|
Status::internal("Database error")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> GrpcStatusExt<T> for Result<T, crate::db::PoolError> {
|
||||||
|
fn to_status(self) -> Result<T, Status> {
|
||||||
|
self.map_err(|e| {
|
||||||
|
error!(error = ?e, "Database pool error");
|
||||||
|
Status::internal("Database pool error")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
use arbiter_proto::{
|
use arbiter_proto::{
|
||||||
proto::{ClientRequest, ClientResponse, UserAgentRequest, UserAgentResponse},
|
proto::{ClientRequest, ClientResponse, UserAgentRequest, UserAgentResponse},
|
||||||
transport::{IdentityRecvConverter, SendConverter, grpc},
|
transport::GrpcAdapter,
|
||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use kameo::actor::Spawn;
|
use kameo::actor::Spawn;
|
||||||
@@ -12,79 +12,17 @@ use tonic::{Request, Response, Status};
|
|||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
actors::user_agent::{UserAgentActor, UserAgentError},
|
actors::user_agent::UserAgentActor,
|
||||||
context::ServerContext,
|
context::ServerContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod actors;
|
pub mod actors;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
mod errors;
|
||||||
|
|
||||||
const DEFAULT_CHANNEL_SIZE: usize = 1000;
|
const DEFAULT_CHANNEL_SIZE: usize = 1000;
|
||||||
|
|
||||||
/// Converts User Agent domain outbounds into the tonic stream item emitted by
|
|
||||||
/// the server.§
|
|
||||||
///
|
|
||||||
/// The conversion is defined at the server boundary so the actor module remains
|
|
||||||
/// focused on domain semantics and does not depend on tonic status encoding.
|
|
||||||
struct UserAgentGrpcSender;
|
|
||||||
|
|
||||||
impl SendConverter for UserAgentGrpcSender {
|
|
||||||
type Input = Result<UserAgentResponse, UserAgentError>;
|
|
||||||
type Output = Result<UserAgentResponse, Status>;
|
|
||||||
|
|
||||||
fn convert(&self, item: Self::Input) -> Self::Output {
|
|
||||||
match item {
|
|
||||||
Ok(message) => Ok(message),
|
|
||||||
Err(err) => Err(user_agent_error_status(err)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Maps User Agent domain errors to public gRPC transport errors for the
|
|
||||||
/// `user_agent` streaming endpoint.
|
|
||||||
fn user_agent_error_status(value: UserAgentError) -> Status {
|
|
||||||
match value {
|
|
||||||
UserAgentError::MissingRequestPayload | UserAgentError::UnexpectedRequestPayload => {
|
|
||||||
Status::invalid_argument("Expected message with payload")
|
|
||||||
}
|
|
||||||
UserAgentError::InvalidStateForChallengeSolution => {
|
|
||||||
Status::invalid_argument("Invalid state for challenge solution")
|
|
||||||
}
|
|
||||||
UserAgentError::InvalidStateForUnsealEncryptedKey => {
|
|
||||||
Status::failed_precondition("Invalid state for unseal encrypted key")
|
|
||||||
}
|
|
||||||
UserAgentError::InvalidClientPubkeyLength => {
|
|
||||||
Status::invalid_argument("client_pubkey must be 32 bytes")
|
|
||||||
}
|
|
||||||
UserAgentError::InvalidAuthPubkeyLength => {
|
|
||||||
Status::invalid_argument("Expected pubkey to have specific length")
|
|
||||||
}
|
|
||||||
UserAgentError::InvalidAuthPubkeyEncoding => {
|
|
||||||
Status::invalid_argument("Failed to convert pubkey to VerifyingKey")
|
|
||||||
}
|
|
||||||
UserAgentError::InvalidSignatureLength => {
|
|
||||||
Status::invalid_argument("Invalid signature length")
|
|
||||||
}
|
|
||||||
UserAgentError::InvalidBootstrapToken => {
|
|
||||||
Status::invalid_argument("Invalid bootstrap token")
|
|
||||||
}
|
|
||||||
UserAgentError::PublicKeyNotRegistered => {
|
|
||||||
Status::unauthenticated("Public key not registered")
|
|
||||||
}
|
|
||||||
UserAgentError::InvalidChallengeSolution => {
|
|
||||||
Status::unauthenticated("Invalid challenge solution")
|
|
||||||
}
|
|
||||||
UserAgentError::StateTransitionFailed => Status::internal("State machine error"),
|
|
||||||
UserAgentError::BootstrapperActorUnreachable => {
|
|
||||||
Status::internal("Bootstrap token consumption failed")
|
|
||||||
}
|
|
||||||
UserAgentError::KeyHolderActorUnreachable => Status::internal("Vault is not available"),
|
|
||||||
UserAgentError::DatabasePoolUnavailable => Status::internal("Database pool error"),
|
|
||||||
UserAgentError::DatabaseOperationFailed => Status::internal("Database error"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
context: ServerContext,
|
context: ServerContext,
|
||||||
}
|
}
|
||||||
@@ -115,13 +53,9 @@ impl arbiter_proto::proto::arbiter_service_server::ArbiterService for Server {
|
|||||||
let req_stream = request.into_inner();
|
let req_stream = request.into_inner();
|
||||||
let (tx, rx) = mpsc::channel(DEFAULT_CHANNEL_SIZE);
|
let (tx, rx) = mpsc::channel(DEFAULT_CHANNEL_SIZE);
|
||||||
|
|
||||||
let transport = grpc::GrpcAdapter::new(
|
let adapter = GrpcAdapter::new(tx, req_stream);
|
||||||
tx,
|
|
||||||
req_stream,
|
UserAgentActor::spawn(UserAgentActor::new(self.context.clone(), adapter));
|
||||||
IdentityRecvConverter::<UserAgentRequest>::new(),
|
|
||||||
UserAgentGrpcSender,
|
|
||||||
);
|
|
||||||
UserAgentActor::spawn(UserAgentActor::new(self.context.clone(), transport));
|
|
||||||
|
|
||||||
info!(event = "connection established", "grpc.user_agent");
|
info!(event = "connection established", "grpc.user_agent");
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ pub async fn test_bootstrap_invalid_token_auth() {
|
|||||||
match result {
|
match result {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
assert_eq!(err, UserAgentError::InvalidBootstrapToken);
|
assert_eq!(err, UserAgentError::InvalidBootstrapToken);
|
||||||
|
let status: tonic::Status = err.into();
|
||||||
|
assert_eq!(status.code(), tonic::Code::InvalidArgument);
|
||||||
}
|
}
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
panic!("Expected error due to invalid bootstrap token, but got success");
|
panic!("Expected error due to invalid bootstrap token, but got success");
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ use chacha20poly1305::{AeadInPlace, XChaCha20Poly1305, XNonce, aead::KeyInit};
|
|||||||
use memsafe::MemSafe;
|
use memsafe::MemSafe;
|
||||||
use x25519_dalek::{EphemeralSecret, PublicKey};
|
use x25519_dalek::{EphemeralSecret, PublicKey};
|
||||||
|
|
||||||
type TestUserAgent =
|
type TestUserAgent = UserAgentActor<DummyTransport<UserAgentRequest, UserAgentResponse, UserAgentError>>;
|
||||||
UserAgentActor<DummyTransport<UserAgentRequest, Result<UserAgentResponse, UserAgentError>>>;
|
|
||||||
|
|
||||||
fn auth_request(payload: ClientAuthPayload) -> UserAgentRequest {
|
fn auth_request(payload: ClientAuthPayload) -> UserAgentRequest {
|
||||||
UserAgentRequest {
|
UserAgentRequest {
|
||||||
|
|||||||
@@ -9,12 +9,7 @@ arbiter-proto.path = "../arbiter-proto"
|
|||||||
kameo.workspace = true
|
kameo.workspace = true
|
||||||
tokio = {workspace = true, features = ["net"]}
|
tokio = {workspace = true, features = ["net"]}
|
||||||
tonic.workspace = true
|
tonic.workspace = true
|
||||||
tonic.features = ["tls-aws-lc"]
|
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
ed25519-dalek.workspace = true
|
ed25519-dalek.workspace = true
|
||||||
smlang.workspace = true
|
smlang.workspace = true
|
||||||
x25519-dalek.workspace = true
|
x25519-dalek.workspace = true
|
||||||
thiserror.workspace = true
|
|
||||||
tokio-stream.workspace = true
|
|
||||||
http = "1.4.0"
|
|
||||||
rustls-webpki = { version = "0.103.9", features = ["aws-lc-rs"] }
|
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
use arbiter_proto::{
|
|
||||||
proto::{
|
|
||||||
UserAgentRequest, UserAgentResponse, arbiter_service_client::ArbiterServiceClient,
|
|
||||||
},
|
|
||||||
transport::{IdentityRecvConverter, IdentitySendConverter, RecvConverter, grpc},
|
|
||||||
url::ArbiterUrl,
|
|
||||||
};
|
|
||||||
use ed25519_dalek::SigningKey;
|
|
||||||
use kameo::actor::{ActorRef, Spawn};
|
|
||||||
|
|
||||||
use tokio::sync::mpsc;
|
|
||||||
use tokio_stream::wrappers::ReceiverStream;
|
|
||||||
|
|
||||||
use tonic::transport::ClientTlsConfig;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum ConnectError {
|
|
||||||
#[error("Could establish connection")]
|
|
||||||
Connection(#[from] tonic::transport::Error),
|
|
||||||
|
|
||||||
#[error("Invalid server URI")]
|
|
||||||
InvalidUri(#[from] http::uri::InvalidUri),
|
|
||||||
|
|
||||||
#[error("Invalid CA certificate")]
|
|
||||||
InvalidCaCert(#[from] webpki::Error),
|
|
||||||
|
|
||||||
#[error("gRPC error")]
|
|
||||||
Grpc(#[from] tonic::Status),
|
|
||||||
}
|
|
||||||
|
|
||||||
use super::UserAgentActor;
|
|
||||||
|
|
||||||
pub type UserAgentGrpc = ActorRef<
|
|
||||||
UserAgentActor<
|
|
||||||
grpc::GrpcAdapter<
|
|
||||||
IdentityRecvConverter<UserAgentResponse>,
|
|
||||||
IdentitySendConverter<UserAgentRequest>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>;
|
|
||||||
pub async fn connect_grpc(
|
|
||||||
url: ArbiterUrl,
|
|
||||||
key: SigningKey,
|
|
||||||
) -> Result<UserAgentGrpc, ConnectError> {
|
|
||||||
let bootstrap_token = url.bootstrap_token.clone();
|
|
||||||
let anchor = webpki::anchor_from_trusted_cert(&url.ca_cert)?.to_owned();
|
|
||||||
let tls = ClientTlsConfig::new().trust_anchor(anchor);
|
|
||||||
|
|
||||||
// TODO: if `host` is localhost, we need to verify server's process authenticity
|
|
||||||
let channel = tonic::transport::Channel::from_shared(format!("{}:{}", url.host, url.port))?
|
|
||||||
.tls_config(tls)?
|
|
||||||
.connect()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut client = ArbiterServiceClient::new(channel);
|
|
||||||
let (tx, rx) = mpsc::channel(16);
|
|
||||||
let bistream = client.user_agent(ReceiverStream::new(rx)).await?;
|
|
||||||
let bistream = bistream.into_inner();
|
|
||||||
|
|
||||||
let adapter = grpc::GrpcAdapter::new(
|
|
||||||
tx,
|
|
||||||
bistream,
|
|
||||||
IdentityRecvConverter::new(),
|
|
||||||
IdentitySendConverter::new(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let actor = UserAgentActor::spawn(UserAgentActor::new(key, bootstrap_token, adapter));
|
|
||||||
|
|
||||||
Ok(actor)
|
|
||||||
}
|
|
||||||
@@ -1,209 +1,13 @@
|
|||||||
use arbiter_proto::{
|
use ed25519_dalek::SigningKey;
|
||||||
format_challenge,
|
use kameo::Actor;
|
||||||
proto::{
|
use tonic::transport::CertificateDer;
|
||||||
UserAgentRequest, UserAgentResponse,
|
|
||||||
auth::{
|
|
||||||
self, AuthChallengeRequest, AuthOk, ClientMessage as AuthClientMessage,
|
|
||||||
ServerMessage as AuthServerMessage, client_message::Payload as ClientAuthPayload,
|
|
||||||
server_message::Payload as ServerAuthPayload,
|
|
||||||
},
|
|
||||||
user_agent_request::Payload as UserAgentRequestPayload,
|
|
||||||
user_agent_response::Payload as UserAgentResponsePayload,
|
|
||||||
},
|
|
||||||
transport::Bi,
|
|
||||||
};
|
|
||||||
use ed25519_dalek::{Signer, SigningKey};
|
|
||||||
use kameo::{Actor, actor::ActorRef};
|
|
||||||
use smlang::statemachine;
|
|
||||||
use tokio::select;
|
|
||||||
use tracing::{error, info};
|
|
||||||
|
|
||||||
statemachine! {
|
struct Storage {
|
||||||
name: UserAgent,
|
pub identity: SigningKey,
|
||||||
custom_error: false,
|
pub server_ca_cert: CertificateDer<'static>,
|
||||||
transitions: {
|
|
||||||
*Init + SentAuthChallengeRequest = WaitingForServerAuth,
|
|
||||||
WaitingForServerAuth + ReceivedAuthChallenge = WaitingForAuthOk,
|
|
||||||
WaitingForServerAuth + ReceivedAuthOk = Authenticated,
|
|
||||||
WaitingForAuthOk + ReceivedAuthOk = Authenticated,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DummyContext;
|
#[derive(Actor)]
|
||||||
impl UserAgentStateMachineContext for DummyContext {}
|
pub struct UserAgent {
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum InboundError {
|
|
||||||
#[error("Invalid user agent response")]
|
|
||||||
InvalidResponse,
|
|
||||||
#[error("Expected response payload")]
|
|
||||||
MissingResponsePayload,
|
|
||||||
#[error("Unexpected response payload")]
|
|
||||||
UnexpectedResponsePayload,
|
|
||||||
#[error("Invalid state for auth challenge")]
|
|
||||||
InvalidStateForAuthChallenge,
|
|
||||||
#[error("Invalid state for auth ok")]
|
|
||||||
InvalidStateForAuthOk,
|
|
||||||
#[error("State machine error")]
|
|
||||||
StateTransitionFailed,
|
|
||||||
#[error("Transport send failed")]
|
|
||||||
TransportSendFailed,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UserAgentActor<Transport>
|
|
||||||
where
|
|
||||||
Transport: Bi<UserAgentResponse, UserAgentRequest>,
|
|
||||||
{
|
|
||||||
key: SigningKey,
|
|
||||||
bootstrap_token: Option<String>,
|
|
||||||
state: UserAgentStateMachine<DummyContext>,
|
|
||||||
transport: Transport,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Transport> UserAgentActor<Transport>
|
|
||||||
where
|
|
||||||
Transport: Bi<UserAgentResponse, UserAgentRequest>,
|
|
||||||
{
|
|
||||||
pub fn new(key: SigningKey, bootstrap_token: Option<String>, transport: Transport) -> Self {
|
|
||||||
Self {
|
|
||||||
key,
|
|
||||||
bootstrap_token,
|
|
||||||
state: UserAgentStateMachine::new(DummyContext),
|
|
||||||
transport,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transition(&mut self, event: UserAgentEvents) -> Result<(), InboundError> {
|
|
||||||
self.state.process_event(event).map_err(|e| {
|
|
||||||
error!(?e, "useragent state transition failed");
|
|
||||||
InboundError::StateTransitionFailed
|
|
||||||
})?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn auth_request(payload: ClientAuthPayload) -> UserAgentRequest {
|
|
||||||
UserAgentRequest {
|
|
||||||
payload: Some(UserAgentRequestPayload::AuthMessage(AuthClientMessage {
|
|
||||||
payload: Some(payload),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_auth_challenge_request(&mut self) -> Result<(), InboundError> {
|
|
||||||
let req = AuthChallengeRequest {
|
|
||||||
pubkey: self.key.verifying_key().to_bytes().to_vec(),
|
|
||||||
bootstrap_token: self.bootstrap_token.take(),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.transition(UserAgentEvents::SentAuthChallengeRequest)?;
|
|
||||||
|
|
||||||
self.transport
|
|
||||||
.send(Self::auth_request(ClientAuthPayload::AuthChallengeRequest(
|
|
||||||
req,
|
|
||||||
)))
|
|
||||||
.await
|
|
||||||
.map_err(|_| InboundError::TransportSendFailed)?;
|
|
||||||
|
|
||||||
info!(actor = "useragent", "auth.request.sent");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_auth_challenge(
|
|
||||||
&mut self,
|
|
||||||
challenge: auth::AuthChallenge,
|
|
||||||
) -> Result<(), InboundError> {
|
|
||||||
self.transition(UserAgentEvents::ReceivedAuthChallenge)?;
|
|
||||||
|
|
||||||
let formatted = format_challenge(&challenge);
|
|
||||||
let signature = self.key.sign(&formatted);
|
|
||||||
let solution = auth::AuthChallengeSolution {
|
|
||||||
signature: signature.to_bytes().to_vec(),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.transport
|
|
||||||
.send(Self::auth_request(
|
|
||||||
ClientAuthPayload::AuthChallengeSolution(solution),
|
|
||||||
))
|
|
||||||
.await
|
|
||||||
.map_err(|_| InboundError::TransportSendFailed)?;
|
|
||||||
|
|
||||||
info!(actor = "useragent", "auth.solution.sent");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_auth_ok(&mut self, _ok: AuthOk) -> Result<(), InboundError> {
|
|
||||||
self.transition(UserAgentEvents::ReceivedAuthOk)?;
|
|
||||||
info!(actor = "useragent", "auth.ok");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn process_inbound_transport(
|
|
||||||
&mut self,
|
|
||||||
inbound: UserAgentResponse
|
|
||||||
) -> Result<(), InboundError> {
|
|
||||||
let payload = inbound
|
|
||||||
.payload
|
|
||||||
.ok_or(InboundError::MissingResponsePayload)?;
|
|
||||||
|
|
||||||
match payload {
|
|
||||||
UserAgentResponsePayload::AuthMessage(AuthServerMessage {
|
|
||||||
payload: Some(ServerAuthPayload::AuthChallenge(challenge)),
|
|
||||||
}) => self.handle_auth_challenge(challenge).await,
|
|
||||||
UserAgentResponsePayload::AuthMessage(AuthServerMessage {
|
|
||||||
payload: Some(ServerAuthPayload::AuthOk(ok)),
|
|
||||||
}) => self.handle_auth_ok(ok),
|
|
||||||
_ => Err(InboundError::UnexpectedResponsePayload),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Transport> Actor for UserAgentActor<Transport>
|
|
||||||
where
|
|
||||||
Transport: Bi<UserAgentResponse, UserAgentRequest>,
|
|
||||||
{
|
|
||||||
type Args = Self;
|
|
||||||
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
async fn on_start(
|
|
||||||
mut args: Self::Args,
|
|
||||||
_actor_ref: ActorRef<Self>,
|
|
||||||
) -> Result<Self, Self::Error> {
|
|
||||||
if let Err(err) = args.send_auth_challenge_request().await {
|
|
||||||
error!(?err, actor = "useragent", "auth.start.failed");
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
Ok(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn next(
|
|
||||||
&mut self,
|
|
||||||
_actor_ref: kameo::prelude::WeakActorRef<Self>,
|
|
||||||
mailbox_rx: &mut kameo::prelude::MailboxReceiver<Self>,
|
|
||||||
) -> Option<kameo::mailbox::Signal<Self>> {
|
|
||||||
loop {
|
|
||||||
select! {
|
|
||||||
signal = mailbox_rx.recv() => {
|
|
||||||
return signal;
|
|
||||||
}
|
|
||||||
inbound = self.transport.recv() => {
|
|
||||||
match inbound {
|
|
||||||
Some(inbound) => {
|
|
||||||
if let Err(err) = self.process_inbound_transport(inbound).await {
|
|
||||||
error!(?err, actor = "useragent", "transport.inbound.failed");
|
|
||||||
return Some(kameo::mailbox::Signal::Stop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
info!(actor = "useragent", "transport.closed");
|
|
||||||
return Some(kameo::mailbox::Signal::Stop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod grpc;
|
|
||||||
pub use grpc::{connect_grpc, ConnectError};
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
use arbiter_proto::{
|
|
||||||
format_challenge,
|
|
||||||
proto::{
|
|
||||||
UserAgentRequest, UserAgentResponse,
|
|
||||||
auth::{
|
|
||||||
AuthChallenge, AuthOk, ClientMessage as AuthClientMessage,
|
|
||||||
ServerMessage as AuthServerMessage, client_message::Payload as ClientAuthPayload,
|
|
||||||
server_message::Payload as ServerAuthPayload,
|
|
||||||
},
|
|
||||||
user_agent_request::Payload as UserAgentRequestPayload,
|
|
||||||
user_agent_response::Payload as UserAgentResponsePayload,
|
|
||||||
},
|
|
||||||
transport::Bi,
|
|
||||||
};
|
|
||||||
use arbiter_useragent::{InboundError, UserAgentActor};
|
|
||||||
use ed25519_dalek::SigningKey;
|
|
||||||
use kameo::actor::Spawn;
|
|
||||||
use tokio::sync::mpsc;
|
|
||||||
use tokio::time::{Duration, timeout};
|
|
||||||
|
|
||||||
struct TestTransport {
|
|
||||||
inbound_rx: mpsc::Receiver<UserAgentResponse>,
|
|
||||||
outbound_tx: mpsc::Sender<UserAgentRequest>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bi<UserAgentResponse, UserAgentRequest> for TestTransport {
|
|
||||||
async fn send(&mut self, item: UserAgentRequest) -> Result<(), arbiter_proto::transport::Error> {
|
|
||||||
self.outbound_tx
|
|
||||||
.send(item)
|
|
||||||
.await
|
|
||||||
.map_err(|_| arbiter_proto::transport::Error::ChannelClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn recv(&mut self) -> Option<UserAgentResponse> {
|
|
||||||
self.inbound_rx.recv().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_transport() -> (
|
|
||||||
TestTransport,
|
|
||||||
mpsc::Sender<UserAgentResponse>,
|
|
||||||
mpsc::Receiver<UserAgentRequest>,
|
|
||||||
) {
|
|
||||||
let (inbound_tx, inbound_rx) = mpsc::channel(8);
|
|
||||||
let (outbound_tx, outbound_rx) = mpsc::channel(8);
|
|
||||||
(
|
|
||||||
TestTransport {
|
|
||||||
inbound_rx,
|
|
||||||
outbound_tx,
|
|
||||||
},
|
|
||||||
inbound_tx,
|
|
||||||
outbound_rx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_key() -> SigningKey {
|
|
||||||
SigningKey::from_bytes(&[7u8; 32])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn auth_response(payload: ServerAuthPayload) -> UserAgentResponse {
|
|
||||||
UserAgentResponse {
|
|
||||||
payload: Some(UserAgentResponsePayload::AuthMessage(AuthServerMessage {
|
|
||||||
payload: Some(payload),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn sends_auth_request_on_start_with_bootstrap_token() {
|
|
||||||
let key = test_key();
|
|
||||||
let pubkey = key.verifying_key().to_bytes().to_vec();
|
|
||||||
let bootstrap_token = Some("bootstrap-123".to_string());
|
|
||||||
let (transport, inbound_tx, mut outbound_rx) = make_transport();
|
|
||||||
|
|
||||||
let actor = UserAgentActor::spawn(UserAgentActor::new(key, bootstrap_token.clone(), transport));
|
|
||||||
|
|
||||||
let outbound = timeout(Duration::from_secs(1), outbound_rx.recv())
|
|
||||||
.await
|
|
||||||
.expect("timed out waiting for auth request")
|
|
||||||
.expect("channel closed before auth request");
|
|
||||||
|
|
||||||
let UserAgentRequest {
|
|
||||||
payload: Some(UserAgentRequestPayload::AuthMessage(AuthClientMessage {
|
|
||||||
payload: Some(ClientAuthPayload::AuthChallengeRequest(req)),
|
|
||||||
})),
|
|
||||||
} = outbound
|
|
||||||
else {
|
|
||||||
panic!("expected auth challenge request");
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(req.pubkey, pubkey);
|
|
||||||
assert_eq!(req.bootstrap_token, bootstrap_token);
|
|
||||||
|
|
||||||
drop(inbound_tx);
|
|
||||||
drop(actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn challenge_flow_sends_solution_from_transport_inbound() {
|
|
||||||
let key = test_key();
|
|
||||||
let verify_key = key.verifying_key();
|
|
||||||
let (transport, inbound_tx, mut outbound_rx) = make_transport();
|
|
||||||
|
|
||||||
let actor = UserAgentActor::spawn(UserAgentActor::new(key, None, transport));
|
|
||||||
|
|
||||||
let _initial_auth_request = timeout(Duration::from_secs(1), outbound_rx.recv())
|
|
||||||
.await
|
|
||||||
.expect("timed out waiting for initial auth request")
|
|
||||||
.expect("missing initial auth request");
|
|
||||||
|
|
||||||
let challenge = AuthChallenge {
|
|
||||||
pubkey: verify_key.to_bytes().to_vec(),
|
|
||||||
nonce: 42,
|
|
||||||
};
|
|
||||||
inbound_tx
|
|
||||||
.send(auth_response(ServerAuthPayload::AuthChallenge(challenge.clone())))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let outbound = timeout(Duration::from_secs(1), outbound_rx.recv())
|
|
||||||
.await
|
|
||||||
.expect("timed out waiting for challenge solution")
|
|
||||||
.expect("missing challenge solution");
|
|
||||||
|
|
||||||
let UserAgentRequest {
|
|
||||||
payload: Some(UserAgentRequestPayload::AuthMessage(AuthClientMessage {
|
|
||||||
payload: Some(ClientAuthPayload::AuthChallengeSolution(solution)),
|
|
||||||
})),
|
|
||||||
} = outbound
|
|
||||||
else {
|
|
||||||
panic!("expected auth challenge solution");
|
|
||||||
};
|
|
||||||
|
|
||||||
let formatted = format_challenge(&challenge);
|
|
||||||
let sig: ed25519_dalek::Signature = solution
|
|
||||||
.signature
|
|
||||||
.as_slice()
|
|
||||||
.try_into()
|
|
||||||
.expect("signature bytes length");
|
|
||||||
verify_key
|
|
||||||
.verify_strict(&formatted, &sig)
|
|
||||||
.expect("solution signature should verify");
|
|
||||||
|
|
||||||
inbound_tx
|
|
||||||
.send(auth_response(ServerAuthPayload::AuthOk(AuthOk {})))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
drop(inbound_tx);
|
|
||||||
drop(actor);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user