Compare commits
No commits in common. "79305724f2ef7600d7e19375bcd94ecc0318717a" and "08a6e5b0faeafee99b87561e844ae13eb4c25d43" have entirely different histories.
79305724f2
...
08a6e5b0fa
10 changed files with 121 additions and 772 deletions
494
Cargo.lock
generated
494
Cargo.lock
generated
|
|
@ -17,15 +17,6 @@ version = "0.2.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android_system_properties"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.21"
|
version = "0.6.21"
|
||||||
|
|
@ -236,12 +227,6 @@ version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.10.0"
|
version = "2.10.0"
|
||||||
|
|
@ -269,16 +254,6 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bstr"
|
|
||||||
version = "1.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.19.1"
|
version = "3.19.1"
|
||||||
|
|
@ -319,39 +294,6 @@ version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chrono"
|
|
||||||
version = "0.4.43"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
|
|
||||||
dependencies = [
|
|
||||||
"iana-time-zone",
|
|
||||||
"num-traits",
|
|
||||||
"windows-link",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chrono-tz"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb"
|
|
||||||
dependencies = [
|
|
||||||
"chrono",
|
|
||||||
"chrono-tz-build",
|
|
||||||
"phf",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chrono-tz-build"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1"
|
|
||||||
dependencies = [
|
|
||||||
"parse-zoneinfo",
|
|
||||||
"phf",
|
|
||||||
"phf_codegen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.54"
|
version = "4.5.54"
|
||||||
|
|
@ -424,12 +366,6 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core-foundation-sys"
|
|
||||||
version = "0.8.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
|
|
@ -454,25 +390,6 @@ version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-deque"
|
|
||||||
version = "0.8.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-epoch",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-queue"
|
name = "crossbeam-queue"
|
||||||
version = "0.3.12"
|
version = "0.3.12"
|
||||||
|
|
@ -531,12 +448,6 @@ dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "deunicode"
|
|
||||||
version = "1.6.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
|
|
@ -630,15 +541,6 @@ dependencies = [
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "file-id"
|
|
||||||
version = "0.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e1fc6a637b6dc58414714eddd9170ff187ecb0933d4c7024d1abbd23a3cc26e9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys 0.60.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
|
@ -677,15 +579,6 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fsevent-sys"
|
|
||||||
version = "4.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
|
|
@ -809,30 +702,6 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "globset"
|
|
||||||
version = "0.4.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"bstr",
|
|
||||||
"log",
|
|
||||||
"regex-automata",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "globwalk"
|
|
||||||
version = "0.9.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"ignore",
|
|
||||||
"walkdir",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.5"
|
version = "0.15.5"
|
||||||
|
|
@ -943,15 +812,6 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "humansize"
|
|
||||||
version = "2.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
|
|
||||||
dependencies = [
|
|
||||||
"libm",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
|
|
@ -989,30 +849,6 @@ dependencies = [
|
||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone"
|
|
||||||
version = "0.1.64"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
|
|
||||||
dependencies = [
|
|
||||||
"android_system_properties",
|
|
||||||
"core-foundation-sys",
|
|
||||||
"iana-time-zone-haiku",
|
|
||||||
"js-sys",
|
|
||||||
"log",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"windows-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone-haiku"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
|
|
@ -1115,22 +951,6 @@ dependencies = [
|
||||||
"icu_properties",
|
"icu_properties",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ignore"
|
|
||||||
version = "0.4.25"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-deque",
|
|
||||||
"globset",
|
|
||||||
"log",
|
|
||||||
"memchr",
|
|
||||||
"regex-automata",
|
|
||||||
"same-file",
|
|
||||||
"walkdir",
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.12.1"
|
version = "2.12.1"
|
||||||
|
|
@ -1141,26 +961,6 @@ dependencies = [
|
||||||
"hashbrown 0.16.1",
|
"hashbrown 0.16.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "inotify"
|
|
||||||
version = "0.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"inotify-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "inotify-sys"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.2"
|
version = "1.70.2"
|
||||||
|
|
@ -1192,26 +992,6 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kqueue"
|
|
||||||
version = "1.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a"
|
|
||||||
dependencies = [
|
|
||||||
"kqueue-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kqueue-sys"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
@ -1239,7 +1019,7 @@ version = "0.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
|
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.7.0",
|
"redox_syscall 0.7.0",
|
||||||
]
|
]
|
||||||
|
|
@ -1333,7 +1113,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
@ -1383,57 +1162,17 @@ dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"axum-login",
|
"axum-login",
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"notify-debouncer-full",
|
|
||||||
"password-auth",
|
"password-auth",
|
||||||
"serde",
|
"serde",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"tera",
|
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-livereload",
|
|
||||||
"tower-sessions",
|
"tower-sessions",
|
||||||
"tower-sessions-sqlx-store",
|
"tower-sessions-sqlx-store",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "notify"
|
|
||||||
version = "8.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"fsevent-sys",
|
|
||||||
"inotify",
|
|
||||||
"kqueue",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"mio",
|
|
||||||
"notify-types",
|
|
||||||
"walkdir",
|
|
||||||
"windows-sys 0.60.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "notify-debouncer-full"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "375bd3a138be7bfeff3480e4a623df4cbfb55b79df617c055cd810ba466fa078"
|
|
||||||
dependencies = [
|
|
||||||
"file-id",
|
|
||||||
"log",
|
|
||||||
"notify",
|
|
||||||
"notify-types",
|
|
||||||
"walkdir",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "notify-types"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.50.3"
|
version = "0.50.3"
|
||||||
|
|
@ -1536,15 +1275,6 @@ dependencies = [
|
||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parse-zoneinfo"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24"
|
|
||||||
dependencies = [
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "password-auth"
|
name = "password-auth"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
@ -1583,49 +1313,6 @@ version = "2.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pest"
|
|
||||||
version = "2.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2c9eb05c21a464ea704b53158d358a31e6425db2f63a1a7312268b05fe2b75f7"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
"ucd-trie",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pest_derive"
|
|
||||||
version = "2.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "68f9dbced329c441fa79d80472764b1a2c7e57123553b8519b36663a2fb234ed"
|
|
||||||
dependencies = [
|
|
||||||
"pest",
|
|
||||||
"pest_generator",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pest_generator"
|
|
||||||
version = "2.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3bb96d5051a78f44f43c8f712d8e810adb0ebf923fc9ed2655a7f66f63ba8ee5"
|
|
||||||
dependencies = [
|
|
||||||
"pest",
|
|
||||||
"pest_meta",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pest_meta"
|
|
||||||
version = "2.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "602113b5b5e8621770cfd490cfd90b9f84ab29bd2b0e49ad83eb6d186cef2365"
|
|
||||||
dependencies = [
|
|
||||||
"pest",
|
|
||||||
"sha2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "petgraph"
|
name = "petgraph"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
|
|
@ -1638,44 +1325,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
|
|
||||||
dependencies = [
|
|
||||||
"phf_shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_codegen"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
|
|
||||||
dependencies = [
|
|
||||||
"phf_generator",
|
|
||||||
"phf_shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_generator"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
|
||||||
dependencies = [
|
|
||||||
"phf_shared",
|
|
||||||
"rand",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_shared"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
|
||||||
dependencies = [
|
|
||||||
"siphasher",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
|
@ -1793,7 +1442,7 @@ version = "0.5.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1802,19 +1451,7 @@ version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
|
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.12.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-automata",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2034,28 +1671,12 @@ dependencies = [
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "siphasher"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.11"
|
version = "0.4.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
|
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "slug"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724"
|
|
||||||
dependencies = [
|
|
||||||
"deunicode",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.15.1"
|
version = "1.15.1"
|
||||||
|
|
@ -2188,7 +1809,7 @@ checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64",
|
"base64",
|
||||||
"bitflags 2.10.0",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"crc",
|
"crc",
|
||||||
|
|
@ -2231,7 +1852,7 @@ checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64",
|
"base64",
|
||||||
"bitflags 2.10.0",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"crc",
|
"crc",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
|
|
@ -2343,28 +1964,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tera"
|
|
||||||
version = "1.20.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e8004bca281f2d32df3bacd59bc67b312cb4c70cea46cbd79dbe8ac5ed206722"
|
|
||||||
dependencies = [
|
|
||||||
"chrono",
|
|
||||||
"chrono-tz",
|
|
||||||
"globwalk",
|
|
||||||
"humansize",
|
|
||||||
"lazy_static",
|
|
||||||
"percent-encoding",
|
|
||||||
"pest",
|
|
||||||
"pest_derive",
|
|
||||||
"rand",
|
|
||||||
"regex",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"slug",
|
|
||||||
"unicode-segmentation",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.69"
|
version = "1.0.69"
|
||||||
|
|
@ -2472,9 +2071,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.49.0"
|
version = "1.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
|
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -2547,20 +2146,6 @@ version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
|
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tower-livereload"
|
|
||||||
version = "0.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "62a893f6b4fbc35dc32eacd6b5cf61dd49abac153ac7b3892c5725b350912e25"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"http",
|
|
||||||
"http-body",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tokio",
|
|
||||||
"tower",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-service"
|
name = "tower-service"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
|
@ -2700,12 +2285,6 @@ version = "1.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ucd-trie"
|
|
||||||
version = "0.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.18"
|
version = "0.3.18"
|
||||||
|
|
@ -2733,12 +2312,6 @@ version = "0.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
|
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-segmentation"
|
|
||||||
version = "1.12.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.8"
|
version = "2.5.8"
|
||||||
|
|
@ -2873,65 +2446,12 @@ dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-core"
|
|
||||||
version = "0.62.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
|
||||||
dependencies = [
|
|
||||||
"windows-implement",
|
|
||||||
"windows-interface",
|
|
||||||
"windows-link",
|
|
||||||
"windows-result",
|
|
||||||
"windows-strings",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-implement"
|
|
||||||
version = "0.60.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-interface"
|
|
||||||
version = "0.59.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-link"
|
name = "windows-link"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-result"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-strings"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,3 @@ displaydoc.workspace = true
|
||||||
password-auth = { workspace = true }
|
password-auth = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||||
tera = "1.20.1"
|
|
||||||
notify-debouncer-full = "0.6.0"
|
|
||||||
tower-livereload = "0.10.2"
|
|
||||||
|
|
|
||||||
|
|
@ -1,63 +1,54 @@
|
||||||
use std::sync::LazyLock;
|
use axum::Form;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::response::Html;
|
use axum::response::Html;
|
||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
|
use axum::response::Redirect;
|
||||||
use axum::routing::get;
|
use axum::routing::get;
|
||||||
|
use axum::routing::post;
|
||||||
use axum_login::AuthManagerLayerBuilder;
|
use axum_login::AuthManagerLayerBuilder;
|
||||||
|
use axum_login::AuthUser;
|
||||||
use axum_login::AuthnBackend;
|
use axum_login::AuthnBackend;
|
||||||
use axum_login::login_required;
|
use axum_login::login_required;
|
||||||
use displaydoc::Display;
|
use displaydoc::Display;
|
||||||
use notify_debouncer_full::DebouncedEvent;
|
use password_auth::generate_hash;
|
||||||
use notify_debouncer_full::notify::EventKind;
|
|
||||||
use password_auth::verify_password;
|
use password_auth::verify_password;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use tera::Context;
|
use sqlx::prelude::FromRow;
|
||||||
use tera::Tera;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use tokio::task::AbortHandle;
|
use tokio::task::AbortHandle;
|
||||||
use tower_livereload::LiveReloadLayer;
|
|
||||||
use tower_sessions::ExpiredDeletion;
|
use tower_sessions::ExpiredDeletion;
|
||||||
use tower_sessions::SessionManagerLayer;
|
use tower_sessions::SessionManagerLayer;
|
||||||
use tower_sessions_sqlx_store::SqliteStore;
|
use tower_sessions_sqlx_store::SqliteStore;
|
||||||
use tracing::error;
|
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
pub mod users;
|
|
||||||
|
|
||||||
pub type WebResult<T> = Result<T, AppError>;
|
|
||||||
|
|
||||||
#[derive(Debug, Error, Display)]
|
|
||||||
pub enum AppError {
|
|
||||||
/// An error occurred while templating
|
|
||||||
Tera(#[from] tera::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoResponse for AppError {
|
|
||||||
fn into_response(self) -> axum::response::Response {
|
|
||||||
let mut error_context = Context::new();
|
|
||||||
error_context.insert("error", &self.to_string());
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
Html(
|
|
||||||
render_template("internal_error.tera.html", &error_context)
|
|
||||||
.unwrap_or_else(|_| "ERROR RENDERING ERROR! FATAL".to_string()),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.into_response()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
run().await
|
run().await
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthSession = axum_login::AuthSession<Backend>;
|
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||||
|
struct User {
|
||||||
|
id: i64,
|
||||||
|
username: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthUser for User {
|
||||||
|
type Id = i64;
|
||||||
|
|
||||||
|
fn id(&self) -> Self::Id {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn session_auth_hash(&self) -> &[u8] {
|
||||||
|
self.password.as_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Backend {
|
struct Backend {
|
||||||
|
|
@ -65,7 +56,7 @@ struct Backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
struct UserCredentials {
|
struct Credentials {
|
||||||
username: String,
|
username: String,
|
||||||
password: String,
|
password: String,
|
||||||
}
|
}
|
||||||
|
|
@ -80,8 +71,8 @@ pub enum AuthBackendError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AuthnBackend for Backend {
|
impl AuthnBackend for Backend {
|
||||||
type User = users::User;
|
type User = User;
|
||||||
type Credentials = UserCredentials;
|
type Credentials = Credentials;
|
||||||
type Error = AuthBackendError;
|
type Error = AuthBackendError;
|
||||||
|
|
||||||
async fn authenticate(
|
async fn authenticate(
|
||||||
|
|
@ -94,7 +85,7 @@ impl AuthnBackend for Backend {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
task::spawn_blocking(move || {
|
task::spawn_blocking(move || {
|
||||||
Ok(user.filter(|user| verify_password(&creds.password, user.password()).is_ok()))
|
Ok(user.filter(|user| verify_password(&creds.password, &user.password).is_ok()))
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
@ -113,13 +104,10 @@ impl AuthnBackend for Backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AppState {
|
pub(crate) struct AppState {
|
||||||
pub db: SqlitePool,
|
pub db: SqlitePool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static TERA: LazyLock<std::sync::RwLock<Tera>> =
|
|
||||||
LazyLock::new(|| Tera::new("templates/**.tera.html").unwrap().into());
|
|
||||||
|
|
||||||
async fn run() -> anyhow::Result<()> {
|
async fn run() -> anyhow::Result<()> {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
.with_env_filter(EnvFilter::from_default_env())
|
||||||
|
|
@ -143,54 +131,21 @@ async fn run() -> anyhow::Result<()> {
|
||||||
let backend = Backend { db: db.clone() };
|
let backend = Backend { db: db.clone() };
|
||||||
let auth_layer = AuthManagerLayerBuilder::new(backend, session_layer).build();
|
let auth_layer = AuthManagerLayerBuilder::new(backend, session_layer).build();
|
||||||
|
|
||||||
let livereload = LiveReloadLayer::new();
|
|
||||||
let reloader = livereload.reloader();
|
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/protected", get(show_protected))
|
.route("/protected", get(show_protected))
|
||||||
.route_layer(login_required!(Backend, login_url = "/login"))
|
.route_layer(login_required!(Backend, login_url = "/login"))
|
||||||
.merge(users::routes())
|
.route("/login", get(show_login))
|
||||||
|
.route("/login", post(do_login))
|
||||||
|
.route("/register", get(show_register))
|
||||||
|
.route("/register", post(do_register))
|
||||||
.layer(auth_layer)
|
.layer(auth_layer)
|
||||||
.layer(livereload)
|
|
||||||
.with_state(AppState { db });
|
.with_state(AppState { db });
|
||||||
|
|
||||||
let mut debouncer = notify_debouncer_full::new_debouncer(
|
|
||||||
Duration::from_millis(50),
|
|
||||||
None,
|
|
||||||
move |event: Result<Vec<DebouncedEvent>, Vec<notify_debouncer_full::notify::Error>>| {
|
|
||||||
match event {
|
|
||||||
Ok(events) => {
|
|
||||||
if events
|
|
||||||
.iter()
|
|
||||||
.any(|ev| !matches!(ev.event.kind, EventKind::Access(_)))
|
|
||||||
{
|
|
||||||
match TERA.write().unwrap().full_reload() {
|
|
||||||
Ok(()) => {
|
|
||||||
reloader.reload();
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
error!("Could not reload tera templates: {error}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_e) => {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
debouncer.watch(
|
|
||||||
"templates/",
|
|
||||||
notify_debouncer_full::notify::RecursiveMode::Recursive,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||||
axum::serve(listener, app.into_make_service())
|
axum::serve(listener, app.into_make_service())
|
||||||
.with_graceful_shutdown(shutdown_signal(deletion_task.abort_handle()))
|
.with_graceful_shutdown(shutdown_signal(deletion_task.abort_handle()))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
debouncer.stop();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,10 +171,85 @@ async fn shutdown_signal(handle: AbortHandle) {
|
||||||
handle.abort();
|
handle.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_template(name: &str, context: &Context) -> tera::Result<String> {
|
async fn show_protected() -> Html<String> {
|
||||||
TERA.read().unwrap().render(name, context)
|
format!(
|
||||||
|
r##"
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Yay, you did it!
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"##
|
||||||
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn show_protected() -> Html<String> {
|
async fn show_login() -> Html<String> {
|
||||||
Html(render_template("protected.tera.html", &Context::default()).unwrap())
|
format!(
|
||||||
|
r##"
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<form action="/login" method="POST">
|
||||||
|
<input type="text" name="username"/>
|
||||||
|
<input type="password" name="password"/>
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"##
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn show_register() -> Html<String> {
|
||||||
|
format!(
|
||||||
|
r##"
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<form action="/register" method="POST">
|
||||||
|
<input type="text" name="username"/>
|
||||||
|
<input type="password" name="password"/>
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"##
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthSession = axum_login::AuthSession<Backend>;
|
||||||
|
|
||||||
|
async fn do_register(
|
||||||
|
app_state: State<AppState>,
|
||||||
|
Form(creds): Form<Credentials>,
|
||||||
|
) -> Result<impl IntoResponse, Html<String>> {
|
||||||
|
sqlx::query("INSERT INTO users (username, password) VALUES (?, ?)")
|
||||||
|
.bind(creds.username)
|
||||||
|
.bind(generate_hash(creds.password))
|
||||||
|
.execute(&app_state.db)
|
||||||
|
.await
|
||||||
|
.map_err(|err| Html(err.to_string()))?;
|
||||||
|
|
||||||
|
Ok(Redirect::to("/login").into_response())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn do_login(
|
||||||
|
mut auth_session: AuthSession,
|
||||||
|
Form(creds): Form<Credentials>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let user = match auth_session.authenticate(creds.clone()).await {
|
||||||
|
Ok(Some(user)) => user,
|
||||||
|
Ok(None) => return StatusCode::UNAUTHORIZED.into_response(),
|
||||||
|
Err(_) => return StatusCode::INTERNAL_SERVER_ERROR.into_response(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if auth_session.login(&user).await.is_err() {
|
||||||
|
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||||
|
}
|
||||||
|
|
||||||
|
Redirect::to("/protected").into_response()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
use axum::Form;
|
|
||||||
use axum::http::StatusCode;
|
|
||||||
use axum::response::Html;
|
|
||||||
use axum::response::IntoResponse;
|
|
||||||
use axum::response::Redirect;
|
|
||||||
use tera::Context;
|
|
||||||
|
|
||||||
use crate::AuthSession;
|
|
||||||
use crate::UserCredentials;
|
|
||||||
use crate::WebResult;
|
|
||||||
use crate::render_template;
|
|
||||||
|
|
||||||
pub async fn show_login() -> WebResult<Html<String>> {
|
|
||||||
Ok(render_template("users/login.tera.html", &Context::default()).map(Html)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn do_login(
|
|
||||||
mut auth_session: AuthSession,
|
|
||||||
Form(creds): Form<UserCredentials>,
|
|
||||||
) -> impl IntoResponse {
|
|
||||||
let user = match auth_session.authenticate(creds.clone()).await {
|
|
||||||
Ok(Some(user)) => user,
|
|
||||||
Ok(None) => return StatusCode::UNAUTHORIZED.into_response(),
|
|
||||||
Err(_) => return StatusCode::INTERNAL_SERVER_ERROR.into_response(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if auth_session.login(&user).await.is_err() {
|
|
||||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
|
||||||
}
|
|
||||||
|
|
||||||
Redirect::to("/protected").into_response()
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
use axum::Router;
|
|
||||||
use axum::routing::get;
|
|
||||||
use axum::routing::post;
|
|
||||||
use axum_login::AuthUser;
|
|
||||||
use serde::Deserialize;
|
|
||||||
use serde::Serialize;
|
|
||||||
use sqlx::FromRow;
|
|
||||||
|
|
||||||
use crate::AppState;
|
|
||||||
|
|
||||||
mod login;
|
|
||||||
mod register;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
|
||||||
pub struct User {
|
|
||||||
id: i64,
|
|
||||||
username: String,
|
|
||||||
password: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl User {
|
|
||||||
pub fn id(&self) -> i64 {
|
|
||||||
self.id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn username(&self) -> &str {
|
|
||||||
&self.username
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn password(&self) -> &str {
|
|
||||||
&self.password
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AuthUser for User {
|
|
||||||
type Id = i64;
|
|
||||||
|
|
||||||
fn id(&self) -> Self::Id {
|
|
||||||
self.id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn session_auth_hash(&self) -> &[u8] {
|
|
||||||
self.password.as_bytes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn routes() -> Router<AppState> {
|
|
||||||
Router::new()
|
|
||||||
.route("/login", get(login::show_login))
|
|
||||||
.route("/login", post(login::do_login))
|
|
||||||
.route("/register", get(register::show_register))
|
|
||||||
.route("/register", post(register::do_register))
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
use axum::Form;
|
|
||||||
use axum::extract::State;
|
|
||||||
use axum::response::Html;
|
|
||||||
use axum::response::IntoResponse;
|
|
||||||
use axum::response::Redirect;
|
|
||||||
use password_auth::generate_hash;
|
|
||||||
use tera::Context;
|
|
||||||
|
|
||||||
use crate::AppState;
|
|
||||||
use crate::UserCredentials;
|
|
||||||
use crate::WebResult;
|
|
||||||
use crate::render_template;
|
|
||||||
|
|
||||||
pub async fn show_register() -> WebResult<Html<String>> {
|
|
||||||
Ok(render_template("users/register.tera.html", &Context::default()).map(Html)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn do_register(
|
|
||||||
app_state: State<AppState>,
|
|
||||||
Form(creds): Form<UserCredentials>,
|
|
||||||
) -> Result<impl IntoResponse, Html<String>> {
|
|
||||||
sqlx::query("INSERT INTO users (username, password) VALUES (?, ?)")
|
|
||||||
.bind(creds.username)
|
|
||||||
.bind(generate_hash(creds.password))
|
|
||||||
.execute(&app_state.db)
|
|
||||||
.await
|
|
||||||
.map_err(|err| Html(err.to_string()))?;
|
|
||||||
|
|
||||||
Ok(Redirect::to("/login").into_response())
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
|
||||||
{% block head %}
|
|
||||||
<title>{% block title %}{% endblock title%} - Nixie CI</title>
|
|
||||||
{% endblock head%}
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="min-h-screen flex flex-col">
|
|
||||||
<nav class="bg-orange-300 px-2 py-2 inset-shadow-2xs border-b-2 border-orange-900">
|
|
||||||
<div class="mx-auto container flex select-none">
|
|
||||||
<a href="/" class="outline-2 outline-gray-800 bg-gray-700 rounded text-white p-2">
|
|
||||||
<span class="text-green-200">>_</span>
|
|
||||||
Nixie CI ❄️
|
|
||||||
</a>
|
|
||||||
<div class="grow"></div>
|
|
||||||
|
|
||||||
<a href="/login" class="outline-2 outline-r-none hover:outline-emerald-900 outline-emerald-700 p-2 select-none rounded-l bg-emerald-600 text-white">Sign in</a>
|
|
||||||
<a href="/register" class="outline-2 hover:outline-emerald-900 outline-blue-700 p-2 select-none rounded-r bg-blue-600 text-white">Register</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<main class="grow px-2 flex flex-col inset-shadow-sm">
|
|
||||||
<div class="grow flex mx-auto container">
|
|
||||||
{% block content %}{% endblock content %}
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<footer class="bg-zinc-300 px-2 min-h-10 py-4">
|
|
||||||
<div class="mx-auto container font-bold">
|
|
||||||
{% block footer %}
|
|
||||||
© Copyright 2026 by Hemera
|
|
||||||
{% endblock footer %}
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
{% macro text_input(label, name, id="",type="text") %}
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<label for="{{id}}" class="font-bold">{{label}}:</label>
|
|
||||||
<input class="border rounded p-1 bg-gray-50" type="{{type}}" name="{{name}}" id="{{id}}" />
|
|
||||||
</div>
|
|
||||||
{% endmacro text_input %}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{% extends "base.tera.html" %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
Protected Page
|
|
||||||
{% endblock title %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
This is super secret content!
|
|
||||||
{% endblock content %}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
{% extends "base.tera.html" %}
|
|
||||||
{% import "inputs.tera.html" as inputs %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
Login
|
|
||||||
{% endblock title %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="grow sm:flex justify-center items-center">
|
|
||||||
<div class="border-2 border-zinc-300 sm:rounded-2xl lg:rounded-4xl my-2 px-20 pb-14 pt-10 sm:shadow-lg space-y-4">
|
|
||||||
<h1 class="font-bold text-3xl">Login</h1>
|
|
||||||
<form action="/login" method="POST" class="space-y-4">
|
|
||||||
{{ inputs::text_input(label="Username", name="username", id="username") }}
|
|
||||||
{{ inputs::text_input(label="Password", name="password", id="password", type="password") }}
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<button type="submit" class="bg-blue-500 p-2 rounded-lg text-white">
|
|
||||||
Login
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<a href="/register" class="bg-zinc-500 p-2 rounded-lg text-white text-center">
|
|
||||||
Register
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock content %}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue