diff --git a/Cargo.lock b/Cargo.lock index c49ab7e..4c31fdd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/coordinator/src/args.rs b/coordinator/src/args.rs index 8dbb329..52d9a9b 100644 --- a/coordinator/src/args.rs +++ b/coordinator/src/args.rs @@ -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 { /// 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, - /// 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 { /// 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>, - /// The coordinator's communication public key. + /// The coordinator's communication public key for HTTP mode. pub comm_pubkey: Option>, /// 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` 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 ProcessedArgs { input: &mut dyn BufRead, output: &mut dyn Write, ) -> Result> { - 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 ProcessedArgs { Ok(ProcessedArgs { cli: args.cli, http: args.http, - username: args.username.clone(), - password, signers, num_signers, public_key_package, @@ -214,7 +187,6 @@ impl ProcessedArgs { 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, diff --git a/coordinator/src/comms/http.rs b/coordinator/src/comms/http.rs index c2f6e3d..0849637 100644 --- a/coordinator/src/comms/http.rs +++ b/coordinator/src/comms/http.rs @@ -266,12 +266,11 @@ pub struct HTTPComms { client: reqwest::Client, host_port: String, session_id: Option, - access_token: String, + access_token: Option, num_signers: u16, args: ProcessedArgs, state: SessionState, pubkeys: HashMap, Identifier>, - should_logout: bool, // The "send" Noise objects by pubkey of recipients. send_noise: Option, Noise>>, // The "receive" Noise objects by pubkey of senders. @@ -286,12 +285,11 @@ impl HTTPComms { 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 Comms for HTTPComms { ); 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::() - .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::() + .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 Comms for HTTPComms { 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 Comms for HTTPComms { 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 Comms for HTTPComms { 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 Comms for HTTPComms { 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()?; diff --git a/frost-client/src/args.rs b/frost-client/src/args.rs index d7ed121..2d4f94b 100644 --- a/frost-client/src/args.rs +++ b/frost-client/src/args.rs @@ -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, - /// The server URL to use, if desired. - #[arg(short, long)] - server_url: Option, - /// The path to the config file to manage. If not specified, it uses - /// $HOME/.local/frost/credentials.toml - #[arg(short, long)] - config: Option, - }, - /// 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, /// 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, - /// 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, /// 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. diff --git a/frost-client/src/config.rs b/frost-client/src/config.rs index b7f80f1..a5373c3 100644 --- a/frost-client/src/config.rs +++ b/frost-client/src/config.rs @@ -18,10 +18,6 @@ pub struct Config { #[serde(skip)] path: Option, pub version: u8, - /// The registry of servers the user has registered into, keyed by server - /// URL. - #[serde(default)] - pub registry: BTreeMap, /// The communication key pair for the user. pub communication_key: Option, /// 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> { - 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, - /// 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, - /// The username of the participant in the server, if any. - pub username: Option, } impl Config { diff --git a/frost-client/src/contact.rs b/frost-client/src/contact.rs index 55ae2e5..14be983 100644 --- a/frost-client/src/contact.rs +++ b/frost-client/src/contact.rs @@ -20,28 +20,17 @@ pub struct Contact { deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec" )] pub pubkey: Vec, - /// The URL of the server where the contact is registered, if any. - pub server_url: Option, - /// The username of the contact on `server_url`, if registered. - pub username: Option, } 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> { /// Export a contact from the user's address book in the config file. pub(crate) fn export(args: &Command) -> Result<(), Box> { - 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> { .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:"); diff --git a/frost-client/src/coordinator.rs b/frost-client/src/coordinator.rs index 61b764e..2c1f99c 100644 --- a/frost-client/src/coordinator.rs +++ b/frost-client/src/coordinator.rs @@ -76,8 +76,6 @@ pub(crate) async fn run_for_ciphersuite( 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( .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 diff --git a/frost-client/src/init.rs b/frost-client/src/init.rs index 11df5ab..7f2d06a 100644 --- a/frost-client/src/init.rs +++ b/frost-client/src/init.rs @@ -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> { - 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::().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 {}...", diff --git a/frost-client/src/login.rs b/frost-client/src/login.rs deleted file mode 100644 index 039f078..0000000 --- a/frost-client/src/login.rs +++ /dev/null @@ -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> { - 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::().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(()) -} diff --git a/frost-client/src/main.rs b/frost-client/src/main.rs index 7fd3a2c..4435ffc 100644 --- a/frost-client/src/main.rs +++ b/frost-client/src/main.rs @@ -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> { 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), diff --git a/frost-client/src/participant.rs b/frost-client/src/participant.rs index 2999d18..453cd9c 100644 --- a/frost-client/src/participant.rs +++ b/frost-client/src/participant.rs @@ -66,15 +66,12 @@ pub(crate) async fn run_for_ciphersuite( 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 diff --git a/frost-client/src/trusted_dealer.rs b/frost-client/src/trusted_dealer.rs index 0aac2cb..ff1a475 100644 --- a/frost-client/src/trusted_dealer.rs +++ b/frost-client/src/trusted_dealer.rs @@ -37,7 +37,6 @@ pub(crate) fn trusted_dealer_for_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, - /// Key package to use. pub key_package: KeyPackage, @@ -94,15 +75,14 @@ pub struct ProcessedArgs { /// 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>, - /// The participant's communication public key. + /// The participant's communication public key for HTTP mode. pub comm_pubkey: Option>, /// 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` 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 ProcessedArgs { input: &mut dyn BufRead, output: &mut dyn Write, ) -> Result> { - 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::>(&bytes) { @@ -137,12 +111,9 @@ impl ProcessedArgs { 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, diff --git a/participant/src/comms/http.rs b/participant/src/comms/http.rs index 30775d5..847cd05 100644 --- a/participant/src/comms/http.rs +++ b/participant/src/comms/http.rs @@ -104,8 +104,7 @@ pub struct HTTPComms { client: reqwest::Client, host_port: String, session_id: Option, - access_token: String, - should_logout: bool, + access_token: Option, args: ProcessedArgs, send_noise: Option, recv_noise: Option, @@ -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::() - .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::() + .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::() @@ -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::() @@ -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(()) } diff --git a/participant/src/tests/round1.rs b/participant/src/tests/round1.rs index afc5292..d4ed5e8 100644 --- a/participant/src/tests/round1.rs +++ b/participant/src/tests/round1.rs @@ -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(); diff --git a/server/Cargo.toml b/server/Cargo.toml index 1b51135..5ffe17d 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -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" diff --git a/server/src/args.rs b/server/src/args.rs index 56de185..ce551c2 100644 --- a/server/src/args.rs +++ b/server/src/args.rs @@ -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, } diff --git a/server/src/functions.rs b/server/src/functions.rs index 82c2740..d42033f 100644 --- a/server/src/functions.rs +++ b/server/src/functions.rs @@ -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, - Json(args): Json, -) -> Result, 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, Json(args): Json, ) -> Result, 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, - Json(args): Json, -) -> Result, 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, user: User, ) -> Result, 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, - user: User, -) -> Result, 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, 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, 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, user: User, @@ -241,6 +157,21 @@ pub(crate) async fn get_session_info( ) -> Result, 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, 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, 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, user: User, @@ -331,16 +262,31 @@ pub(crate) async fn close_session( ) -> Result, 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); } diff --git a/server/src/lib.rs b/server/src/lib.rs index d3e6f25..0761c41 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -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> { - 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); diff --git a/server/src/state.rs b/server/src/state.rs index 66de3da..5e4adb8 100644 --- a/server/src/state.rs +++ b/server/src/state.rs @@ -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>, pub(crate) challenges: Arc>>, pub(crate) access_tokens: Arc>>>, - pub(crate) db: SqlitePool, } #[derive(Debug, Default)] @@ -47,22 +46,15 @@ pub struct SessionState { } impl AppState { - pub async fn new(database: &str) -> Result> { - 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> { 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; diff --git a/server/src/user.rs b/server/src/user.rs index 11ce3ae..ac042fb 100644 --- a/server/src/user.rs +++ b/server/src/user.rs @@ -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, - #[sqlx(skip)] - pub(crate) access_tokens: Vec, - #[sqlx(skip)] - pub(crate) current_token: Option, -} - -#[derive(Debug, FromRow)] -#[allow(dead_code)] -pub struct AccessToken { - pub(crate) id: i64, - pub(crate) user_id: i64, - pub(crate) access_token: Option, -} - -/// 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, -) -> Result<(), Box> { - // 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, Box> { - let user: Option = sqlx::query_as("select * from users where username = ? ") - .bind(username) - .fetch_optional(&db) - .await?; - if let Some(mut user) = user { - let access_tokens: Vec = - 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> { - 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, Box> { - let user: Option = 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> { - 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> { - 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, Box> { - let user: Option = 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 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(), + )); } } } diff --git a/server/tests/integration_tests.rs b/server/tests/integration_tests.rs index 9c2a6d9..3cfb265 100644 --- a/server/tests/integration_tests.rs +++ b/server/tests/integration_tests.rs @@ -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> { // 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> { 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(),