server: remove username and password support (#383)
* remove username and password support * remove sqlx dependency
This commit is contained in:
parent
fe7ea0a27d
commit
2a07585b85
|
@ -52,18 +52,6 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
|
@ -73,12 +61,6 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.15"
|
||||
|
@ -134,18 +116,6 @@ version = "1.0.86"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"blake2",
|
||||
"cpufeatures",
|
||||
"password-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.8"
|
||||
|
@ -179,15 +149,6 @@ dependencies = [
|
|||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atoi"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-polyfill"
|
||||
version = "1.0.3"
|
||||
|
@ -391,9 +352,6 @@ name = "bitflags"
|
|||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
|
@ -570,15 +528,6 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-crc32-nostd"
|
||||
version = "1.3.1"
|
||||
|
@ -661,21 +610,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
|
||||
dependencies = [
|
||||
"crc-catalog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc-catalog"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.1.2"
|
||||
|
@ -691,15 +625,6 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.20"
|
||||
|
@ -784,7 +709,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"pem-rfc7468",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
|
@ -843,7 +767,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"const-oid",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
@ -905,12 +828,6 @@ dependencies = [
|
|||
"litrs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dotenvy"
|
||||
version = "0.15.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||
|
||||
[[package]]
|
||||
name = "ed25519"
|
||||
version = "2.2.3"
|
||||
|
@ -940,9 +857,6 @@ name = "either"
|
|||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-io"
|
||||
|
@ -981,28 +895,6 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "etcetera"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"home",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exitcode"
|
||||
version = "1.1.2"
|
||||
|
@ -1041,17 +933,6 @@ version = "0.2.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||
|
||||
[[package]]
|
||||
name = "flume"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -1213,17 +1094,6 @@ dependencies = [
|
|||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-intrusive"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"lock_api",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.31"
|
||||
|
@ -1288,10 +1158,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1354,19 +1222,6 @@ name = "hashbrown"
|
|||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "headers"
|
||||
|
@ -1433,33 +1288,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
|
||||
dependencies = [
|
||||
"hmac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
|
@ -1687,9 +1515,6 @@ name = "lazy_static"
|
|||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
|
@ -1697,12 +1522,6 @@ version = "0.2.164"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.3"
|
||||
|
@ -1713,17 +1532,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
|
@ -1767,16 +1575,6 @@ version = "0.7.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
|
@ -1829,12 +1627,6 @@ dependencies = [
|
|||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.4"
|
||||
|
@ -1914,16 +1706,6 @@ dependencies = [
|
|||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
|
@ -1934,59 +1716,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint-dig"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"lazy_static",
|
||||
"libm",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"smallvec",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.2"
|
||||
|
@ -2064,12 +1799,6 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
|
@ -2088,7 +1817,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.5.3",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
@ -2119,29 +1848,6 @@ dependencies = [
|
|||
"xeddsa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "password-auth"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a2a4764cc1f8d961d802af27193c6f4f0124bd0e76e8393cf818e18880f0524"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"getrandom",
|
||||
"password-hash",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pasta_curves"
|
||||
version = "0.5.1"
|
||||
|
@ -2155,21 +1861,6 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
|
@ -2217,17 +1908,6 @@ dependencies = [
|
|||
"crossbeam-channel",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs1"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
|
||||
dependencies = [
|
||||
"der",
|
||||
"pkcs8",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs8"
|
||||
version = "0.10.2"
|
||||
|
@ -2292,7 +1972,7 @@ version = "0.2.18"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f"
|
||||
dependencies = [
|
||||
"zerocopy 0.6.6",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2377,15 +2057,6 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.3"
|
||||
|
@ -2529,26 +2200,6 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"digest",
|
||||
"num-bigint-dig",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"pkcs1",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"signature",
|
||||
"spki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtoolbox"
|
||||
version = "0.0.2"
|
||||
|
@ -2789,7 +2440,6 @@ dependencies = [
|
|||
"frost-ed25519",
|
||||
"frost-rerandomized",
|
||||
"hex",
|
||||
"password-auth",
|
||||
"rand",
|
||||
"reddsa",
|
||||
"regex",
|
||||
|
@ -2798,7 +2448,6 @@ dependencies = [
|
|||
"serde_json",
|
||||
"serdect",
|
||||
"snow",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
|
@ -2853,7 +2502,6 @@ version = "2.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
|
@ -2871,9 +2519,6 @@ name = "smallvec"
|
|||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "snow"
|
||||
|
@ -2920,218 +2565,6 @@ dependencies = [
|
|||
"der",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlformat"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f"
|
||||
dependencies = [
|
||||
"nom",
|
||||
"unicode_categories",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e"
|
||||
dependencies = [
|
||||
"sqlx-core",
|
||||
"sqlx-macros",
|
||||
"sqlx-mysql",
|
||||
"sqlx-postgres",
|
||||
"sqlx-sqlite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-core"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"crc",
|
||||
"crossbeam-queue",
|
||||
"either",
|
||||
"event-listener",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-intrusive",
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"hashbrown",
|
||||
"hashlink",
|
||||
"hex",
|
||||
"indexmap",
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"smallvec",
|
||||
"sqlformat",
|
||||
"thiserror 1.0.69",
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-macros"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"sqlx-core",
|
||||
"sqlx-macros-core",
|
||||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-macros-core"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5"
|
||||
dependencies = [
|
||||
"dotenvy",
|
||||
"either",
|
||||
"heck 0.5.0",
|
||||
"hex",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"sqlx-core",
|
||||
"sqlx-mysql",
|
||||
"sqlx-postgres",
|
||||
"sqlx-sqlite",
|
||||
"syn 2.0.87",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-mysql"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.22.1",
|
||||
"bitflags 2.6.0",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"crc",
|
||||
"digest",
|
||||
"dotenvy",
|
||||
"either",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"generic-array",
|
||||
"hex",
|
||||
"hkdf",
|
||||
"hmac",
|
||||
"itoa",
|
||||
"log",
|
||||
"md-5",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"rsa",
|
||||
"serde",
|
||||
"sha1",
|
||||
"sha2",
|
||||
"smallvec",
|
||||
"sqlx-core",
|
||||
"stringprep",
|
||||
"thiserror 1.0.69",
|
||||
"time",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-postgres"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.22.1",
|
||||
"bitflags 2.6.0",
|
||||
"byteorder",
|
||||
"crc",
|
||||
"dotenvy",
|
||||
"etcetera",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"hkdf",
|
||||
"hmac",
|
||||
"home",
|
||||
"itoa",
|
||||
"log",
|
||||
"md-5",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"smallvec",
|
||||
"sqlx-core",
|
||||
"stringprep",
|
||||
"thiserror 1.0.69",
|
||||
"time",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-sqlite"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"flume",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-intrusive",
|
||||
"futures-util",
|
||||
"libsqlite3-sys",
|
||||
"log",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_urlencoded",
|
||||
"sqlx-core",
|
||||
"time",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable-eyre"
|
||||
version = "0.2.2"
|
||||
|
@ -3155,17 +2588,6 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "stringprep"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
"unicode-properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
|
@ -3461,17 +2883,6 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.11"
|
||||
|
@ -3719,18 +3130,6 @@ dependencies = [
|
|||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-properties"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_categories"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
|
@ -3825,12 +3224,6 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasite"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.92"
|
||||
|
@ -3907,16 +3300,6 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "whoami"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9"
|
||||
dependencies = [
|
||||
"redox_syscall 0.4.1",
|
||||
"wasite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -4176,16 +3559,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive 0.6.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive 0.7.35",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4199,17 +3573,6 @@ dependencies = [
|
|||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
|
|
|
@ -31,15 +31,6 @@ pub struct Args {
|
|||
#[arg(long, default_value_t = false)]
|
||||
pub http: bool,
|
||||
|
||||
/// The username to use in HTTP mode.
|
||||
#[arg(short = 'u', long, default_value = "")]
|
||||
pub username: String,
|
||||
|
||||
/// The password to use in HTTP mode. If specified, it will be read from the
|
||||
/// environment variable with the given name.
|
||||
#[arg(short = 'w', long, default_value = "")]
|
||||
pub password: String,
|
||||
|
||||
/// The comma-separated usernames of the signers to use in HTTP mode.
|
||||
/// If HTTP mode is enabled and this is empty, then the session ID
|
||||
/// will be printed and will have to be shared manually.
|
||||
|
@ -99,16 +90,6 @@ pub struct ProcessedArgs<C: Ciphersuite> {
|
|||
/// FROST server.
|
||||
pub http: bool,
|
||||
|
||||
/// The username to use in HTTP mode.
|
||||
pub username: String,
|
||||
|
||||
/// The (actual) password to use in HTTP mode.
|
||||
pub password: String,
|
||||
|
||||
/// The authentication token to use in HTTP mode; if not specified
|
||||
/// it will login with `password`
|
||||
pub authentication_token: Option<String>,
|
||||
|
||||
/// The comma-separated keys of the signers to use in
|
||||
/// HTTP mode. If HTTP mode is enabled and this is empty, then the session
|
||||
/// ID will be printed and will have to be shared manually.
|
||||
|
@ -138,15 +119,15 @@ pub struct ProcessedArgs<C: Ciphersuite> {
|
|||
/// Port to connect to, if using HTTP mode.
|
||||
pub port: u16,
|
||||
|
||||
/// The coordinator's communication private key. Specifying this along with
|
||||
/// `comm_participant_pubkey_getter` enables encryption.
|
||||
/// The coordinator's communication private key for HTTP mode.
|
||||
pub comm_privkey: Option<Vec<u8>>,
|
||||
|
||||
/// The coordinator's communication public key.
|
||||
/// The coordinator's communication public key for HTTP mode.
|
||||
pub comm_pubkey: Option<Vec<u8>>,
|
||||
|
||||
/// A function that confirms if the public key of a participant is in the
|
||||
/// user's contact book, returning the same public key, or None if not.
|
||||
/// user's contact book, returning the same public key, or None if not. For
|
||||
/// HTTP mode.
|
||||
// It is a `Rc<dyn Fn>` to make it easier to use;
|
||||
// using `fn()` would preclude using closures and using generics would
|
||||
// require a lot of code change for something simple.
|
||||
|
@ -163,12 +144,6 @@ impl<C: Ciphersuite + 'static> ProcessedArgs<C> {
|
|||
input: &mut dyn BufRead,
|
||||
output: &mut dyn Write,
|
||||
) -> Result<Self, Box<dyn Error>> {
|
||||
let password = if args.http {
|
||||
read_password(&args.password)?
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let num_signers = if !args.signers.is_empty() {
|
||||
args.signers.len() as u16
|
||||
} else if args.num_signers == 0 {
|
||||
|
@ -204,8 +179,6 @@ impl<C: Ciphersuite + 'static> ProcessedArgs<C> {
|
|||
Ok(ProcessedArgs {
|
||||
cli: args.cli,
|
||||
http: args.http,
|
||||
username: args.username.clone(),
|
||||
password,
|
||||
signers,
|
||||
num_signers,
|
||||
public_key_package,
|
||||
|
@ -214,7 +187,6 @@ impl<C: Ciphersuite + 'static> ProcessedArgs<C> {
|
|||
signature: args.signature.clone(),
|
||||
ip: args.ip.clone(),
|
||||
port: args.port,
|
||||
authentication_token: None,
|
||||
comm_privkey: None,
|
||||
comm_pubkey: None,
|
||||
comm_participant_pubkey_getter: None,
|
||||
|
|
|
@ -266,12 +266,11 @@ pub struct HTTPComms<C: Ciphersuite> {
|
|||
client: reqwest::Client,
|
||||
host_port: String,
|
||||
session_id: Option<Uuid>,
|
||||
access_token: String,
|
||||
access_token: Option<String>,
|
||||
num_signers: u16,
|
||||
args: ProcessedArgs<C>,
|
||||
state: SessionState<C>,
|
||||
pubkeys: HashMap<Vec<u8>, Identifier<C>>,
|
||||
should_logout: bool,
|
||||
// The "send" Noise objects by pubkey of recipients.
|
||||
send_noise: Option<HashMap<Vec<u8>, Noise>>,
|
||||
// The "receive" Noise objects by pubkey of senders.
|
||||
|
@ -286,12 +285,11 @@ impl<C: Ciphersuite> HTTPComms<C> {
|
|||
client,
|
||||
host_port: format!("http://{}:{}", args.ip, args.port),
|
||||
session_id: None,
|
||||
access_token: args.authentication_token.clone().unwrap_or_default(),
|
||||
access_token: None,
|
||||
num_signers: 0,
|
||||
args: args.clone(),
|
||||
state: SessionState::new(args.messages.len(), args.num_signers as usize),
|
||||
pubkeys: Default::default(),
|
||||
should_logout: args.authentication_token.is_none(),
|
||||
send_noise: None,
|
||||
recv_noise: None,
|
||||
_phantom: Default::default(),
|
||||
|
@ -370,29 +368,30 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
|
|||
);
|
||||
let signature: [u8; 64] = privkey.sign(challenge.as_bytes(), &mut rng);
|
||||
|
||||
self.access_token = self
|
||||
.client
|
||||
.post(format!("{}/key_login", self.host_port))
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: challenge,
|
||||
pubkey: self
|
||||
.args
|
||||
.comm_pubkey
|
||||
.clone()
|
||||
.ok_or_eyre("comm_pubkey must be specified")?,
|
||||
signature: signature.to_vec(),
|
||||
})
|
||||
.send()
|
||||
.await?
|
||||
.json::<server::LoginOutput>()
|
||||
.await?
|
||||
.access_token
|
||||
.to_string();
|
||||
self.access_token = Some(
|
||||
self.client
|
||||
.post(format!("{}/login", self.host_port))
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: challenge,
|
||||
pubkey: self
|
||||
.args
|
||||
.comm_pubkey
|
||||
.clone()
|
||||
.ok_or_eyre("comm_pubkey must be specified")?,
|
||||
signature: signature.to_vec(),
|
||||
})
|
||||
.send()
|
||||
.await?
|
||||
.json::<server::LoginOutput>()
|
||||
.await?
|
||||
.access_token
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
let r = self
|
||||
.client
|
||||
.post(format!("{}/create_new_session", self.host_port))
|
||||
.bearer_auth(&self.access_token)
|
||||
.bearer_auth(self.access_token.as_ref().expect("was just set"))
|
||||
.json(&server::CreateNewSessionArgs {
|
||||
pubkeys: self.args.signers.iter().cloned().map(PublicKey).collect(),
|
||||
num_signers,
|
||||
|
@ -460,7 +459,7 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
|
|||
let r = self
|
||||
.client
|
||||
.post(format!("{}/receive", self.host_port))
|
||||
.bearer_auth(&self.access_token)
|
||||
.bearer_auth(self.access_token.as_ref().expect("was just set"))
|
||||
.json(&server::ReceiveArgs {
|
||||
session_id: r.session_id,
|
||||
as_coordinator: true,
|
||||
|
@ -511,7 +510,11 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
|
|||
let _r = self
|
||||
.client
|
||||
.post(format!("{}/send", self.host_port))
|
||||
.bearer_auth(&self.access_token)
|
||||
.bearer_auth(
|
||||
self.access_token
|
||||
.as_ref()
|
||||
.expect("must have been set before"),
|
||||
)
|
||||
.json(&server::SendArgs {
|
||||
session_id: self.session_id.unwrap(),
|
||||
recipients: vec![server::PublicKey(recipient.clone())],
|
||||
|
@ -529,7 +532,11 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
|
|||
let r = self
|
||||
.client
|
||||
.post(format!("{}/receive", self.host_port))
|
||||
.bearer_auth(&self.access_token)
|
||||
.bearer_auth(
|
||||
self.access_token
|
||||
.as_ref()
|
||||
.expect("must have been set before"),
|
||||
)
|
||||
.json(&server::ReceiveArgs {
|
||||
session_id: self.session_id.unwrap(),
|
||||
as_coordinator: true,
|
||||
|
@ -553,21 +560,27 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
|
|||
let _r = self
|
||||
.client
|
||||
.post(format!("{}/close_session", self.host_port))
|
||||
.bearer_auth(&self.access_token)
|
||||
.bearer_auth(
|
||||
self.access_token
|
||||
.as_ref()
|
||||
.expect("must have been set before"),
|
||||
)
|
||||
.json(&server::CloseSessionArgs {
|
||||
session_id: self.session_id.unwrap(),
|
||||
})
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if self.should_logout {
|
||||
let _r = self
|
||||
.client
|
||||
.post(format!("{}/logout", self.host_port))
|
||||
.bearer_auth(&self.access_token)
|
||||
.send()
|
||||
.await?;
|
||||
}
|
||||
let _r = self
|
||||
.client
|
||||
.post(format!("{}/logout", self.host_port))
|
||||
.bearer_auth(
|
||||
self.access_token
|
||||
.as_ref()
|
||||
.expect("must have been set before"),
|
||||
)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
let signature_shares = self.state.signature_shares()?;
|
||||
|
||||
|
|
|
@ -9,31 +9,9 @@ pub(crate) struct Args {
|
|||
|
||||
#[derive(Subcommand, Clone)]
|
||||
pub(crate) enum Command {
|
||||
/// Initializes the user, generating a communication key pair and optionally
|
||||
/// registering with a FROST server. The key pair and additional information
|
||||
/// are saved to the config file. You can rerun the command to register
|
||||
/// in other servers; the communication key pair will not be regenerated.
|
||||
Init {
|
||||
/// The username to use when registering, if desired.
|
||||
#[arg(short, long)]
|
||||
username: Option<String>,
|
||||
/// The server URL to use, if desired.
|
||||
#[arg(short, long)]
|
||||
server_url: Option<String>,
|
||||
/// The path to the config file to manage. If not specified, it uses
|
||||
/// $HOME/.local/frost/credentials.toml
|
||||
#[arg(short, long)]
|
||||
config: Option<String>,
|
||||
},
|
||||
/// Logs the user on the server and saves the returned authentication token
|
||||
/// Initializes the user, generating a communication key pair and saving
|
||||
/// to the config file.
|
||||
Login {
|
||||
/// The username to use when logging in.
|
||||
#[arg(short, long)]
|
||||
username: String,
|
||||
/// The server URL to use.
|
||||
#[arg(short, long)]
|
||||
server_url: String,
|
||||
Init {
|
||||
/// The path to the config file to manage. If not specified, it uses
|
||||
/// $HOME/.local/frost/credentials.toml
|
||||
#[arg(short, long)]
|
||||
|
@ -45,10 +23,6 @@ pub(crate) enum Command {
|
|||
/// The name to use when exporting.
|
||||
#[arg(short, long)]
|
||||
name: String,
|
||||
/// The server URL for which to export a contact. You can use a
|
||||
/// substring of the URL.
|
||||
#[arg(short, long)]
|
||||
server_url: Option<String>,
|
||||
/// The path to the config file to manage. If not specified, it uses
|
||||
/// $HOME/.local/frost/credentials.toml
|
||||
#[arg(short, long)]
|
||||
|
@ -86,10 +60,6 @@ pub(crate) enum Command {
|
|||
/// The comma-separated name of each participant.
|
||||
#[arg(short = 'N', long, value_delimiter = ',')]
|
||||
names: Vec<String>,
|
||||
/// The comma-separated username of each participant in the same order
|
||||
/// as `names`. Note: these won't be checked in the server.
|
||||
#[arg(short, long, value_delimiter = ',')]
|
||||
usernames: Vec<String>,
|
||||
/// The server URL, if desired. Note that this does not connect to the
|
||||
/// server; it will just associated the server URL with the group in the
|
||||
/// config file.
|
||||
|
|
|
@ -18,10 +18,6 @@ pub struct Config {
|
|||
#[serde(skip)]
|
||||
path: Option<PathBuf>,
|
||||
pub version: u8,
|
||||
/// The registry of servers the user has registered into, keyed by server
|
||||
/// URL.
|
||||
#[serde(default)]
|
||||
pub registry: BTreeMap<String, Registry>,
|
||||
/// The communication key pair for the user.
|
||||
pub communication_key: Option<CommunicationKey>,
|
||||
/// The address book of the user, keyed by each contact's name.
|
||||
|
@ -41,25 +37,6 @@ impl Config {
|
|||
.cloned()
|
||||
.ok_or_eyre("contact not found")?)
|
||||
}
|
||||
|
||||
pub fn username_by_server_url(&self, server_url: &str) -> Result<String, Box<dyn Error>> {
|
||||
Ok(self
|
||||
.registry
|
||||
.get(server_url)
|
||||
.ok_or_eyre("Not logged in in the giver server")?
|
||||
.username
|
||||
.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// A registry entry. Note that the server URL is not in the struct;
|
||||
/// it is the key in the `registry` map in Config.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Registry {
|
||||
/// The authentication token, if the user is logged in.
|
||||
pub token: Option<String>,
|
||||
/// The username of the user
|
||||
pub username: String,
|
||||
}
|
||||
|
||||
/// The communication key pair for the user.
|
||||
|
@ -117,7 +94,7 @@ impl Group {
|
|||
);
|
||||
for participant in self.participant.values() {
|
||||
let contact = config.contact_by_pubkey(&participant.pubkey)?;
|
||||
s += &format!("\t{}\n", contact.name);
|
||||
s += &format!("\t{} ({})\n", contact.name, hex::encode(contact.pubkey));
|
||||
}
|
||||
Ok(s)
|
||||
}
|
||||
|
@ -138,8 +115,6 @@ pub struct Participant {
|
|||
deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec"
|
||||
)]
|
||||
pub pubkey: Vec<u8>,
|
||||
/// The username of the participant in the server, if any.
|
||||
pub username: Option<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
|
|
@ -20,28 +20,17 @@ pub struct Contact {
|
|||
deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec"
|
||||
)]
|
||||
pub pubkey: Vec<u8>,
|
||||
/// The URL of the server where the contact is registered, if any.
|
||||
pub server_url: Option<String>,
|
||||
/// The username of the contact on `server_url`, if registered.
|
||||
pub username: Option<String>,
|
||||
}
|
||||
|
||||
impl Contact {
|
||||
/// Returns a human-readable summary of the contact; used when it is
|
||||
/// printed to the terminal.
|
||||
pub fn as_human_readable_summary(&self) -> String {
|
||||
let mut s = format!(
|
||||
format!(
|
||||
"Name: {}\nPublic Key: {}\n",
|
||||
self.name,
|
||||
hex::encode(&self.pubkey)
|
||||
);
|
||||
if let Some(server_url) = &self.server_url {
|
||||
s += format!("Server URL: {}\n", server_url).as_str();
|
||||
}
|
||||
if let Some(username) = &self.username {
|
||||
s += format!("Username: {}\n", username).as_str();
|
||||
}
|
||||
s
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the contact encoded as a text string, with Bech32.
|
||||
|
@ -92,57 +81,12 @@ pub(crate) fn import(args: &Command) -> Result<(), Box<dyn Error>> {
|
|||
|
||||
/// Export a contact from the user's address book in the config file.
|
||||
pub(crate) fn export(args: &Command) -> Result<(), Box<dyn Error>> {
|
||||
let Command::Export {
|
||||
name,
|
||||
server_url,
|
||||
config,
|
||||
} = (*args).clone()
|
||||
else {
|
||||
let Command::Export { name, config } = (*args).clone() else {
|
||||
panic!("invalid Command");
|
||||
};
|
||||
|
||||
let config = Config::read(config)?;
|
||||
|
||||
// Get the server_url to export depending on whether the user has registered
|
||||
// in a server, or if they are registered in multiple servers.
|
||||
let server_url = if config.registry.is_empty() && server_url.is_some() {
|
||||
return Err(eyre!("User has not been registered yet").into());
|
||||
} else if config.registry.is_empty() {
|
||||
None
|
||||
} else if config.registry.len() > 1 {
|
||||
let Some(server_url) = &server_url else {
|
||||
return Err(eyre!(
|
||||
"More than one registry found. Specify which one with the server_url argument"
|
||||
)
|
||||
.into());
|
||||
};
|
||||
// There are multiple server registrations. Try to match one using
|
||||
// `server_url` with a simple substring test.
|
||||
let matches: Vec<_> = config
|
||||
.registry
|
||||
.keys()
|
||||
.filter(|k| k.contains(server_url))
|
||||
.collect();
|
||||
if matches.is_empty() {
|
||||
return Err(eyre!("server_url not found").into());
|
||||
} else if matches.len() > 1 {
|
||||
return Err(eyre!(
|
||||
"Multiple registries matches the server_url argument; make it more specific"
|
||||
)
|
||||
.into());
|
||||
}
|
||||
Some(matches[0].clone())
|
||||
} else {
|
||||
Some(
|
||||
config
|
||||
.registry
|
||||
.first_key_value()
|
||||
.expect("should have an entry")
|
||||
.0
|
||||
.clone(),
|
||||
)
|
||||
};
|
||||
|
||||
// Build the contact to export.
|
||||
let contact = Contact {
|
||||
version: Some(0),
|
||||
|
@ -151,8 +95,6 @@ pub(crate) fn export(args: &Command) -> Result<(), Box<dyn Error>> {
|
|||
.communication_key
|
||||
.ok_or(eyre!("pubkey not generated yet"))?
|
||||
.pubkey,
|
||||
server_url: server_url.clone(),
|
||||
username: server_url.map(|s| config.registry[&s].username.clone()),
|
||||
};
|
||||
|
||||
eprintln!("Exporting this information:");
|
||||
|
|
|
@ -76,8 +76,6 @@ pub(crate) async fn run_for_ciphersuite<C: RandomizedCiphersuite + 'static>(
|
|||
let pargs = coordinator::args::ProcessedArgs {
|
||||
cli: false,
|
||||
http: true,
|
||||
username: String::new(),
|
||||
password: String::new(),
|
||||
signers,
|
||||
num_signers,
|
||||
public_key_package,
|
||||
|
@ -89,7 +87,6 @@ pub(crate) async fn run_for_ciphersuite<C: RandomizedCiphersuite + 'static>(
|
|||
.ok_or_eyre("host missing in URL")?
|
||||
.to_owned(),
|
||||
port: server_url_parsed.port().unwrap_or(2744),
|
||||
authentication_token: None,
|
||||
comm_privkey: Some(
|
||||
config
|
||||
.communication_key
|
||||
|
|
|
@ -1,91 +1,28 @@
|
|||
use std::error::Error;
|
||||
|
||||
use eyre::eyre;
|
||||
|
||||
use crate::{
|
||||
args::Command,
|
||||
config::{CommunicationKey, Config, Registry},
|
||||
config::{CommunicationKey, Config},
|
||||
};
|
||||
|
||||
pub(crate) async fn init(args: &Command) -> Result<(), Box<dyn Error>> {
|
||||
let Command::Init {
|
||||
server_url,
|
||||
username,
|
||||
config,
|
||||
} = (*args).clone()
|
||||
else {
|
||||
let Command::Init { config } = (*args).clone() else {
|
||||
panic!("invalid Command");
|
||||
};
|
||||
|
||||
let mut config = Config::read(config)?;
|
||||
|
||||
let pubkey = match &config.communication_key {
|
||||
Some(communication_key) => {
|
||||
eprintln!("Skipping keypair generation; keypair already generated and stored");
|
||||
hex::decode(&communication_key.pubkey)?
|
||||
}
|
||||
None => {
|
||||
eprintln!("Generating keypair... ");
|
||||
let builder = snow::Builder::new("Noise_K_25519_ChaChaPoly_BLAKE2s".parse().unwrap());
|
||||
let keypair = builder.generate_keypair().unwrap();
|
||||
config.communication_key = Some(CommunicationKey {
|
||||
privkey: keypair.private.clone(),
|
||||
pubkey: keypair.public.clone(),
|
||||
});
|
||||
keypair.public
|
||||
}
|
||||
};
|
||||
|
||||
if let (Some(server_url), Some(username)) = (server_url, username) {
|
||||
// TODO: check if already registered, prompt to overwrite
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let password = rpassword::prompt_password("Password to use: ").unwrap();
|
||||
let rpassword = rpassword::prompt_password("Repeat password: ").unwrap();
|
||||
if password != rpassword {
|
||||
return Err(eyre!("Passwords are different").into());
|
||||
}
|
||||
|
||||
eprintln!("Registering at {}...", server_url);
|
||||
let r = client
|
||||
.post(format!("http://{}/register", server_url))
|
||||
.json(&server::RegisterArgs {
|
||||
username: username.clone(),
|
||||
password: password.clone(),
|
||||
pubkey: pubkey.clone(),
|
||||
})
|
||||
.send()
|
||||
.await?;
|
||||
if r.status() != reqwest::StatusCode::OK {
|
||||
return Err(eyre!("{}", r.text().await?).into());
|
||||
}
|
||||
|
||||
eprintln!("Logging in at {}...", server_url);
|
||||
let r = client
|
||||
.post(format!("http://{}/login", server_url))
|
||||
.json(&server::LoginArgs {
|
||||
username: username.clone(),
|
||||
password,
|
||||
})
|
||||
.send()
|
||||
.await?;
|
||||
if r.status() != reqwest::StatusCode::OK {
|
||||
return Err(eyre!("{}", r.text().await?).into());
|
||||
}
|
||||
let r = r.json::<server::LoginOutput>().await?;
|
||||
|
||||
config.registry.insert(
|
||||
server_url,
|
||||
Registry {
|
||||
token: Some(r.access_token.to_string()),
|
||||
username,
|
||||
},
|
||||
);
|
||||
if config.communication_key.is_some() {
|
||||
eprintln!("Skipping keypair generation; keypair already generated and stored");
|
||||
} else {
|
||||
eprintln!(
|
||||
"Skipping user registration, specify username and server_url if you want to register"
|
||||
);
|
||||
}
|
||||
eprintln!("Generating keypair... ");
|
||||
let builder = snow::Builder::new("Noise_K_25519_ChaChaPoly_BLAKE2s".parse().unwrap());
|
||||
let keypair = builder.generate_keypair().unwrap();
|
||||
config.communication_key = Some(CommunicationKey {
|
||||
privkey: keypair.private.clone(),
|
||||
pubkey: keypair.public.clone(),
|
||||
});
|
||||
};
|
||||
|
||||
eprintln!(
|
||||
"Writing to config file at {}...",
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
use std::error::Error;
|
||||
|
||||
use eyre::eyre;
|
||||
|
||||
use crate::{
|
||||
args::Command,
|
||||
config::{Config, Registry},
|
||||
};
|
||||
|
||||
pub(crate) async fn login(args: &Command) -> Result<(), Box<dyn Error>> {
|
||||
let Command::Login {
|
||||
server_url,
|
||||
username,
|
||||
config,
|
||||
} = (*args).clone()
|
||||
else {
|
||||
panic!("invalid Command");
|
||||
};
|
||||
|
||||
let mut config = Config::read(config)?;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let password = rpassword::prompt_password("Password: ").unwrap();
|
||||
|
||||
eprintln!("Logging in at {}...", server_url);
|
||||
let r = client
|
||||
.post(format!("http://{}/login", server_url))
|
||||
.json(&server::LoginArgs {
|
||||
username: username.clone(),
|
||||
password,
|
||||
})
|
||||
.send()
|
||||
.await?;
|
||||
if r.status() != reqwest::StatusCode::OK {
|
||||
return Err(eyre!("{}", r.text().await?).into());
|
||||
}
|
||||
let r = r.json::<server::LoginOutput>().await?;
|
||||
|
||||
config.registry.insert(
|
||||
server_url,
|
||||
Registry {
|
||||
token: Some(r.access_token.to_string()),
|
||||
username,
|
||||
},
|
||||
);
|
||||
|
||||
eprintln!(
|
||||
"Writing to config file at {}...",
|
||||
config.path().expect("should not be None").display()
|
||||
);
|
||||
config.write()?;
|
||||
eprintln!("Done.");
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -5,7 +5,6 @@ pub mod contact;
|
|||
pub mod coordinator;
|
||||
pub mod group;
|
||||
pub mod init;
|
||||
pub mod login;
|
||||
pub mod participant;
|
||||
pub mod trusted_dealer;
|
||||
pub mod write_atomic;
|
||||
|
@ -22,7 +21,6 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
match args.command {
|
||||
Command::Init { .. } => init::init(&args.command).await,
|
||||
Command::Login { .. } => login::login(&args.command).await,
|
||||
Command::Export { .. } => contact::export(&args.command),
|
||||
Command::Import { .. } => contact::import(&args.command),
|
||||
Command::Contacts { .. } => contact::list(&args.command),
|
||||
|
|
|
@ -66,15 +66,12 @@ pub(crate) async fn run_for_ciphersuite<C: RandomizedCiphersuite + 'static>(
|
|||
let pargs = participant::args::ProcessedArgs {
|
||||
cli: false,
|
||||
http: true,
|
||||
username: String::new(),
|
||||
password: String::new(),
|
||||
key_package,
|
||||
ip: server_url_parsed
|
||||
.host_str()
|
||||
.ok_or_eyre("host missing in URL")?
|
||||
.to_owned(),
|
||||
port: server_url_parsed.port().unwrap_or(2744),
|
||||
authentication_token: None,
|
||||
session_id: String::new(),
|
||||
comm_privkey: Some(
|
||||
config
|
||||
|
|
|
@ -37,7 +37,6 @@ pub(crate) fn trusted_dealer_for_ciphersuite<C: Ciphersuite + MaybeIntoEvenY + '
|
|||
threshold,
|
||||
num_signers,
|
||||
names,
|
||||
usernames,
|
||||
server_url,
|
||||
} = (*args).clone()
|
||||
else {
|
||||
|
@ -67,36 +66,21 @@ pub(crate) fn trusted_dealer_for_ciphersuite<C: Ciphersuite + MaybeIntoEvenY + '
|
|||
// First pass over configs; create participants map
|
||||
let mut participants = BTreeMap::new();
|
||||
let mut contacts = Vec::new();
|
||||
for (idx, (identifier, path, name)) in
|
||||
izip!(shares.keys(), config.iter(), names.iter()).enumerate()
|
||||
{
|
||||
for (identifier, path, name) in izip!(shares.keys(), config.iter(), names.iter()) {
|
||||
let config = Config::read(Some(path.to_string()))?;
|
||||
let pubkey = config
|
||||
.communication_key
|
||||
.ok_or_eyre("config not initialized")?
|
||||
.pubkey;
|
||||
let username = if server_url.is_some() {
|
||||
Some(
|
||||
usernames
|
||||
.get(idx)
|
||||
.ok_or_eyre("must specify usernames of all users")?
|
||||
.clone(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let participant = Participant {
|
||||
identifier: identifier.serialize(),
|
||||
pubkey: pubkey.clone(),
|
||||
username,
|
||||
};
|
||||
participants.insert(hex::encode(identifier.serialize()), participant);
|
||||
let contact = Contact {
|
||||
version: None,
|
||||
name: name.clone(),
|
||||
pubkey,
|
||||
server_url: None,
|
||||
username: None,
|
||||
};
|
||||
contacts.push(contact);
|
||||
}
|
||||
|
|
|
@ -31,15 +31,6 @@ pub struct Args {
|
|||
#[arg(long, default_value_t = false)]
|
||||
pub http: bool,
|
||||
|
||||
/// The username to use in HTTP mode.
|
||||
#[arg(short = 'u', long, default_value = "")]
|
||||
pub username: String,
|
||||
|
||||
/// The password to use in HTTP mode. If specified, it will be read from the
|
||||
/// environment variable with the given name.
|
||||
#[arg(short = 'w', long, default_value = "")]
|
||||
pub password: String,
|
||||
|
||||
/// Public key package to use. Can be a file with a JSON-encoded
|
||||
/// package, or "". If the file does not exist or if "" is specified,
|
||||
/// then it will be read from standard input.
|
||||
|
@ -70,16 +61,6 @@ pub struct ProcessedArgs<C: Ciphersuite> {
|
|||
/// FROST server.
|
||||
pub http: bool,
|
||||
|
||||
/// The username to use in HTTP mode.
|
||||
pub username: String,
|
||||
|
||||
/// The (actual) password to use in HTTP mode.
|
||||
pub password: String,
|
||||
|
||||
/// The authentication token to use in HTTP mode; if not specified
|
||||
/// it will login with `password`
|
||||
pub authentication_token: Option<String>,
|
||||
|
||||
/// Key package to use.
|
||||
pub key_package: KeyPackage<C>,
|
||||
|
||||
|
@ -94,15 +75,14 @@ pub struct ProcessedArgs<C: Ciphersuite> {
|
|||
/// Optional Session ID
|
||||
pub session_id: String,
|
||||
|
||||
/// The participant's communication private key. Specifying this along with
|
||||
/// `comm_coordinator_pubkey_getter` enables encryption.
|
||||
/// The participant's communication private key for HTTP mode.
|
||||
pub comm_privkey: Option<Vec<u8>>,
|
||||
|
||||
/// The participant's communication public key.
|
||||
/// The participant's communication public key for HTTP mode.
|
||||
pub comm_pubkey: Option<Vec<u8>>,
|
||||
|
||||
/// A function that confirms that a public key from the server is trusted by
|
||||
/// the user; returns the same public key.
|
||||
/// the user; returns the same public key. For HTTP mode.
|
||||
// It is a `Rc<dyn Fn>` to make it easier to use;
|
||||
// using `fn()` would preclude using closures and using generics would
|
||||
// require a lot of code change for something simple.
|
||||
|
@ -119,12 +99,6 @@ impl<C: Ciphersuite + 'static> ProcessedArgs<C> {
|
|||
input: &mut dyn BufRead,
|
||||
output: &mut dyn Write,
|
||||
) -> Result<Self, Box<dyn Error>> {
|
||||
let password = if args.http {
|
||||
read_password(&args.password)?
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let bytes = read_from_file_or_stdin(input, output, "key package", &args.key_package)?;
|
||||
|
||||
let key_package = if let Ok(secret_share) = serde_json::from_str::<SecretShare<C>>(&bytes) {
|
||||
|
@ -137,12 +111,9 @@ impl<C: Ciphersuite + 'static> ProcessedArgs<C> {
|
|||
Ok(ProcessedArgs {
|
||||
cli: args.cli,
|
||||
http: args.http,
|
||||
username: args.username.clone(),
|
||||
password,
|
||||
key_package,
|
||||
ip: args.ip.clone(),
|
||||
port: args.port,
|
||||
authentication_token: None,
|
||||
session_id: args.session_id.clone(),
|
||||
comm_privkey: None,
|
||||
comm_pubkey: None,
|
||||
|
|
|
@ -104,8 +104,7 @@ pub struct HTTPComms<C: Ciphersuite> {
|
|||
client: reqwest::Client,
|
||||
host_port: String,
|
||||
session_id: Option<Uuid>,
|
||||
access_token: String,
|
||||
should_logout: bool,
|
||||
access_token: Option<String>,
|
||||
args: ProcessedArgs<C>,
|
||||
send_noise: Option<Noise>,
|
||||
recv_noise: Option<Noise>,
|
||||
|
@ -125,8 +124,7 @@ where
|
|||
client,
|
||||
host_port: format!("http://{}:{}", args.ip, args.port),
|
||||
session_id: Uuid::parse_str(&args.session_id).ok(),
|
||||
access_token: args.authentication_token.clone().unwrap_or_default(),
|
||||
should_logout: args.authentication_token.is_none(),
|
||||
access_token: None,
|
||||
args: args.clone(),
|
||||
send_noise: None,
|
||||
recv_noise: None,
|
||||
|
@ -201,24 +199,25 @@ where
|
|||
);
|
||||
let signature: [u8; 64] = privkey.sign(challenge.as_bytes(), &mut rng);
|
||||
|
||||
self.access_token = self
|
||||
.client
|
||||
.post(format!("{}/key_login", self.host_port))
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: challenge,
|
||||
pubkey: self
|
||||
.args
|
||||
.comm_pubkey
|
||||
.clone()
|
||||
.ok_or_eyre("comm_pubkey must be specified")?,
|
||||
signature: signature.to_vec(),
|
||||
})
|
||||
.send()
|
||||
.await?
|
||||
.json::<server::LoginOutput>()
|
||||
.await?
|
||||
.access_token
|
||||
.to_string();
|
||||
self.access_token = Some(
|
||||
self.client
|
||||
.post(format!("{}/login", self.host_port))
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: challenge,
|
||||
pubkey: self
|
||||
.args
|
||||
.comm_pubkey
|
||||
.clone()
|
||||
.ok_or_eyre("comm_pubkey must be specified")?,
|
||||
signature: signature.to_vec(),
|
||||
})
|
||||
.send()
|
||||
.await?
|
||||
.json::<server::LoginOutput>()
|
||||
.await?
|
||||
.access_token
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
let session_id = match self.session_id {
|
||||
Some(s) => s,
|
||||
|
@ -227,7 +226,7 @@ where
|
|||
let r = self
|
||||
.client
|
||||
.post(format!("{}/list_sessions", self.host_port))
|
||||
.bearer_auth(&self.access_token)
|
||||
.bearer_auth(self.access_token.as_ref().expect("was just set"))
|
||||
.send()
|
||||
.await?
|
||||
.json::<server::ListSessionsOutput>()
|
||||
|
@ -256,7 +255,7 @@ where
|
|||
.client
|
||||
.post(format!("{}/get_session_info", self.host_port))
|
||||
.json(&server::GetSessionInfoArgs { session_id })
|
||||
.bearer_auth(&self.access_token)
|
||||
.bearer_auth(self.access_token.as_ref().expect("was just set"))
|
||||
.send()
|
||||
.await?
|
||||
.json::<server::GetSessionInfoOutput>()
|
||||
|
@ -298,7 +297,7 @@ where
|
|||
let msg = self.encrypt_if_needed(serde_json::to_vec(&send_commitments_args)?)?;
|
||||
self.client
|
||||
.post(format!("{}/send", self.host_port))
|
||||
.bearer_auth(&self.access_token)
|
||||
.bearer_auth(self.access_token.as_ref().expect("was just set"))
|
||||
.json(&server::SendArgs {
|
||||
session_id,
|
||||
// Empty recipients: Coordinator
|
||||
|
@ -316,7 +315,7 @@ where
|
|||
let r = self
|
||||
.client
|
||||
.post(format!("{}/receive", self.host_port))
|
||||
.bearer_auth(&self.access_token)
|
||||
.bearer_auth(self.access_token.as_ref().expect("was just set"))
|
||||
.json(&server::ReceiveArgs {
|
||||
session_id,
|
||||
as_coordinator: false,
|
||||
|
@ -371,7 +370,7 @@ where
|
|||
let _r = self
|
||||
.client
|
||||
.post(format!("{}/send", self.host_port))
|
||||
.bearer_auth(&self.access_token)
|
||||
.bearer_auth(self.access_token.as_ref().expect("must be set before"))
|
||||
.json(&server::SendArgs {
|
||||
session_id: self.session_id.unwrap(),
|
||||
// Empty recipients: Coordinator
|
||||
|
@ -381,14 +380,12 @@ where
|
|||
.send()
|
||||
.await?;
|
||||
|
||||
if self.should_logout {
|
||||
let _r = self
|
||||
.client
|
||||
.post(format!("{}/logout", self.host_port))
|
||||
.bearer_auth(&self.access_token)
|
||||
.send()
|
||||
.await?;
|
||||
}
|
||||
let _r = self
|
||||
.client
|
||||
.post(format!("{}/logout", self.host_port))
|
||||
.bearer_auth(self.access_token.as_ref().expect("must be set before"))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -46,8 +46,6 @@ async fn check_valid_round_1_inputs() {
|
|||
port: 80,
|
||||
session_id: "session-id".to_string(),
|
||||
http: false,
|
||||
username: "".to_string(),
|
||||
password: "".to_string(),
|
||||
};
|
||||
let input = SECRET_SHARE_JSON;
|
||||
let mut valid_input = input.as_bytes();
|
||||
|
|
|
@ -15,13 +15,11 @@ derivative = "2.2.0"
|
|||
eyre = "0.6.11"
|
||||
frost-core = { version = "2.0.0", features = ["serde"] }
|
||||
frost-rerandomized = { version = "2.0.0-rc.0", features = ["serde"] }
|
||||
password-auth = "1.0.0"
|
||||
rand = "0.8"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serdect = { version = "0.2.0" }
|
||||
serde_json = "1.0.133"
|
||||
snow = "0.9.6"
|
||||
sqlx = { version = "0.8.2", features = ["sqlite", "time", "runtime-tokio", "uuid"] }
|
||||
tokio = { version = "1.42", features = ["full"] }
|
||||
tower-http = { version = "0.6.2", features = ["trace"] }
|
||||
tracing = "0.1"
|
||||
|
|
|
@ -10,8 +10,4 @@ pub struct Args {
|
|||
/// Port to bind to
|
||||
#[arg(short, long, default_value_t = 2744)]
|
||||
pub port: u16,
|
||||
|
||||
/// Database to use.
|
||||
#[arg(short, long, default_value = "db.sqlite")]
|
||||
pub database: String,
|
||||
}
|
||||
|
|
|
@ -6,35 +6,10 @@ use xeddsa::{xed25519, Verify as _};
|
|||
use crate::{
|
||||
state::{Session, SharedState},
|
||||
types::*,
|
||||
user::{
|
||||
add_access_token, authenticate_user, create_user, delete_user, remove_access_token, User,
|
||||
},
|
||||
user::User,
|
||||
AppError,
|
||||
};
|
||||
|
||||
/// Implement the register API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state,args), fields(args.username = %args.username))]
|
||||
pub(crate) async fn register(
|
||||
State(state): State<SharedState>,
|
||||
Json(args): Json<RegisterArgs>,
|
||||
) -> Result<Json<()>, AppError> {
|
||||
let username = args.username.trim();
|
||||
let password = args.password.trim();
|
||||
|
||||
if username.is_empty() || password.is_empty() {
|
||||
return Err(AppError(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
eyre!("empty args").into(),
|
||||
));
|
||||
}
|
||||
|
||||
create_user(state.db.clone(), username, password, args.pubkey)
|
||||
.await
|
||||
.map_err(|e| AppError(StatusCode::INTERNAL_SERVER_ERROR, e))?;
|
||||
|
||||
Ok(Json(()))
|
||||
}
|
||||
|
||||
/// Implement the challenge API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, _args))]
|
||||
pub(crate) async fn challenge(
|
||||
|
@ -52,7 +27,7 @@ pub(crate) async fn challenge(
|
|||
|
||||
/// Implement the key_login API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, args))]
|
||||
pub(crate) async fn key_login(
|
||||
pub(crate) async fn login(
|
||||
State(state): State<SharedState>,
|
||||
Json(args): Json<KeyLoginArgs>,
|
||||
) -> Result<Json<KeyLoginOutput>, AppError> {
|
||||
|
@ -100,81 +75,22 @@ pub(crate) async fn key_login(
|
|||
Ok(Json(token))
|
||||
}
|
||||
|
||||
/// Implement the login API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state,args), fields(args.username = %args.username))]
|
||||
pub(crate) async fn login(
|
||||
State(state): State<SharedState>,
|
||||
Json(args): Json<LoginArgs>,
|
||||
) -> Result<Json<LoginOutput>, AppError> {
|
||||
// Check if the user sent the credentials
|
||||
if args.username.is_empty() || args.password.is_empty() {
|
||||
return Err(AppError(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
eyre!("empty args").into(),
|
||||
));
|
||||
}
|
||||
|
||||
let user = authenticate_user(state.db.clone(), &args.username, &args.password)
|
||||
.await
|
||||
.map_err(|e| AppError(StatusCode::INTERNAL_SERVER_ERROR, e))?;
|
||||
|
||||
let user = match user {
|
||||
Some(user) => user,
|
||||
None => {
|
||||
return Err(AppError(
|
||||
StatusCode::UNAUTHORIZED,
|
||||
eyre!("invalid user or password").into(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let access_token = add_access_token(state.db.clone(), user.id)
|
||||
.await
|
||||
.map_err(|e| AppError(StatusCode::INTERNAL_SERVER_ERROR, e))?;
|
||||
|
||||
let token = LoginOutput { access_token };
|
||||
|
||||
Ok(Json(token))
|
||||
}
|
||||
|
||||
/// Implement the logout API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state,user), fields(user.username = %user.username))]
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn logout(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
) -> Result<Json<()>, AppError> {
|
||||
state.access_tokens.write().unwrap().remove(
|
||||
&user
|
||||
.current_token
|
||||
.expect("user is logged in so they must have a token"),
|
||||
);
|
||||
|
||||
remove_access_token(
|
||||
state.db.clone(),
|
||||
user.current_token
|
||||
.expect("user is logged in so they must have a token"),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| AppError(StatusCode::INTERNAL_SERVER_ERROR, e))?;
|
||||
|
||||
Ok(Json(()))
|
||||
}
|
||||
|
||||
/// Implement the unregister API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state,user), fields(user.username = %user.username))]
|
||||
pub(crate) async fn unregister(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
) -> Result<Json<()>, AppError> {
|
||||
delete_user(state.db.clone(), user.id)
|
||||
.await
|
||||
.map_err(|e| AppError(StatusCode::INTERNAL_SERVER_ERROR, e))?;
|
||||
|
||||
state
|
||||
.access_tokens
|
||||
.write()
|
||||
.unwrap()
|
||||
.remove(&user.current_token);
|
||||
Ok(Json(()))
|
||||
}
|
||||
|
||||
/// Implement the create_new_session API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state,user), fields(user.username = %user.username))]
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn create_new_session(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -216,7 +132,7 @@ pub(crate) async fn create_new_session(
|
|||
}
|
||||
|
||||
/// Implement the create_new_session API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state,user), fields(user.username = %user.username))]
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn list_sessions(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -233,7 +149,7 @@ pub(crate) async fn list_sessions(
|
|||
}
|
||||
|
||||
/// Implement the get_session_info API
|
||||
#[tracing::instrument(ret, err(Debug), skip(state,user), fields(user.username = %user.username))]
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn get_session_info(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -241,6 +157,21 @@ pub(crate) async fn get_session_info(
|
|||
) -> Result<Json<GetSessionInfoOutput>, AppError> {
|
||||
let state_lock = state.sessions.read().unwrap();
|
||||
|
||||
let sessions = state_lock
|
||||
.sessions_by_pubkey
|
||||
.get(&user.pubkey)
|
||||
.ok_or(AppError(
|
||||
StatusCode::NOT_FOUND,
|
||||
eyre!("user is not in any session").into(),
|
||||
))?;
|
||||
|
||||
if !sessions.contains(&args.session_id) {
|
||||
return Err(AppError(
|
||||
StatusCode::NOT_FOUND,
|
||||
eyre!("session ID not found").into(),
|
||||
));
|
||||
}
|
||||
|
||||
let session = state_lock.sessions.get(&args.session_id).ok_or(AppError(
|
||||
StatusCode::NOT_FOUND,
|
||||
eyre!("session ID not found").into(),
|
||||
|
@ -256,7 +187,7 @@ pub(crate) async fn get_session_info(
|
|||
|
||||
/// Implement the send API
|
||||
// TODO: get identifier from channel rather from arguments
|
||||
#[tracing::instrument(ret, err(Debug), skip(state,user), fields(user.username = %user.username))]
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn send(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -294,7 +225,7 @@ pub(crate) async fn send(
|
|||
|
||||
/// Implement the recv API
|
||||
// TODO: get identifier from channel rather from arguments
|
||||
#[tracing::instrument(ret, err(Debug), skip(state,user), fields(user.username = %user.username))]
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn receive(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -323,7 +254,7 @@ pub(crate) async fn receive(
|
|||
}
|
||||
|
||||
/// Implement the close_session API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state,user), fields(user.username = %user.username))]
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn close_session(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -331,16 +262,31 @@ pub(crate) async fn close_session(
|
|||
) -> Result<Json<()>, AppError> {
|
||||
let mut state = state.sessions.write().unwrap();
|
||||
|
||||
for username in state
|
||||
.sessions
|
||||
.get(&args.session_id)
|
||||
.ok_or(AppError(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
eyre!("invalid session ID").into(),
|
||||
))?
|
||||
.pubkeys
|
||||
.clone()
|
||||
{
|
||||
let sessions = state.sessions_by_pubkey.get(&user.pubkey).ok_or(AppError(
|
||||
StatusCode::NOT_FOUND,
|
||||
eyre!("user is not in any session").into(),
|
||||
))?;
|
||||
|
||||
if !sessions.contains(&args.session_id) {
|
||||
return Err(AppError(
|
||||
StatusCode::NOT_FOUND,
|
||||
eyre!("session ID not found").into(),
|
||||
));
|
||||
}
|
||||
|
||||
let session = state.sessions.get(&args.session_id).ok_or(AppError(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
eyre!("invalid session ID").into(),
|
||||
))?;
|
||||
|
||||
if session.coordinator_pubkey != user.pubkey {
|
||||
return Err(AppError(
|
||||
StatusCode::NOT_FOUND,
|
||||
eyre!("user is not the coordinator of the session").into(),
|
||||
));
|
||||
}
|
||||
|
||||
for username in session.pubkeys.clone() {
|
||||
if let Some(v) = state.sessions_by_pubkey.get_mut(&username) {
|
||||
v.remove(&args.session_id);
|
||||
}
|
||||
|
|
|
@ -22,12 +22,9 @@ use axum::{
|
|||
pub fn router(shared_state: SharedState) -> Router {
|
||||
// Shared state that is passed to each handler by axum
|
||||
Router::new()
|
||||
.route("/register", post(functions::register))
|
||||
.route("/challenge", post(functions::challenge))
|
||||
.route("/login", post(functions::login))
|
||||
.route("/key_login", post(functions::key_login))
|
||||
.route("/logout", post(functions::logout))
|
||||
.route("/unregister", post(functions::unregister))
|
||||
.route("/create_new_session", post(functions::create_new_session))
|
||||
.route("/list_sessions", post(functions::list_sessions))
|
||||
.route("/get_session_info", post(functions::get_session_info))
|
||||
|
@ -40,7 +37,7 @@ pub fn router(shared_state: SharedState) -> Router {
|
|||
|
||||
/// Run the server with the specified arguments.
|
||||
pub async fn run(args: &Args) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let shared_state = AppState::new(&args.database).await?;
|
||||
let shared_state = AppState::new().await?;
|
||||
let app = router(shared_state.clone());
|
||||
|
||||
let addr = format!("{}:{}", args.ip, args.port);
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
use std::{
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
str::FromStr,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
use delay_map::{HashMapDelay, HashSetDelay};
|
||||
use sqlx::{
|
||||
sqlite::{SqliteConnectOptions, SqlitePoolOptions},
|
||||
SqlitePool,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::Msg;
|
||||
|
||||
/// How long a challenge can be replied to.
|
||||
const CHALLENGE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
/// How long an acesss token lasts.
|
||||
const ACCESS_TOKEN_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(60 * 60);
|
||||
|
||||
/// A particular signing session.
|
||||
#[derive(Debug)]
|
||||
pub struct Session {
|
||||
|
@ -36,7 +36,6 @@ pub struct AppState {
|
|||
pub(crate) sessions: Arc<RwLock<SessionState>>,
|
||||
pub(crate) challenges: Arc<RwLock<HashSetDelay<Uuid>>>,
|
||||
pub(crate) access_tokens: Arc<RwLock<HashMapDelay<Uuid, Vec<u8>>>>,
|
||||
pub(crate) db: SqlitePool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -47,22 +46,15 @@ pub struct SessionState {
|
|||
}
|
||||
|
||||
impl AppState {
|
||||
pub async fn new(database: &str) -> Result<SharedState, Box<dyn std::error::Error>> {
|
||||
tracing::event!(tracing::Level::INFO, "opening database {}", database);
|
||||
let options = SqliteConnectOptions::from_str(database)?.create_if_missing(true);
|
||||
let db = SqlitePoolOptions::new().connect_with(options).await?;
|
||||
sqlx::migrate!().run(&db).await?;
|
||||
pub async fn new() -> Result<SharedState, Box<dyn std::error::Error>> {
|
||||
let state = Self {
|
||||
sessions: Default::default(),
|
||||
challenges: RwLock::new(HashSetDelay::new(std::time::Duration::from_secs(10))).into(),
|
||||
access_tokens: RwLock::new(HashMapDelay::new(std::time::Duration::from_secs(60 * 60)))
|
||||
.into(),
|
||||
db,
|
||||
challenges: RwLock::new(HashSetDelay::new(CHALLENGE_TIMEOUT)).into(),
|
||||
access_tokens: RwLock::new(HashMapDelay::new(ACCESS_TOKEN_TIMEOUT)).into(),
|
||||
};
|
||||
Ok(Arc::new(state))
|
||||
}
|
||||
}
|
||||
|
||||
/// Type alias for the global state under a reference-counted RW mutex,
|
||||
/// which allows reading and writing the state across different handlers.
|
||||
/// Type alias for the global state under a reference-counted pointer.
|
||||
pub type SharedState = Arc<AppState>;
|
||||
|
|
|
@ -11,172 +11,16 @@ use axum_extra::{
|
|||
TypedHeader,
|
||||
};
|
||||
use eyre::eyre;
|
||||
use sqlx::{FromRow, SqlitePool};
|
||||
use tokio::task;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{state::SharedState, AppError};
|
||||
|
||||
/// An User, as stored in the database.
|
||||
#[derive(Debug, FromRow)]
|
||||
/// An User
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct User {
|
||||
pub(crate) id: i64,
|
||||
pub(crate) username: String,
|
||||
pub(crate) password: String,
|
||||
pub(crate) pubkey: Vec<u8>,
|
||||
#[sqlx(skip)]
|
||||
pub(crate) access_tokens: Vec<AccessToken>,
|
||||
#[sqlx(skip)]
|
||||
pub(crate) current_token: Option<Uuid>,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromRow)]
|
||||
#[allow(dead_code)]
|
||||
pub struct AccessToken {
|
||||
pub(crate) id: i64,
|
||||
pub(crate) user_id: i64,
|
||||
pub(crate) access_token: Option<Uuid>,
|
||||
}
|
||||
|
||||
/// Create user in the database.
|
||||
///
|
||||
/// The password is hashed and its hash is written in the DB.
|
||||
pub(crate) async fn create_user(
|
||||
db: SqlitePool,
|
||||
username: &str,
|
||||
password: &str,
|
||||
pubkey: Vec<u8>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// TODO: enforce mininum password length
|
||||
let password = password.to_owned();
|
||||
let pwhash = task::spawn_blocking(|| password_auth::generate_hash(password)).await?;
|
||||
sqlx::query(
|
||||
r#"
|
||||
insert into users (username, password, pubkey)
|
||||
values (?, ?, ?)
|
||||
"#,
|
||||
)
|
||||
.bind(username)
|
||||
.bind(pwhash)
|
||||
.bind(pubkey)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get user from database, or None if it's not registered.
|
||||
pub(crate) async fn get_user(
|
||||
db: SqlitePool,
|
||||
username: &str,
|
||||
) -> Result<Option<User>, Box<dyn std::error::Error>> {
|
||||
let user: Option<User> = sqlx::query_as("select * from users where username = ? ")
|
||||
.bind(username)
|
||||
.fetch_optional(&db)
|
||||
.await?;
|
||||
if let Some(mut user) = user {
|
||||
let access_tokens: Vec<AccessToken> =
|
||||
sqlx::query_as("select * from access_tokens where user_id = ?")
|
||||
.bind(user.id)
|
||||
.fetch_all(&db)
|
||||
.await?;
|
||||
user.access_tokens = access_tokens;
|
||||
Ok(Some(user))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete an User from the database, given its database ID.
|
||||
pub(crate) async fn delete_user(db: SqlitePool, id: i64) -> Result<(), Box<dyn std::error::Error>> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
delete from users where id = ?
|
||||
"#,
|
||||
)
|
||||
.bind(id)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Authenticate user registered in the database. Returns the User if
|
||||
/// authentication is successful, or None if the username or password is wrong.
|
||||
///
|
||||
/// The given password is hashed and verified against the stored hash.
|
||||
pub(crate) async fn authenticate_user(
|
||||
db: SqlitePool,
|
||||
username: &str,
|
||||
password: &str,
|
||||
) -> Result<Option<User>, Box<dyn std::error::Error>> {
|
||||
let user: Option<User> = get_user(db, username).await?;
|
||||
|
||||
// Verifying the password is blocking and potentially slow, so we'll do so
|
||||
// via `spawn_blocking`.
|
||||
let password = password.to_owned();
|
||||
let r: Result<_, password_auth::VerifyError> = task::spawn_blocking(|| {
|
||||
// We're using password-based authentication--this works by comparing our form
|
||||
// input with an argon2 password hash.
|
||||
Ok(user.filter(|user| password_auth::verify_password(password, &user.password).is_ok()))
|
||||
})
|
||||
.await?;
|
||||
Ok(r?)
|
||||
}
|
||||
|
||||
/// Refreshes the user's access token, identified by its id in the database.
|
||||
///
|
||||
/// Generates a new token and overwrites the old one in the database, if any.
|
||||
pub(crate) async fn add_access_token(
|
||||
db: SqlitePool,
|
||||
id: i64,
|
||||
) -> Result<Uuid, Box<dyn std::error::Error>> {
|
||||
let access_token = Uuid::new_v4();
|
||||
|
||||
sqlx::query(
|
||||
r#"
|
||||
insert into access_tokens (user_id, access_token)
|
||||
values (?, ?)
|
||||
"#,
|
||||
)
|
||||
.bind(id)
|
||||
.bind(access_token)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
Ok(access_token)
|
||||
}
|
||||
|
||||
/// Remove a user's access token.
|
||||
pub(crate) async fn remove_access_token(
|
||||
db: SqlitePool,
|
||||
access_token: Uuid,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
delete from access_tokens where access_token = ?
|
||||
"#,
|
||||
)
|
||||
.bind(access_token)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the User for a given access token, or None if there is no match.
|
||||
pub(crate) async fn get_user_for_access_token(
|
||||
db: SqlitePool,
|
||||
access_token: Uuid,
|
||||
) -> Result<Option<User>, Box<dyn std::error::Error>> {
|
||||
let user: Option<User> = sqlx::query_as(
|
||||
r#"
|
||||
select * from users inner join access_tokens on users.id = access_tokens.user_id where access_tokens.access_token = ?
|
||||
"#,
|
||||
)
|
||||
.bind(access_token)
|
||||
.fetch_optional(&db)
|
||||
.await?;
|
||||
Ok(user)
|
||||
pub(crate) current_token: Uuid,
|
||||
}
|
||||
|
||||
/// Read a User from a request. This is used to authenticate users. If any axum
|
||||
|
@ -219,32 +63,16 @@ impl FromRequestParts<SharedState> for User {
|
|||
.get(&access_token)
|
||||
.cloned();
|
||||
|
||||
let user = if let Some(pubkey) = pubkey {
|
||||
Some(User {
|
||||
id: -1,
|
||||
username: String::new(),
|
||||
password: String::new(),
|
||||
if let Some(pubkey) = pubkey {
|
||||
Ok(User {
|
||||
pubkey,
|
||||
access_tokens: vec![],
|
||||
current_token: Some(access_token),
|
||||
current_token: access_token,
|
||||
})
|
||||
} else {
|
||||
get_user_for_access_token(state.db.clone(), access_token)
|
||||
.await
|
||||
.map_err(|e| AppError(StatusCode::INTERNAL_SERVER_ERROR, e))?
|
||||
};
|
||||
|
||||
match user {
|
||||
Some(mut user) => {
|
||||
user.current_token = Some(access_token);
|
||||
Ok(user)
|
||||
}
|
||||
None => {
|
||||
return Err(AppError(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
eyre!("user not found").into(),
|
||||
))
|
||||
}
|
||||
return Err(AppError(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
eyre!("user not found").into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ async fn test_main_router<
|
|||
.collect();
|
||||
|
||||
// Instantiate test server using axum_test
|
||||
let shared_state = AppState::new(":memory:").await?;
|
||||
let shared_state = AppState::new().await?;
|
||||
let router = router(shared_state);
|
||||
let server = TestServer::new(router)?;
|
||||
|
||||
|
@ -85,7 +85,7 @@ async fn test_main_router<
|
|||
xed25519::PrivateKey::from(&TryInto::<[u8; 32]>::try_into(alice_keypair.private).unwrap());
|
||||
let alice_signature: [u8; 64] = alice_private.sign(alice_challenge.as_bytes(), &mut rng);
|
||||
let res = server
|
||||
.post("/key_login")
|
||||
.post("/login")
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: alice_challenge,
|
||||
pubkey: alice_keypair.public.clone(),
|
||||
|
@ -100,7 +100,7 @@ async fn test_main_router<
|
|||
xed25519::PrivateKey::from(&TryInto::<[u8; 32]>::try_into(bob_keypair.private).unwrap());
|
||||
let bob_signature: [u8; 64] = bob_private.sign(bob_challenge.as_bytes(), &mut rng);
|
||||
let res = server
|
||||
.post("/key_login")
|
||||
.post("/login")
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: bob_challenge,
|
||||
pubkey: bob_keypair.public.clone(),
|
||||
|
@ -389,7 +389,6 @@ async fn test_http() -> Result<(), Box<dyn std::error::Error>> {
|
|||
// Spawn server for testing
|
||||
tokio::spawn(async move {
|
||||
server::run(&Args {
|
||||
database: ":memory:".to_string(),
|
||||
ip: "127.0.0.1".to_string(),
|
||||
port: 2744,
|
||||
})
|
||||
|
@ -425,7 +424,7 @@ async fn test_http() -> Result<(), Box<dyn std::error::Error>> {
|
|||
xed25519::PrivateKey::from(&TryInto::<[u8; 32]>::try_into(alice_keypair.private).unwrap());
|
||||
let alice_signature: [u8; 64] = alice_private.sign(alice_challenge.as_bytes(), &mut rng);
|
||||
let r = client
|
||||
.post("http://127.0.0.1:2744/key_login")
|
||||
.post("http://127.0.0.1:2744/login")
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: alice_challenge,
|
||||
pubkey: alice_keypair.public.clone(),
|
||||
|
|
Loading…
Reference in New Issue