almost works, still need to impl auth

This commit is contained in:
Joe Ardent 2023-12-17 16:41:04 -08:00
parent d4a684de29
commit 57eb4001ee
12 changed files with 266 additions and 309 deletions

321
Cargo.lock generated
View File

@ -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]]

View File

@ -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"

71
src/auth.rs Normal file
View File

@ -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<AuthStore>;
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<Option<Self::User>, Self::Error> {
todo!()
}
async fn get_user(&self, _user_id: &UserId<Self>) -> Result<Option<Self::User>, Self::Error> {
todo!()
}
}
pub async fn session_layer(pool: SqlitePool) -> SessionManagerLayer<SqliteStore> {
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))
}

View File

@ -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<SqliteStore> {
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<SqliteStore, SessionManagerLayer<SqliteStore>> {
todo!()
}
//-************************************************************************
// Tests for `db` module.
//-************************************************************************

View File

@ -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)]

View File

@ -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<SqlitePool>;
// 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<julid::Julid, User, axum_login::SqliteStore<User>>;
/// 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<axum::Router> {
use axum::{middleware, routing::get};
pub async fn app(db_pool: sqlx::SqlitePool) -> IntoMakeService<axum::Router> {
// 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<ax
post_add_watch_quest,
};
let (session_layer, auth_layer) = {
let session_layer = db::session_layer(db_pool.clone(), secret).await;
let auth_layer = db::auth_layer(db_pool.clone(), secret).await;
(session_layer, auth_layer)
let auth_layer = {
let sessions = session_layer(db_pool.clone()).await;
let store = AuthStore::new(db_pool.clone());
tower::ServiceBuilder::new()
.layer(HandleErrorLayer::new(|_: BoxError| async {
http::StatusCode::BAD_REQUEST
}))
.layer(axum_login::AuthManagerLayerBuilder::new(store, sessions).build())
};
let css_dir = std::env::current_dir()
.unwrap()
.join("templates")
.join("css");
let css_svc = ServeDir::new(css_dir.as_path());
axum::Router::new()
.route("/", get(handle_slash).post(handle_slash))
.nest_service(
"/css",
ServeDir::new(css_dir.as_path()).append_index_html_on_directories(false),
)
.nest_service("/css", css_svc)
.route("/signup", get(get_create_user).post(post_create_user))
.route("/signup_success/:id", get(get_signup_success))
.route("/login", get(get_login).post(post_login))
@ -82,7 +85,6 @@ pub async fn app(db_pool: sqlx::SqlitePool, secret: &[u8]) -> IntoMakeService<ax
users::handle_update_last_seen,
))
.layer(auth_layer)
.layer(session_layer)
.with_state(db_pool)
.into_make_service()
}

View File

@ -11,7 +11,7 @@ use axum::{
use serde::{Deserialize, Serialize};
use sqlx::SqlitePool;
use crate::{AuthContext, LoginPage, LogoutPage, LogoutSuccessPage, User};
use crate::{AuthSession, LoginPage, LogoutPage, LogoutSuccessPage, User};
//-************************************************************************
// Constants
@ -41,6 +41,7 @@ impl IntoResponse for LoginError {
)
.into_response(),
LoginErrorKind::Unknown => (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<SqlitePool>,
Form(login): Form<LoginPostForm>,
) -> Result<impl IntoResponse, LoginError> {
@ -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);
})

View File

@ -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());

View File

@ -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);
});

View File

@ -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,

View File

@ -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<SqlitePool>,
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)

View File

@ -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<SqlitePool>,
Form(form): Form<PostAddNewWatch>,
) -> Result<impl IntoResponse, WatchAddError> {
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<SqlitePool>,
Form(_form): Form<PostAddExistingWatch>,
) -> 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<Path<String>>,
State(pool): State<SqlitePool>,
) -> 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<SqlitePool>) -> impl IntoResponse {
let user = auth.current_user;
pub async fn get_watches(auth: AuthSession, State(pool): State<SqlitePool>) -> impl IntoResponse {
let user = auth.user;
let watches: Vec<Watch> = 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<SqlitePool>) -> i
}
pub async fn get_search_watch(
auth: AuthContext,
auth: AuthSession,
State(pool): State<SqlitePool>,
search: Query<SearchQuery>,
) -> 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;