From f41e0caa7482531ac7d490862ff9a76a2a2020be Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Wed, 16 Aug 2023 00:02:44 +0100 Subject: [PATCH 1/5] feat: got started on allowing old members to set an email for password recovery --- Cargo.lock | 487 ++++++++++++++++++++++++++++++++- Cargo.toml | 3 + src/lib.rs | 17 ++ src/main.rs | 1 + src/methods/account_recover.rs | 93 +++++++ 5 files changed, 588 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e3bfebb..3ec38b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,7 +19,7 @@ checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" dependencies = [ "aes-soft", "aesni", - "cipher", + "cipher 0.2.5", ] [[package]] @@ -30,7 +30,7 @@ checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" dependencies = [ "aead", "aes", - "cipher", + "cipher 0.2.5", "ctr", "ghash", "subtle", @@ -42,7 +42,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" dependencies = [ - "cipher", + "cipher 0.2.5", "opaque-debug", ] @@ -52,7 +52,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" dependencies = [ - "cipher", + "cipher 0.2.5", "opaque-debug", ] @@ -353,6 +353,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.12.3" @@ -371,6 +377,12 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bincode" version = "1.3.3" @@ -501,6 +513,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "concurrent-queue" version = "2.2.0" @@ -510,6 +532,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + [[package]] name = "const_fn" version = "0.4.9" @@ -604,6 +632,18 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "crypto-bigint" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -671,7 +711,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" dependencies = [ - "cipher", + "cipher 0.2.5", ] [[package]] @@ -705,6 +745,43 @@ dependencies = [ "winapi", ] +[[package]] +name = "curve25519-dalek" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f711ade317dd348950a9910f81c5947e3d8907ebd2b83f76203ff1807e6a2bc2" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "platforms", + "rustc_version 0.4.0", + "subtle", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "digest" version = "0.9.0" @@ -721,7 +798,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -736,12 +815,81 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dsa" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5638f6d17447bc0ffc46354949ee366847e83450e2a07895862942085cc9761" +dependencies = [ + "digest 0.10.7", + "num-bigint-dig", + "num-traits", + "pkcs8", + "rfc6979", + "sha2 0.10.7", + "signature", + "zeroize", +] + +[[package]] +name = "ecdsa" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +dependencies = [ + "curve25519-dalek", + "ed25519", + "sha2 0.10.7", +] + [[package]] name = "either" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "elliptic-curve" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "email-encoding" version = "0.2.0" @@ -828,6 +976,22 @@ dependencies = [ "web-sys", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + [[package]] name = "flume" version = "0.9.2" @@ -848,7 +1012,7 @@ dependencies = [ "futures-core", "futures-sink", "pin-project", - "spin", + "spin 0.9.8", ] [[package]] @@ -1004,6 +1168,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1050,6 +1215,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1125,6 +1301,15 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "hostname" version = "0.3.1" @@ -1244,6 +1429,15 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -1325,6 +1519,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "lber" @@ -1389,6 +1586,12 @@ version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + [[package]] name = "libnghttp2-sys" version = "0.1.7+1.45.0" @@ -1545,6 +1748,44 @@ dependencies = [ "minimal-lexical", ] +[[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 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -1552,6 +1793,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1610,6 +1852,30 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.7", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.7", +] + [[package]] name = "parking" version = "2.1.0" @@ -1647,6 +1913,15 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +[[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.2.0" @@ -1691,12 +1966,39 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + [[package]] name = "polling" version = "2.8.0" @@ -1730,6 +2032,15 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "primeorder" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1873,19 +2184,61 @@ dependencies = [ "bitflags", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + [[package]] name = "route-recognizer" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56770675ebc04927ded3e60633437841581c285dc6236109ea25fbf3beb7b59e" +[[package]] +name = "rsa" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +dependencies = [ + "byteorder", + "const-oid", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "sha2 0.10.7", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.18", ] [[package]] @@ -1923,6 +2276,20 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "2.9.1" @@ -1955,6 +2322,12 @@ dependencies = [ "semver-parser", ] +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + [[package]] name = "semver-parser" version = "0.7.0" @@ -2033,6 +2406,17 @@ dependencies = [ "sha1_smol", ] +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha1_smol" version = "1.0.0" @@ -2054,9 +2438,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if 1.0.0", "cpufeatures", @@ -2082,6 +2466,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + [[package]] name = "simple-mutex" version = "1.1.5" @@ -2105,6 +2499,7 @@ dependencies = [ "rand 0.8.5", "serde", "sqlx", + "ssh-key", "surf", "tide", ] @@ -2145,6 +2540,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" @@ -2163,6 +2564,16 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "sqlformat" version = "0.2.1" @@ -2217,7 +2628,7 @@ dependencies = [ "once_cell", "paste", "percent-encoding", - "sha2 0.10.6", + "sha2 0.10.7", "smallvec", "sqlformat", "sqlx-rt", @@ -2238,7 +2649,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "sha2 0.10.6", + "sha2 0.10.7", "sqlx-core", "sqlx-rt", "syn 1.0.109", @@ -2256,6 +2667,50 @@ dependencies = [ "native-tls", ] +[[package]] +name = "ssh-cipher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" +dependencies = [ + "cipher 0.4.4", + "ssh-encoding", +] + +[[package]] +name = "ssh-encoding" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" +dependencies = [ + "base64ct", + "pem-rfc7468", + "sha2 0.10.7", +] + +[[package]] +name = "ssh-key" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0a17fec6ea344bfa1cda3aed2f0696fddc6295cfcc8c454a3bf58b8ffaabeb" +dependencies = [ + "dsa", + "ed25519-dalek", + "num-bigint-dig", + "p256", + "p384", + "rand_core 0.6.4", + "rsa", + "sec1", + "sha1 0.10.5", + "sha2 0.10.7", + "signature", + "ssh-cipher", + "ssh-encoding", + "subtle", + "zeroize", +] + [[package]] name = "standback" version = "0.2.17" @@ -2272,7 +2727,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" dependencies = [ "discard", - "rustc_version", + "rustc_version 0.2.3", "stdweb-derive", "stdweb-internal-macros", "stdweb-internal-runtime", @@ -2304,7 +2759,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "sha1", + "sha1 0.6.1", "syn 1.0.109", ] @@ -2984,3 +3439,9 @@ name = "windows_x86_64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/Cargo.toml b/Cargo.toml index bc1bf5f..1825971 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,3 +41,6 @@ csv = "1.2" lettre = "0.10.4" maud = "0.25.0" +# verifying ssh keys +ssh-key = { version = "0.6.0", features = ["ecdsa", "rand_core", "std", "dsa", "ed25519", "rsa" ] } + diff --git a/src/lib.rs b/src/lib.rs index 03e5a51..d1fafa6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,13 @@ pub struct AccountsReset { pub date_expiry: String, } +#[derive(Debug, Clone, Deserialize, Serialize, sqlx::FromRow)] +pub struct AccountsSSH { + pub user: String, + pub auth_code: String, + pub email: String, +} + #[derive(Debug, Clone, Deserialize, Serialize, sqlx::FromRow)] pub struct Accounts { pub user: String, @@ -95,6 +102,16 @@ pub async fn db_init(config: &Config) -> Result, Error> { .execute(&pool) .await?; + sqlx::query( + "CREATE TABLE IF NOT EXISTS accounts_ssh ( + user text primary key, + auth_code text not null, + email text not null + )", + ) + .execute(&pool) + .await?; + sqlx::query( "CREATE TABLE IF NOT EXISTS accounts_reset ( user text primary key, diff --git a/src/main.rs b/src/main.rs index e860632..e8e80fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,6 +31,7 @@ async fn main() -> tide::Result<()> { app.at("/ldap/recover/password").post(account_recover::password::reset); app.at("/ldap/recover/password/auth").post(account_recover::password::auth); app.at("/ldap/recover/username").post(account_recover::username::submit); + app.at("/ldap/recover/ssh/request").post(account_recover::ssh::request); app.listen(host_port).await?; Ok(()) diff --git a/src/methods/account_recover.rs b/src/methods/account_recover.rs index eb954c6..7737ee8 100644 --- a/src/methods/account_recover.rs +++ b/src/methods/account_recover.rs @@ -422,3 +422,96 @@ pub mod username { mailer.send(&email) } } + +pub mod ssh { + use super::*; + use crate::AccountsSSH; + use ssh_key::AuthorizedKeys; + use std::fs; + + // this is for a legacy member who has forgotten their account password to be able to set an email. + // With an email they can do a password recovery + + #[derive(Debug, Deserialize)] + struct RequestChallenge { + user: String, + email: String, + } + + #[derive(Debug, Deserialize)] + struct RequestResult { + auth: String, + keys: Vec, + } + + pub async fn request(mut req: Request) -> tide::Result { + let RequestChallenge { + user, + email, + } = req.body_json().await?; + + // check that any mail is not using @skynet.ie + if email.trim().ends_with("@skynet.ie") { + // all responses from this are a success + return Ok(json!({"result": "error", "error": "Skynet email not permitted."}).into()); + } + + // check if //.ssh/authorized_keys exists + //let root = "/skynet_old"; + let root = "."; + let path = format!("{}/{}/.ssh/authorized_keys", root, user); + let mut keys = vec![]; + if fs::read_to_string(&path).is_ok() { + if let Ok(x) = AuthorizedKeys::read_file(path) { + for entry in x { + if let Ok(y) = entry.public_key().to_openssh() { + keys.push(y); + } + } + } + } + + if keys.is_empty() { + return Ok(json!({ "result": "success", "success": { "auth": "", "keys": keys }}).into()); + } + + let db = &req.state().db; + + // check if there is ane listing entry, use that auth if exists + if let Ok(result) = sqlx::query_as::<_, AccountsSSH>( + r#" + SELECT * + FROM accounts_ssh + WHERE user == ? + "#, + ) + .bind(&user) + .fetch_one(db) + .await + { + return Ok(json!({ "result": "success", "success": { "auth": result.auth_code, "keys": keys }}).into()); + } + + // not in db, generate auth and save + let auth = random_string(50); + if sqlx::query_as::<_, AccountsSSH>( + " + INSERT OR REPLACE INTO accounts_ssh (user, auth_code, email) + VALUES (?1, ?2, ?3) + ", + ) + .bind(&user) + .bind(&auth) + .bind(&email) + .fetch_optional(db) + .await + .is_err() + { + // dont return any keys + return Ok(json!({ "result": "success", "success": { "auth": "", "keys": [] }}).into()); + } + + // return the full thing + Ok(json!({"result": "success","success": { "auth": auth,"keys": keys }}).into()) + } +} -- 2.46.1 From 82d7ca48bb6d879d01c2a6f28166128159ff26cd Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sat, 19 Aug 2023 20:41:07 +0100 Subject: [PATCH 2/5] feat: added verification for the ssh keys Closes #15 --- Cargo.lock | 4 +- Cargo.toml | 3 +- silver/.ssh/authorized_keys | 3 + src/main.rs | 1 + src/methods/account_recover.rs | 100 ++++++++++++++++++++++++++++++++- 5 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 silver/.ssh/authorized_keys diff --git a/Cargo.lock b/Cargo.lock index 3ec38b1..8ee6a84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2690,9 +2690,9 @@ dependencies = [ [[package]] name = "ssh-key" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0a17fec6ea344bfa1cda3aed2f0696fddc6295cfcc8c454a3bf58b8ffaabeb" +checksum = "728fdf5286c394f12d83eaad51190af629aade5494813ce6b57f7425f1ca51b7" dependencies = [ "dsa", "ed25519-dalek", diff --git a/Cargo.toml b/Cargo.toml index 1825971..7556d3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,5 +42,4 @@ lettre = "0.10.4" maud = "0.25.0" # verifying ssh keys -ssh-key = { version = "0.6.0", features = ["ecdsa", "rand_core", "std", "dsa", "ed25519", "rsa" ] } - +ssh-key = { version = "0.6.1", features = ["crypto", "dsa"] } diff --git a/silver/.ssh/authorized_keys b/silver/.ssh/authorized_keys new file mode 100644 index 0000000..776f908 --- /dev/null +++ b/silver/.ssh/authorized_keys @@ -0,0 +1,3 @@ +# --- BEGIN PVE --- +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBHbsOjxIcLasz+CHA8gUg1pvc8dPHwMKdWoIwNvPxLp Desktop_WSL +# --- END PVE --- \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e8e80fc..b7ddedf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,7 @@ async fn main() -> tide::Result<()> { app.at("/ldap/recover/password/auth").post(account_recover::password::auth); app.at("/ldap/recover/username").post(account_recover::username::submit); app.at("/ldap/recover/ssh/request").post(account_recover::ssh::request); + app.at("/ldap/recover/ssh/verify").post(account_recover::ssh::verify); app.listen(host_port).await?; Ok(()) diff --git a/src/methods/account_recover.rs b/src/methods/account_recover.rs index 7737ee8..68df84c 100644 --- a/src/methods/account_recover.rs +++ b/src/methods/account_recover.rs @@ -426,7 +426,9 @@ pub mod username { pub mod ssh { use super::*; use crate::AccountsSSH; - use ssh_key::AuthorizedKeys; + use ldap3::Mod; + use ssh_key::{AuthorizedKeys, SshSig}; + use std::collections::HashSet; use std::fs; // this is for a legacy member who has forgotten their account password to be able to set an email. @@ -479,7 +481,7 @@ pub mod ssh { // check if there is ane listing entry, use that auth if exists if let Ok(result) = sqlx::query_as::<_, AccountsSSH>( - r#" + r#" SELECT * FROM accounts_ssh WHERE user == ? @@ -495,7 +497,7 @@ pub mod ssh { // not in db, generate auth and save let auth = random_string(50); if sqlx::query_as::<_, AccountsSSH>( - " + " INSERT OR REPLACE INTO accounts_ssh (user, auth_code, email) VALUES (?1, ?2, ?3) ", @@ -514,4 +516,96 @@ pub mod ssh { // return the full thing Ok(json!({"result": "success","success": { "auth": auth,"keys": keys }}).into()) } + + #[derive(Debug, Deserialize)] + struct RequestVerify { + user: String, + auth_signed: String, + } + + // echo "auth code" | ssh-keygen -Y sign -n file -f /path/to/key + pub async fn verify(mut req: Request) -> tide::Result { + let RequestVerify { + user, + auth_signed, + } = req.body_json().await?; + + let db = &req.state().db; + let config = &req.state().config; + let details = if let Ok(result) = sqlx::query_as::<_, AccountsSSH>( + r#" + SELECT * + FROM accounts_ssh + WHERE user == ? + "#, + ) + .bind(&user) + .fetch_one(db) + .await + { + result + } else { + return Ok(json!({ "result": "error"}).into()); + }; + + // check if //.ssh/authorized_keys exists + //let root = "/skynet_old"; + let root = "."; + let path = format!("{}/{}/.ssh/authorized_keys", root, user); + + let sig = match SshSig::from_pem(auth_signed) { + Ok(x) => x, + Err(_) => { + return Ok(json!({ "result": "error", "error": "Incorrect signed format"}).into()); + } + }; + + // when ye echo it adds a newline to the end of the "file", need to duplicate it here. + let msg_tmp = format!("{}\n", details.auth_code); + let msg = msg_tmp.as_bytes(); + + let mut valid = false; + if fs::read_to_string(&path).is_ok() { + if let Ok(x) = AuthorizedKeys::read_file(path) { + for entry in x { + let key = entry.public_key(); + match key.verify("file", msg, &sig) { + Ok(_) => { + valid = true; + break; + } + Err(_) => {} + } + } + } + } + + if !valid { + return Ok(json!({"result": "error", "error": "no valid key"}).into()); + } + + // add to ldap + let mut ldap = LdapConn::new(&config.ldap_host)?; + ldap.simple_bind(&config.ldap_admin, &config.ldap_admin_pw)?.success()?; + + let mods = vec![Mod::Replace(String::from("mail"), HashSet::from([details.email]))]; + + let dn = format!("uid={},ou=users,dc=skynet,dc=ie", &user); + ldap.modify(&dn, mods)?.success()?; + ldap.unbind()?; + + // delete from tmp + sqlx::query_as::<_, AccountsSSH>( + r#" + DELETE FROM accounts_ssh + WHERE user == ? + "#, + ) + .bind(&user) + .fetch_optional(db) + .await?; + + // return the full thing + Ok(json!({"result": "success", "success": "key valid"}).into()) + } } -- 2.46.1 From 8bec5e87b5bd48ca75eac5caeb8f23673bc94c83 Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sat, 19 Aug 2023 20:47:58 +0100 Subject: [PATCH 3/5] fix: set a root for the ssh verification. --- flake.nix | 1 + src/lib.rs | 5 +++++ src/methods/account_recover.rs | 5 +++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 90ef311..28b1d4e 100644 --- a/flake.nix +++ b/flake.nix @@ -56,6 +56,7 @@ DATABASE = "database.db"; CSV = "wolves.csv"; HOST_PORT = cfg.host_port; + SSH_ROOT = "/skynet_old/home"; # Email stuff EMAIL_SMTP = cfg.mail.host; diff --git a/src/lib.rs b/src/lib.rs index d1fafa6..7e730dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -188,6 +188,7 @@ pub struct Config { pub mail_smtp: String, pub mail_user: String, pub mail_pass: String, + pub ssh_root: String, } pub fn get_config() -> Config { @@ -205,6 +206,7 @@ pub fn get_config() -> Config { mail_smtp: "".to_string(), mail_user: "".to_string(), mail_pass: "".to_string(), + ssh_root: "/skynet_old/home".to_string(), }; if let Ok(x) = env::var("LDAP_HOST") { @@ -237,6 +239,9 @@ pub fn get_config() -> Config { if let Ok(x) = env::var("EMAIL_PASS") { config.mail_pass = x.trim().to_string(); } + if let Ok(x) = env::var("SSH_ROOT") { + config.ssh_root = x.trim().to_string(); + } config } diff --git a/src/methods/account_recover.rs b/src/methods/account_recover.rs index 68df84c..daddbfa 100644 --- a/src/methods/account_recover.rs +++ b/src/methods/account_recover.rs @@ -458,9 +458,10 @@ pub mod ssh { return Ok(json!({"result": "error", "error": "Skynet email not permitted."}).into()); } + let config = &req.state().config; + // check if //.ssh/authorized_keys exists - //let root = "/skynet_old"; - let root = "."; + let root = &config.ssh_root; let path = format!("{}/{}/.ssh/authorized_keys", root, user); let mut keys = vec![]; if fs::read_to_string(&path).is_ok() { -- 2.46.1 From bacb03d051149a2dde784edb30bd500f1d21670d Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sat, 19 Aug 2023 21:29:23 +0100 Subject: [PATCH 4/5] doc: updated documentation --- README.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c69c2e..15d2c22 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ All responses: ### POST /ldap/recover/password/auth ```json -{ +{ "auth" : "Auth key from teh email", "pass" : "Password the user chooses" } @@ -127,6 +127,65 @@ Success: {"result": "success", "success": "Password set"} ``` +### POST /ldap/recover/ssh/request +This endpoint can set emails for old skynet members who previously logged in via ssh keys. +1. Request for their account. +2. A list of public keys will be displayed. +3. Sign using one of the private keys. +4. Submit the pem value. + +```bash +echo "auth code" | ssh-keygen -Y sign -n file -f /path/to/private/key +``` + +```json +{ + "user" : "Skynet username", + "email" : "Email to set" +} +``` + +Errors: +```json +{"result": "error", "error": "Skynet email not permitted."} +``` + +```json +{ "result": "success", "success": { "auth": "", "keys": [] }} +``` +```json +{ "result": "success", "success": { "auth": "code here", "keys": ["key 1", "key 2"] }} +``` + +### POST /ldap/recover/ssh/verify + + +```json +{ + "user" : "Skynet username", + "auth_signed" : "signed auth code" +} +``` + +#### Errors +```json +{ "result": "error"} +``` + +```json +{ "result": "error", "error": "Incorrect signed format"} +``` + +```json +{"result": "error", "error": "no valid key"} +``` + +#### Success + +```json +{"result": "success", "success": "key valid"} +``` + ## Responses Generic responses which is used unless otherwise specified above. -- 2.46.1 From ab4b8d37dff1fb0819e568b804b5539728f78b98 Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sat, 19 Aug 2023 21:31:52 +0100 Subject: [PATCH 5/5] fmt: fmt and clippy --- src/methods/account_recover.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/methods/account_recover.rs b/src/methods/account_recover.rs index daddbfa..eb0087f 100644 --- a/src/methods/account_recover.rs +++ b/src/methods/account_recover.rs @@ -440,12 +440,6 @@ pub mod ssh { email: String, } - #[derive(Debug, Deserialize)] - struct RequestResult { - auth: String, - keys: Vec, - } - pub async fn request(mut req: Request) -> tide::Result { let RequestChallenge { user, @@ -459,7 +453,7 @@ pub mod ssh { } let config = &req.state().config; - + // check if //.ssh/authorized_keys exists let root = &config.ssh_root; let path = format!("{}/{}/.ssh/authorized_keys", root, user); @@ -570,12 +564,9 @@ pub mod ssh { if let Ok(x) = AuthorizedKeys::read_file(path) { for entry in x { let key = entry.public_key(); - match key.verify("file", msg, &sig) { - Ok(_) => { - valid = true; - break; - } - Err(_) => {} + if key.verify("file", msg, &sig).is_ok() { + valid = true; + break; } } } -- 2.46.1