From 57eb4001ee7b2eeea1ef50f1bca0a9c83aeebccc Mon Sep 17 00:00:00 2001 From: Joe Ardent Date: Sun, 17 Dec 2023 16:41:04 -0800 Subject: [PATCH] almost works, still need to impl auth --- Cargo.lock | 321 +++++++++++++++------------------------- Cargo.toml | 5 +- src/auth.rs | 71 +++++++++ src/db.rs | 34 +---- src/generic_handlers.rs | 10 +- src/lib.rs | 32 ++-- src/login.rs | 27 ++-- src/main.rs | 19 +-- src/signup.rs | 20 +-- src/test_utils.rs | 4 +- src/users.rs | 6 +- src/watches/handlers.rs | 26 ++-- 12 files changed, 266 insertions(+), 309 deletions(-) create mode 100644 src/auth.rs diff --git a/Cargo.lock b/Cargo.lock index 80ad6af..9e84609 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,8 +158,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41603f7cdbf5ac4af60760f17253eb6adf6ec5b6f14a7ed830cf687d375f163" dependencies = [ "askama", - "axum-core 0.4.1", - "http 1.0.0", + "axum-core", + "http", ] [[package]] @@ -175,7 +175,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -231,7 +231,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -265,38 +265,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core 0.3.4", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http 0.2.11", - "http-body 0.4.6", - "hyper 0.14.27", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tower", - "tower-layer", - "tower-service", -] - [[package]] name = "axum" version = "0.7.2" @@ -304,14 +272,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d" dependencies = [ "async-trait", - "axum-core 0.4.1", + "axum-core", "axum-macros", "bytes", "futures-util", - "http 1.0.0", - "http-body 1.0.0", + "http", + "http-body", "http-body-util", - "hyper 1.0.1", + "hyper", "hyper-util", "itoa", "matchit", @@ -331,23 +299,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.11", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.4.1" @@ -357,8 +308,8 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.0.0", - "http-body 1.0.0", + "http", + "http-body", "http-body-util", "mime", "pin-project-lite", @@ -375,8 +326,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40f7051fdc094b6e5ea06cab9bca4b198c54dee4472a9419155f0ff19f19901e" dependencies = [ "async-trait", - "axum-core 0.4.1", - "http 1.0.0", + "axum-core", + "http", ] [[package]] @@ -386,7 +337,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61b018d073eea48729e2309c8ecd7198e1eea90e132d99a5e1cc7e952053c8d6" dependencies = [ "async-trait", - "axum 0.7.2", + "axum", "ring", "serde", "thiserror", @@ -407,24 +358,34 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] name = "axum-test" -version = "9.1.1" +version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8822bb73c863cdc96a4476fdae6443495c9c312f9f659720aa4ea59d76074577" +checksum = "56ac99db40006a1a3fffeb381f2a78cb341dbc99d07b561e8bd119e22a2b1b0f" dependencies = [ "anyhow", + "async-trait", "auto-future", - "axum 0.6.20", - "cookie 0.17.0", - "hyper 0.14.27", - "portpicker", + "axum", + "bytes", + "cookie", + "http", + "http-body-util", + "hyper", + "hyper-util", + "pretty_assertions", + "reserve-port", "serde", "serde_json", + "serde_urlencoded", + "smallvec", "tokio", + "tower", + "url", ] [[package]] @@ -621,7 +582,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -638,9 +599,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "constant_time_eq" @@ -648,16 +609,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -[[package]] -name = "cookie" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" -dependencies = [ - "time 0.3.30", - "version_check", -] - [[package]] name = "cookie" version = "0.18.0" @@ -701,9 +652,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "b9bcf5bdbfdd6030fb4a1c497b5d5fc5921aa2f60d359a17e249c0e6df3de153" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -711,9 +662,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" dependencies = [ "cfg-if 1.0.0", ] @@ -769,6 +720,12 @@ dependencies = [ "serde", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.9.0" @@ -942,7 +899,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1012,7 +969,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 1.0.0", + "http", "indexmap", "slab", "tokio", @@ -1062,9 +1019,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac 0.12.1", ] @@ -1090,22 +1047,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "http" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" -dependencies = [ - "bytes", - "fnv", - "itoa", + "windows-sys 0.52.0", ] [[package]] @@ -1119,17 +1065,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.11", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.0" @@ -1137,7 +1072,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", - "http 1.0.0", + "http", ] [[package]] @@ -1148,16 +1083,16 @@ checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" dependencies = [ "bytes", "futures-util", - "http 1.0.0", - "http-body 1.0.0", + "http", + "http-body", "pin-project-lite", ] [[package]] name = "http-range-header" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +checksum = "3ce4ef31cda248bbdb6e6820603b82dfcd9e833db65a43e997a0ccec777d11fe" [[package]] name = "httparse" @@ -1180,29 +1115,6 @@ dependencies = [ "libm", ] -[[package]] -name = "hyper" -version = "0.14.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http 0.2.11", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.4.10", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.0.1" @@ -1213,13 +1125,14 @@ dependencies = [ "futures-channel", "futures-util", "h2", - "http 1.0.0", - "http-body 1.0.0", + "http", + "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", "tokio", + "want", ] [[package]] @@ -1231,11 +1144,11 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.0.0", - "http-body 1.0.0", - "hyper 1.0.1", + "http", + "http-body", + "hyper", "pin-project-lite", - "socket2 0.5.5", + "socket2", "tokio", "tower", "tower-service", @@ -1576,7 +1489,7 @@ name = "optional_optional_user" version = "0.1.0" dependencies = [ "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1657,7 +1570,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1699,15 +1612,6 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" -[[package]] -name = "portpicker" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be97d76faf1bfab666e1375477b23fde79eccf0276e9b63b92a39d676a889ba9" -dependencies = [ - "rand", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -1720,6 +1624,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro2" version = "1.0.70" @@ -1831,6 +1745,16 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "reserve-port" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3969e7fe15c6c1532ba1a761628298e870bbd18c252fd41a58445f6091c372a0" +dependencies = [ + "lazy_static", + "thiserror", +] + [[package]] name = "ring" version = "0.17.7" @@ -1941,7 +1865,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -2076,16 +2000,6 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.5" @@ -2373,9 +2287,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" dependencies = [ "proc-macro2", "quote", @@ -2403,22 +2317,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -2500,7 +2414,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2", "tokio-macros", "tracing", "windows-sys 0.48.0", @@ -2514,7 +2428,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -2576,10 +2490,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fd0118512cf0b3768f7fcccf0bef1ae41d68f2b45edc1e77432b36c97c56c6d" dependencies = [ "async-trait", - "axum-core 0.4.1", - "cookie 0.18.0", + "axum-core", + "cookie", "futures-util", - "http 1.0.0", + "http", "parking_lot", "pin-project-lite", "tower-layer", @@ -2588,16 +2502,16 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +checksum = "09e12e6351354851911bdf8c2b8f2ab15050c567d70a8b9a37ae7b8301a4080d" dependencies = [ "bitflags 2.4.1", "bytes", - "futures-core", "futures-util", - "http 0.2.11", - "http-body 0.4.6", + "http", + "http-body", + "http-body-util", "http-range-header", "httpdate", "mime", @@ -2641,9 +2555,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d733b3ae4a6a4cb80cd585e87ffe1a1a7011174581785039c83c4cd63ee61c" dependencies = [ "async-trait", - "axum-core 0.4.1", + "axum-core", "futures", - "http 1.0.0", + "http", "parking_lot", "serde", "serde_json", @@ -2702,7 +2616,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -2903,7 +2817,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", "wasm-bindgen-shared", ] @@ -2925,7 +2839,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2945,13 +2859,14 @@ dependencies = [ "askama_axum", "async-session", "async-trait", - "axum 0.7.2", + "axum", "axum-htmx", "axum-login", "axum-macros", "axum-test", "chrono", "clap", + "http", "julid-rs", "justerror", "optional_optional_user", @@ -3144,23 +3059,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] -name = "zerocopy" -version = "0.7.30" +name = "yansi" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zerocopy" +version = "0.7.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.30" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba" +checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0cf37e1..cfe8238 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ axum-login = "0.10" axum-macros = "0.4" chrono = { version = "0.4", default-features = false, features = ["std", "clock"] } clap = { version = "4", features = ["derive", "env", "unicode", "suggestions", "usage"] } +http = "1.0.0" julid-rs = "1" justerror = "1" password-hash = { version = "0.5", features = ["std", "getrandom"] } @@ -33,13 +34,13 @@ tokio = { version = "1", features = ["full", "tracing"], default-features = fals tokio-retry = "0.3" tokio-stream = "0.1" tower = { version = "0.4", features = ["util", "timeout"], default-features = false } -tower-http = { version = "0.4", features = ["add-extension", "trace", "tracing", "fs"], default-features = false } +tower-http = { version = "0.5", features = ["add-extension", "trace", "tracing", "fs"], default-features = false } tower-sessions = { version = "0.7", default-features = false, features = ["sqlite-store"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } unicode-segmentation = "1" [dev-dependencies] -axum-test = "9" +axum-test = "14" serde_test = "1" diff --git a/src/auth.rs b/src/auth.rs new file mode 100644 index 0000000..a2df43b --- /dev/null +++ b/src/auth.rs @@ -0,0 +1,71 @@ +use async_trait::async_trait; + +use axum_login::{AuthnBackend, UserId}; + +use sqlx::SqlitePool; + +use tower_sessions::{ + cookie::time::Duration, Expiry, SessionManagerLayer, + SqliteStore, +}; + +use crate::User; + +const SESSION_TTL: Duration = Duration::new((365.2422 * 24. * 3600.0) as i64, 0); + +#[derive(Debug, Clone)] +pub struct AuthStore(SqlitePool); + +pub type AuthSession = axum_login::AuthSession; + +impl AuthStore { + pub fn new(pool: SqlitePool) -> Self { + AuthStore(pool) + } +} + +impl std::ops::DerefMut for AuthStore { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl std::ops::Deref for AuthStore { + type Target = SqlitePool; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[async_trait] +impl AuthnBackend for AuthStore { + type User = User; + + type Credentials = String; + + type Error = sqlx::Error; + + async fn authenticate( + &self, + _creds: Self::Credentials, + ) -> Result, Self::Error> { + todo!() + } + + async fn get_user(&self, _user_id: &UserId) -> Result, Self::Error> { + todo!() + } +} + +pub async fn session_layer(pool: SqlitePool) -> SessionManagerLayer { + let store = SqliteStore::new(pool); + store + .migrate() + .await + .expect("Calling `migrate()` should be reliable, is the DB gone?"); + + SessionManagerLayer::new(store) + .with_secure(true) + .with_expiry(Expiry::OnInactivity(SESSION_TTL)) +} diff --git a/src/db.rs b/src/db.rs index 680c985..26ca512 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,22 +1,14 @@ -use async_session::SessionStore; -use axum_login::{AuthManagerLayer, AuthManagerLayerBuilder, AuthSession, AuthUser, AuthnBackend}; -use julid::Julid; +use std::time::Duration; + use sqlx::{ migrate::Migrator, sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions}, SqlitePool, }; -use tower_sessions::{ - cookie::time::Duration, session_store::ExpiredDeletion, Expiry, Session, SessionManagerLayer, - SqliteStore, -}; - -use crate::User; const MAX_CONNS: u32 = 200; const MIN_CONNS: u32 = 5; const TIMEOUT: u64 = 11; -const SESSION_TTL: Duration = Duration::new((365.2422 * 24. * 3600.0) as i64, 0); pub fn get_db_pool() -> SqlitePool { let db_filename = { @@ -48,8 +40,7 @@ pub fn get_db_pool() -> SqlitePool { .journal_mode(SqliteJournalMode::Wal) .synchronous(sqlx::sqlite::SqliteSynchronous::Normal) .filename(&db_filename) - // need to build this out of band and put it in the project root; see instructions at - // https://gitlab.com/nebkor/julid + // be sure to have run `make` so that the libjulid extension is built .extension("./libjulid") .busy_timeout(Duration::from_secs(TIMEOUT)) .create_if_missing(true); @@ -86,25 +77,6 @@ pub fn get_db_pool() -> SqlitePool { pool } -pub async fn session_layer(pool: SqlitePool) -> SessionManagerLayer { - let store = SqliteStore::new(pool); - store - .migrate() - .await - .expect("Calling `migrate()` should be reliable, is the DB gone?"); - - SessionManagerLayer::new(store) - .with_secure(true) - .with_expiry(Expiry::OnInactivity(SESSION_TTL.into())) -} - -pub async fn auth_layer( - pool: SqlitePool, - secret: &[u8], -) -> AuthManagerLayer> { - todo!() -} - //-************************************************************************ // Tests for `db` module. //-************************************************************************ diff --git a/src/generic_handlers.rs b/src/generic_handlers.rs index 15118c2..0b05e92 100644 --- a/src/generic_handlers.rs +++ b/src/generic_handlers.rs @@ -1,21 +1,19 @@ use axum::response::{IntoResponse, Redirect}; -use crate::{AuthContext, MainPage}; +use crate::{AuthSession, MainPage}; pub async fn handle_slash_redir() -> impl IntoResponse { Redirect::to("/") } -pub async fn handle_slash(auth: AuthContext) -> impl IntoResponse { - if let Some(ref user) = auth.current_user { +pub async fn handle_slash(auth: AuthSession) -> impl IntoResponse { + if let Some(ref user) = auth.user { let name = &user.username; tracing::debug!("Logged in as: {name}"); } else { tracing::debug!("Not logged in."); } - MainPage { - user: auth.current_user, - } + MainPage { user: auth.user } } #[cfg(test)] diff --git a/src/lib.rs b/src/lib.rs index 8e563dc..7a5c429 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -use axum::routing::IntoMakeService; +use axum::{error_handling::HandleErrorLayer, routing::IntoMakeService, BoxError}; use sqlx::SqlitePool; #[macro_use] extern crate justerror; @@ -10,12 +10,14 @@ pub mod test_utils; /// app pub use db::get_db_pool; pub mod import_utils; + pub use users::User; pub use watches::{ShowKind, Watch, WatchQuest}; pub type WWRouter = axum::Router; // everything else is private to the crate +mod auth; mod db; mod generic_handlers; mod login; @@ -26,17 +28,16 @@ mod util; mod watches; // things we want in the crate namespace +use auth::AuthSession; use optional_optional_user::OptionalOptionalUser; use templates::*; use watches::templates::*; -type AuthContext = - axum_login::extractors::AuthContext>; - /// Returns the router to be used as a service or test object, you do you. -pub async fn app(db_pool: sqlx::SqlitePool, secret: &[u8]) -> IntoMakeService { - use axum::{middleware, routing::get}; +pub async fn app(db_pool: sqlx::SqlitePool) -> IntoMakeService { // don't bother bringing handlers into the whole crate namespace + use auth::*; + use axum::{middleware, routing::get}; use generic_handlers::{handle_slash, handle_slash_redir}; use login::{get_login, get_logout, post_login, post_logout}; use signup::{get_create_user, get_signup_success, post_create_user}; @@ -46,23 +47,25 @@ pub async fn app(db_pool: sqlx::SqlitePool, secret: &[u8]) -> IntoMakeService IntoMakeService (StatusCode::OK, "Not successful.").into_response(), + // we don't say it's a bad password, we just silently fail _ => (StatusCode::OK, format!("{self}")).into_response(), } } @@ -60,7 +61,7 @@ pub struct LoginPostForm { /// Handle login queries #[axum::debug_handler] pub async fn post_login( - mut auth: AuthContext, + mut auth: AuthSession, State(pool): State, Form(login): Form, ) -> Result { @@ -98,11 +99,15 @@ pub async fn get_logout() -> impl IntoResponse { LogoutPage } -pub async fn post_logout(mut auth: AuthContext) -> impl IntoResponse { - if auth.current_user.is_some() { - auth.logout().await; +pub async fn post_logout(mut auth: AuthSession) -> impl IntoResponse { + match auth.logout() { + Ok(_) => LogoutSuccessPage.into_response(), + Err(e) => { + tracing::debug!("{e}"); + let e: LoginError = LoginErrorKind::Internal.into(); + e.into_response() + } } - LogoutSuccessPage } //-************************************************************************ @@ -131,7 +136,7 @@ mod test { rt.block_on(async { let s = server_with_pool(&db).await; let resp = s.get("/login").await; - let body = std::str::from_utf8(resp.bytes()).unwrap().to_string(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap().to_string(); assert_eq!(body, LoginPage::default().to_string()); }) } @@ -215,7 +220,7 @@ mod test { rt.block_on(async { let s = server_with_pool(&db).await; let resp = s.get("/logout").await; - let body = std::str::from_utf8(resp.bytes()).unwrap().to_string(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap().to_string(); assert_eq!(body, LogoutPage.to_string()); }) } @@ -232,7 +237,7 @@ mod test { let s = server_with_pool(&db).await; let resp = s.post("/logout").await; resp.assert_status_ok(); - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); let default = LogoutSuccessPage.to_string(); assert_eq!(body, &default); }) @@ -263,11 +268,11 @@ mod test { let logged_in = MainPage { user: Some(user) }.to_string(); let main_page = s.get("/").await; - let body = std::str::from_utf8(main_page.bytes()).unwrap(); + let body = std::str::from_utf8(main_page.as_bytes()).unwrap(); assert_eq!(&logged_in, body); let resp = s.post("/logout").await; - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); let default = LogoutSuccessPage.to_string(); assert_eq!(body, &default); }) diff --git a/src/main.rs b/src/main.rs index 1d9e851..9e0ae43 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,5 @@ use std::net::SocketAddr; -use rand::{thread_rng, RngCore}; use tokio::signal; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; use what2watch::get_db_pool; @@ -21,24 +20,16 @@ fn main() { .build() .unwrap(); - let secret = { - let mut bytes = [0u8; 64]; - let mut rng = thread_rng(); - rng.fill_bytes(&mut bytes); - bytes - }; - - let app = rt.block_on(what2watch::app(pool.clone(), &secret)); + let app = rt.block_on(what2watch::app(pool.clone())); rt.block_on(async { let addr: SocketAddr = ([0, 0, 0, 0], 3000).into(); tracing::debug!("binding to {addr:?}"); - axum::Server::bind(&addr) - .serve(app) - .with_graceful_shutdown(shutdown_signal()) - .await - .unwrap_or_default(); + let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); + axum::serve(listener, app).await.unwrap(); + //.with_graceful_shutdown(shutdown_signal()) // removed in 0.7 because of upstream dep changes + }); rt.block_on(pool.close()); diff --git a/src/signup.rs b/src/signup.rs index 84c7a58..27ae94c 100644 --- a/src/signup.rs +++ b/src/signup.rs @@ -235,7 +235,7 @@ mod test { let server = server_with_pool(&pool).await; let resp = server.get("/signup").await; - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); let expected = SignupPage::default().to_string(); assert_eq!(&expected, body); }); @@ -265,7 +265,7 @@ mod test { let path = format!("/signup_success/{id}"); let resp = server.get(&path).expect_success().await; - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); let expected = SignupSuccessPage(user).to_string(); assert_eq!(&expected, body); }); @@ -310,7 +310,7 @@ mod test { let user = User::try_get("bad_user", &pool).await; assert!(user.is_err()); - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); let expected = CreateUserError(CreateUserErrorKind::PasswordMismatch).to_string(); assert_eq!(&expected, body); }); @@ -336,7 +336,7 @@ mod test { let user = User::try_get("bad_user", &pool).await; assert!(user.is_err()); - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); let expected = CreateUserError(CreateUserErrorKind::BadPassword).to_string(); assert_eq!(&expected, body); }); @@ -362,7 +362,7 @@ mod test { let user = User::try_get("bad_user", &pool).await; assert!(user.is_err()); - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); let expected = CreateUserError(CreateUserErrorKind::BadPassword).to_string(); assert_eq!(&expected, body); }); @@ -396,7 +396,7 @@ mod test { let user = User::try_get("bad_user", &pool).await; assert!(user.is_err()); - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); let expected = CreateUserError(CreateUserErrorKind::BadPassword).to_string(); assert_eq!(&expected, body); }); @@ -422,7 +422,7 @@ mod test { let user = User::try_get("bad_user", &pool).await; assert!(user.is_err()); - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); let expected = CreateUserError(CreateUserErrorKind::BadUsername).to_string(); assert_eq!(&expected, body); }); @@ -448,7 +448,7 @@ mod test { let user = User::try_get("bad_user", &pool).await; assert!(user.is_err()); - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); let expected = CreateUserError(CreateUserErrorKind::BadUsername).to_string(); assert_eq!(&expected, body); }); @@ -483,7 +483,7 @@ mod test { assert_eq!(resp.status_code(), StatusCode::OK); let expected = CreateUserError(CreateUserErrorKind::AlreadyExists).to_string(); - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); assert_eq!(&expected, body); }); } @@ -508,7 +508,7 @@ mod test { let user = User::try_get("bad_user", &pool).await; assert!(user.is_err()); - let body = std::str::from_utf8(resp.bytes()).unwrap(); + let body = std::str::from_utf8(resp.as_bytes()).unwrap(); let expected = CreateUserError(CreateUserErrorKind::BadDisplayname).to_string(); assert_eq!(&expected, body); }); diff --git a/src/test_utils.rs b/src/test_utils.rs index f8b9c60..c17cf21 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -8,8 +8,6 @@ use crate::User; pub const FORM_CONTENT_TYPE: &str = "application/x-www-form-urlencoded"; pub async fn server_with_pool(pool: &SqlitePool) -> TestServer { - let secret = [0u8; 64]; - let user = get_test_user(); insert_user_with_id(&user, pool).await; @@ -19,7 +17,7 @@ pub async fn server_with_pool(pool: &SqlitePool) -> TestServer { .unwrap_or_default(); assert!(r == 1); - let app = crate::app(pool.clone(), &secret).await; + let app = crate::app(pool.clone()).await; let config = TestServerConfig { save_cookies: true, diff --git a/src/users.rs b/src/users.rs index 02a80f8..bb76578 100644 --- a/src/users.rs +++ b/src/users.rs @@ -13,7 +13,7 @@ use julid::Julid; use serde::{Deserialize, Serialize}; use sqlx::SqlitePool; -use crate::AuthContext; +use crate::auth::AuthSession; const USERNAME_QUERY: &str = "select * from users where username = $1"; const LAST_SEEN_QUERY: &str = "update users set last_seen = (select unixepoch()) where id = $1"; @@ -94,11 +94,11 @@ impl User { pub async fn handle_update_last_seen( State(pool): State, - auth: AuthContext, + auth: AuthSession, request: Request, next: Next, ) -> impl IntoResponse { - if let Some(user) = auth.current_user { + if let Some(user) = auth.user { if let Some(then) = user.last_seen { let now = SystemTime::now() .duration_since(UNIX_EPOCH) diff --git a/src/watches/handlers.rs b/src/watches/handlers.rs index 1fec9a6..c5b92f2 100644 --- a/src/watches/handlers.rs +++ b/src/watches/handlers.rs @@ -10,7 +10,7 @@ use sqlx::{query, query_as, query_scalar, SqlitePool}; use super::templates::{AddNewWatchPage, GetWatchPage, SearchWatchesPage}; use crate::{ util::{empty_string_as_none, year_to_epoch}, - AuthContext, MyWatchesPage, ShowKind, Watch, WatchQuest, + AuthSession, MyWatchesPage, ShowKind, Watch, WatchQuest, }; //-************************************************************************ @@ -104,10 +104,8 @@ pub struct PostAddExistingWatch { // handlers //-************************************************************************ -pub async fn get_add_new_watch(auth: AuthContext) -> impl IntoResponse { - AddNewWatchPage { - user: auth.current_user, - } +pub async fn get_add_new_watch(auth: AuthSession) -> impl IntoResponse { + AddNewWatchPage { user: auth.user } } struct QuestQuest { @@ -118,11 +116,11 @@ struct QuestQuest { /// Add a Watch to your watchlist (side effects system-add) pub async fn post_add_new_watch( - auth: AuthContext, + auth: AuthSession, State(pool): State, Form(form): Form, ) -> Result { - if let Some(user) = auth.current_user { + if let Some(user) = auth.user { { let release_date = year_to_epoch(form.year.as_deref()); let watch = Watch { @@ -195,7 +193,7 @@ async fn add_new_watch_impl( /// Add a Watch to your watchlist by selecting it with a checkbox pub async fn post_add_watch_quest( - _auth: AuthContext, + _auth: AuthSession, State(_pool): State, Form(_form): Form, ) -> impl IntoResponse { @@ -218,7 +216,7 @@ pub async fn _add_watch_quest_impl(pool: &SqlitePool, quest: &WatchQuest) -> Res /// A single Watch pub async fn get_watch( - auth: AuthContext, + auth: AuthSession, watch: Option>, State(pool): State, ) -> impl IntoResponse { @@ -234,13 +232,13 @@ pub async fn get_watch( GetWatchPage { watch, - user: auth.current_user, + user: auth.user, } } /// everything the user has saved -pub async fn get_watches(auth: AuthContext, State(pool): State) -> impl IntoResponse { - let user = auth.current_user; +pub async fn get_watches(auth: AuthSession, State(pool): State) -> impl IntoResponse { + let user = auth.user; let watches: Vec = if (user).is_some() { query_as(GET_SAVED_WATCHES_QUERY) .bind(user.as_ref().unwrap().id) @@ -255,11 +253,11 @@ pub async fn get_watches(auth: AuthContext, State(pool): State) -> i } pub async fn get_search_watch( - auth: AuthContext, + auth: AuthSession, State(pool): State, search: Query, ) -> impl IntoResponse { - let user = auth.current_user; + let user = auth.user; let (search_string, qstring) = if search.0 != EMPTY_SEARCH_QUERY_STRUCT { let s = search.0;