diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..bec987f
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ postgresql
+ true
+ org.postgresql.Driver
+ jdbc:postgresql://localhost:5432/postgres
+ $ProjectFileDir$
+
+
+
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index d0c97b7..8211efe 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -63,10 +63,22 @@ dependencies = [
]
[[package]]
-name = "async-compression"
-version = "0.4.42"
+name = "argon2"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac"
+checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
+dependencies = [
+ "base64ct",
+ "blake2",
+ "cpufeatures 0.2.17",
+ "password-hash",
+]
+
+[[package]]
+name = "async-compression"
+version = "0.4.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3976abdc8fe7d1133d43d304afd42abdf5bc3e1319d263d223bde07b5efc4be8"
dependencies = [
"compression-codecs",
"compression-core",
@@ -192,25 +204,6 @@ dependencies = [
"http",
]
-[[package]]
-name = "axum-login"
-version = "0.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "964ea6eb764a227baa8c3368e45c94d23b6863cc7b880c6c9e341c143c5a5ff7"
-dependencies = [
- "axum",
- "form_urlencoded",
- "serde",
- "subtle",
- "thiserror",
- "tower-cookies",
- "tower-layer",
- "tower-service",
- "tower-sessions 0.14.0",
- "tracing",
- "urlencoding",
-]
-
[[package]]
name = "axum-macros"
version = "0.5.1"
@@ -228,6 +221,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+[[package]]
+name = "base64"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
+
[[package]]
name = "base64-simd"
version = "0.7.0"
@@ -237,6 +236,12 @@ dependencies = [
"simd-abstraction",
]
+[[package]]
+name = "base64ct"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
+
[[package]]
name = "bitflags"
version = "2.13.1"
@@ -258,6 +263,15 @@ dependencies = [
"wyz",
]
+[[package]]
+name = "blake2"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
+dependencies = [
+ "digest 0.10.7",
+]
+
[[package]]
name = "block-buffer"
version = "0.10.4"
@@ -370,12 +384,6 @@ dependencies = [
"cc",
]
-[[package]]
-name = "cmov"
-version = "0.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
-
[[package]]
name = "combine"
version = "4.6.7"
@@ -403,6 +411,12 @@ version = "0.4.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789"
+[[package]]
+name = "const-oid"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+
[[package]]
name = "const-oid"
version = "0.10.2"
@@ -609,15 +623,6 @@ dependencies = [
"syn 2.0.119",
]
-[[package]]
-name = "ctutils"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e"
-dependencies = [
- "cmov",
-]
-
[[package]]
name = "dashmap"
version = "5.5.3"
@@ -631,6 +636,20 @@ dependencies = [
"parking_lot_core",
]
+[[package]]
+name = "dashmap"
+version = "6.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+ "hashbrown 0.14.5",
+ "lock_api",
+ "once_cell",
+ "parking_lot_core",
+]
+
[[package]]
name = "data-encoding"
version = "2.11.0"
@@ -646,6 +665,17 @@ dependencies = [
"matches",
]
+[[package]]
+name = "der"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
+dependencies = [
+ "const-oid 0.9.6",
+ "pem-rfc7468",
+ "zeroize",
+]
+
[[package]]
name = "deranged"
version = "0.5.8"
@@ -685,7 +715,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer 0.10.4",
+ "const-oid 0.9.6",
"crypto-common 0.1.6",
+ "subtle",
]
[[package]]
@@ -695,9 +727,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
dependencies = [
"block-buffer 0.12.1",
- "const-oid",
+ "const-oid 0.10.2",
"crypto-common 0.2.2",
- "ctutils",
]
[[package]]
@@ -774,12 +805,13 @@ dependencies = [
[[package]]
name = "etcetera"
-version = "0.11.0"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96"
+checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
dependencies = [
"cfg-if",
- "windows-sys 0.61.2",
+ "home",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -825,9 +857,9 @@ dependencies = [
[[package]]
name = "flume"
-version = "0.12.0"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be"
+checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
dependencies = [
"futures-core",
"futures-sink",
@@ -840,6 +872,12 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
[[package]]
name = "foldhash"
version = "0.2.0"
@@ -855,6 +893,16 @@ dependencies = [
"percent-encoding",
]
+[[package]]
+name = "forwarded-header-value"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9"
+dependencies = [
+ "nonempty",
+ "thiserror 1.0.69",
+]
+
[[package]]
name = "fred"
version = "10.1.0"
@@ -986,6 +1034,12 @@ version = "0.3.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109"
+[[package]]
+name = "futures-timer"
+version = "3.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968"
+
[[package]]
name = "futures-util"
version = "0.3.33"
@@ -1033,9 +1087,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
"r-efi 5.3.0",
"wasip2",
+ "wasm-bindgen",
]
[[package]]
@@ -1052,6 +1108,29 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "governor"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9efcab3c1958580ff1f25a2a41be1668f7603d849bb63af523b208a3cc1223b8"
+dependencies = [
+ "cfg-if",
+ "dashmap 6.2.1",
+ "futures-sink",
+ "futures-timer",
+ "futures-util",
+ "getrandom 0.3.4",
+ "hashbrown 0.16.1",
+ "nonzero_ext",
+ "parking_lot",
+ "portable-atomic",
+ "quanta",
+ "rand 0.9.5",
+ "smallvec",
+ "spinning_top",
+ "web-time",
+]
+
[[package]]
name = "h2"
version = "0.4.15"
@@ -1086,6 +1165,17 @@ version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+[[package]]
+name = "hashbrown"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash 0.1.5",
+]
+
[[package]]
name = "hashbrown"
version = "0.16.1"
@@ -1094,7 +1184,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
dependencies = [
"allocator-api2",
"equivalent",
- "foldhash",
+ "foldhash 0.2.0",
]
[[package]]
@@ -1105,11 +1195,11 @@ checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "hashlink"
-version = "0.11.1"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f"
+checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
dependencies = [
- "hashbrown 0.16.1",
+ "hashbrown 0.15.5",
]
[[package]]
@@ -1126,20 +1216,29 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hkdf"
-version = "0.13.0"
+version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018"
+checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
dependencies = [
"hmac",
]
[[package]]
name = "hmac"
-version = "0.13.0"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
- "digest 0.11.3",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "home"
+version = "0.5.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
+dependencies = [
+ "windows-sys 0.61.2",
]
[[package]]
@@ -1231,7 +1330,20 @@ dependencies = [
"tokio",
"tokio-rustls",
"tower-service",
- "webpki-roots",
+ "webpki-roots 1.0.9",
+]
+
+[[package]]
+name = "hyper-timeout"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
+dependencies = [
+ "hyper",
+ "hyper-util",
+ "pin-project-lite",
+ "tokio",
+ "tower-service",
]
[[package]]
@@ -1240,7 +1352,7 @@ version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
dependencies = [
- "base64",
+ "base64 0.22.1",
"bytes",
"futures-channel",
"futures-util",
@@ -1416,7 +1528,7 @@ dependencies = [
"jni-sys",
"log",
"simd_cesu8",
- "thiserror",
+ "thiserror 2.0.19",
"walkdir",
"windows-link",
]
@@ -1479,6 +1591,9 @@ name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+dependencies = [
+ "spin",
+]
[[package]]
name = "libc"
@@ -1487,10 +1602,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
[[package]]
-name = "libsqlite3-sys"
-version = "0.37.0"
+name = "libm"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1"
+checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
+
+[[package]]
+name = "libredox"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d0a00925a9f930d679b6789b721e3a7f9ed110f41b86d2497caa780c3a070a"
+dependencies = [
+ "bitflags",
+ "libc",
+ "plain",
+ "redox_syscall 0.9.2",
+]
+
+[[package]]
+name = "libsqlite3-sys"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
dependencies = [
"pkg-config",
"vcpkg",
@@ -1507,7 +1640,7 @@ dependencies = [
"const-str",
"cssparser",
"cssparser-color",
- "dashmap",
+ "dashmap 5.5.3",
"data-encoding",
"getrandom 0.3.4",
"indexmap",
@@ -1564,7 +1697,7 @@ checksum = "4543dd90f92818d8a73ba91ab02138bb6751689113e79ddd75130f3f7579883d"
dependencies = [
"async-trait",
"serde",
- "thiserror",
+ "thiserror 2.0.19",
]
[[package]]
@@ -1636,12 +1769,12 @@ dependencies = [
[[package]]
name = "md-5"
-version = "0.11.0"
+version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98"
+checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
dependencies = [
"cfg-if",
- "digest 0.11.3",
+ "digest 0.10.7",
]
[[package]]
@@ -1665,10 +1798,10 @@ name = "microtld-web"
version = "0.1.0"
dependencies = [
"anyhow",
- "async-trait",
+ "argon2",
"axum",
"axum-htmx",
- "axum-login",
+ "base64 0.23.1",
"fred",
"inventory",
"lightningcss",
@@ -1678,13 +1811,21 @@ dependencies = [
"reqwest 0.13.4",
"rust-embed",
"serde",
+ "sha2 0.11.0",
"sqlx",
+ "subtle",
+ "time",
"tokio",
"tower",
+ "tower-csrf",
"tower-http 0.7.0",
- "tower-sessions 0.15.0",
+ "tower-sessions",
+ "tower-sessions-sqlx-store",
+ "tower_governor",
"tracing",
"tracing-subscriber",
+ "urlencoding",
+ "uuid",
]
[[package]]
@@ -1740,6 +1881,18 @@ dependencies = [
"minimal-lexical",
]
+[[package]]
+name = "nonempty"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7"
+
+[[package]]
+name = "nonzero_ext"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
+
[[package]]
name = "nu-ansi-term"
version = "0.50.3"
@@ -1749,12 +1902,47 @@ dependencies = [
"windows-sys 0.61.2",
]
+[[package]]
+name = "num-bigint-dig"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7"
+dependencies = [
+ "lazy_static",
+ "libm",
+ "num-integer",
+ "num-iter",
+ "num-traits",
+ "rand 0.8.7",
+ "smallvec",
+ "zeroize",
+]
+
[[package]]
name = "num-conv"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
+[[package]]
+name = "num-integer"
+version = "0.1.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-iter"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b"
+dependencies = [
+ "num-integer",
+ "num-traits",
+]
+
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -1762,6 +1950,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
+ "libm",
]
[[package]]
@@ -1836,11 +2025,22 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall",
+ "redox_syscall 0.5.18",
"smallvec",
"windows-link",
]
+[[package]]
+name = "password-hash"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
+dependencies = [
+ "base64ct",
+ "rand_core 0.6.4",
+ "subtle",
+]
+
[[package]]
name = "pastey"
version = "0.1.1"
@@ -1853,6 +2053,15 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
+[[package]]
+name = "pem-rfc7468"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
+dependencies = [
+ "base64ct",
+]
+
[[package]]
name = "percent-encoding"
version = "2.3.2"
@@ -1940,18 +2149,71 @@ dependencies = [
"siphasher",
]
+[[package]]
+name = "pin-project"
+version = "1.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+[[package]]
+name = "pkcs1"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
+dependencies = [
+ "der",
+ "pkcs8",
+ "spki",
+]
+
+[[package]]
+name = "pkcs8"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+dependencies = [
+ "der",
+ "spki",
+]
+
[[package]]
name = "pkg-config"
version = "0.3.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
+[[package]]
+name = "plain"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
+
+[[package]]
+name = "portable-atomic"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
+
[[package]]
name = "potential_utf"
version = "0.1.5"
@@ -2023,6 +2285,21 @@ dependencies = [
"syn 1.0.109",
]
+[[package]]
+name = "quanta"
+version = "0.12.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7"
+dependencies = [
+ "crossbeam-utils",
+ "libc",
+ "once_cell",
+ "raw-cpuid",
+ "wasi",
+ "web-sys",
+ "winapi",
+]
+
[[package]]
name = "quinn"
version = "0.11.11"
@@ -2037,7 +2314,7 @@ dependencies = [
"rustc-hash",
"rustls",
"socket2 0.6.5",
- "thiserror",
+ "thiserror 2.0.19",
"tokio",
"tracing",
"web-time",
@@ -2060,7 +2337,7 @@ dependencies = [
"rustls",
"rustls-pki-types",
"slab",
- "thiserror",
+ "thiserror 2.0.19",
"tinyvec",
"tracing",
"web-time",
@@ -2192,6 +2469,15 @@ dependencies = [
"rand_core 0.10.1",
]
+[[package]]
+name = "raw-cpuid"
+version = "11.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
+dependencies = [
+ "bitflags",
+]
+
[[package]]
name = "rayon"
version = "1.12.0"
@@ -2235,6 +2521,15 @@ dependencies = [
"bitflags",
]
+[[package]]
+name = "redox_syscall"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1c93da5bb2c5d4e6c0ef7abeead62c89169a0a4882bfb83ac892f2423aea2fe"
+dependencies = [
+ "bitflags",
+]
+
[[package]]
name = "regex-automata"
version = "0.4.16"
@@ -2267,7 +2562,7 @@ version = "0.12.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
dependencies = [
- "base64",
+ "base64 0.22.1",
"bytes",
"futures-core",
"http",
@@ -2296,7 +2591,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "webpki-roots",
+ "webpki-roots 1.0.9",
]
[[package]]
@@ -2305,7 +2600,7 @@ version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
dependencies = [
- "base64",
+ "base64 0.22.1",
"bytes",
"encoding_rs",
"futures-core",
@@ -2380,6 +2675,45 @@ dependencies = [
"syn 1.0.109",
]
+[[package]]
+name = "rmp"
+version = "0.8.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "rmp-serde"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155"
+dependencies = [
+ "rmp",
+ "serde",
+]
+
+[[package]]
+name = "rsa"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d"
+dependencies = [
+ "const-oid 0.9.6",
+ "digest 0.10.7",
+ "num-bigint-dig",
+ "num-integer",
+ "num-traits",
+ "pkcs1",
+ "pkcs8",
+ "rand_core 0.6.4",
+ "signature",
+ "spki",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "rust-embed"
version = "8.12.0"
@@ -2654,13 +2988,13 @@ dependencies = [
[[package]]
name = "sha1"
-version = "0.11.0"
+version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214"
+checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8"
dependencies = [
"cfg-if",
- "cpufeatures 0.3.0",
- "digest 0.11.3",
+ "cpufeatures 0.2.17",
+ "digest 0.10.7",
]
[[package]]
@@ -2710,6 +3044,16 @@ dependencies = [
"libc",
]
+[[package]]
+name = "signature"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
+dependencies = [
+ "digest 0.10.7",
+ "rand_core 0.6.4",
+]
+
[[package]]
name = "simd-abstraction"
version = "0.7.1"
@@ -2792,10 +3136,29 @@ dependencies = [
]
[[package]]
-name = "sqlx"
-version = "0.9.0"
+name = "spinning_top"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "378620ccc25c62c89d8be1c819e76a88d59bdcc3304733330788948e619bfd71"
+checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
+name = "spki"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
+[[package]]
+name = "sqlx"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc"
dependencies = [
"sqlx-core",
"sqlx-macros",
@@ -2806,13 +3169,12 @@ dependencies = [
[[package]]
name = "sqlx-core"
-version = "0.9.0"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb"
+checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
dependencies = [
- "base64",
+ "base64 0.22.1",
"bytes",
- "cfg-if",
"crc",
"crossbeam-queue",
"either",
@@ -2821,28 +3183,33 @@ dependencies = [
"futures-intrusive",
"futures-io",
"futures-util",
- "hashbrown 0.16.1",
+ "hashbrown 0.15.5",
"hashlink",
"indexmap",
"log",
"memchr",
+ "once_cell",
"percent-encoding",
+ "rustls",
"serde",
"serde_json",
"sha2 0.10.9",
"smallvec",
- "thiserror",
+ "thiserror 2.0.19",
+ "time",
"tokio",
"tokio-stream",
"tracing",
"url",
+ "uuid",
+ "webpki-roots 0.26.11",
]
[[package]]
name = "sqlx-macros"
-version = "0.9.0"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd2b84f2bc39a5705ef27ec785a11c934a41bbd4a24941e257927cddc26b60bf"
+checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d"
dependencies = [
"proc-macro2",
"quote",
@@ -2853,15 +3220,15 @@ dependencies = [
[[package]]
name = "sqlx-macros-core"
-version = "0.9.0"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb8d96de5fdc85a5c4ec813432b523ec637e80ba98f046555f75f7908ddac7c3"
+checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b"
dependencies = [
- "cfg-if",
"dotenvy",
"either",
"heck",
"hex",
+ "once_cell",
"proc-macro2",
"quote",
"serde",
@@ -2872,45 +3239,62 @@ dependencies = [
"sqlx-postgres",
"sqlx-sqlite",
"syn 2.0.119",
- "thiserror",
"tokio",
"url",
]
[[package]]
name = "sqlx-mysql"
-version = "0.9.0"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27"
+checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
dependencies = [
+ "atoi",
+ "base64 0.22.1",
"bitflags",
"byteorder",
"bytes",
"crc",
- "digest 0.11.3",
+ "digest 0.10.7",
"dotenvy",
"either",
+ "futures-channel",
"futures-core",
+ "futures-io",
"futures-util",
"generic-array",
+ "hex",
+ "hkdf",
+ "hmac",
+ "itoa",
"log",
+ "md-5",
+ "memchr",
+ "once_cell",
"percent-encoding",
+ "rand 0.8.7",
+ "rsa",
"serde",
"sha1",
- "sha2 0.11.0",
+ "sha2 0.10.9",
+ "smallvec",
"sqlx-core",
- "thiserror",
+ "stringprep",
+ "thiserror 2.0.19",
+ "time",
"tracing",
+ "uuid",
+ "whoami",
]
[[package]]
name = "sqlx-postgres"
-version = "0.9.0"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e"
+checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
dependencies = [
"atoi",
- "base64",
+ "base64 0.22.1",
"bitflags",
"byteorder",
"crc",
@@ -2922,31 +3306,34 @@ dependencies = [
"hex",
"hkdf",
"hmac",
+ "home",
"itoa",
"log",
"md-5",
"memchr",
- "rand 0.10.2",
+ "once_cell",
+ "rand 0.8.7",
"serde",
"serde_json",
- "sha2 0.11.0",
+ "sha2 0.10.9",
"smallvec",
"sqlx-core",
"stringprep",
- "thiserror",
+ "thiserror 2.0.19",
+ "time",
"tracing",
+ "uuid",
"whoami",
]
[[package]]
name = "sqlx-sqlite"
-version = "0.9.0"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c"
+checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
dependencies = [
"atoi",
"flume",
- "form_urlencoded",
"futures-channel",
"futures-core",
"futures-executor",
@@ -2956,10 +3343,13 @@ dependencies = [
"log",
"percent-encoding",
"serde",
+ "serde_urlencoded",
"sqlx-core",
- "thiserror",
+ "thiserror 2.0.19",
+ "time",
"tracing",
"url",
+ "uuid",
]
[[package]]
@@ -3065,13 +3455,33 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
[[package]]
name = "thiserror"
version = "2.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9"
dependencies = [
- "thiserror-impl",
+ "thiserror-impl 2.0.19",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
]
[[package]]
@@ -3212,6 +3622,35 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "tonic"
+version = "0.14.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef"
+dependencies = [
+ "async-trait",
+ "axum",
+ "base64 0.22.1",
+ "bytes",
+ "h2",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-timeout",
+ "hyper-util",
+ "percent-encoding",
+ "pin-project",
+ "socket2 0.6.5",
+ "sync_wrapper",
+ "tokio",
+ "tokio-stream",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
[[package]]
name = "tower"
version = "0.5.3"
@@ -3220,9 +3659,12 @@ checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
dependencies = [
"futures-core",
"futures-util",
+ "indexmap",
"pin-project-lite",
+ "slab",
"sync_wrapper",
"tokio",
+ "tokio-util",
"tower-layer",
"tower-service",
"tracing",
@@ -3244,6 +3686,19 @@ dependencies = [
"tower-service",
]
+[[package]]
+name = "tower-csrf"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d38be628f9ef990a4714803c31a9ecc45b20e4a11401ec9121a8109de541a4aa"
+dependencies = [
+ "http",
+ "thiserror 2.0.19",
+ "tower",
+ "tracing",
+ "url",
+]
+
[[package]]
name = "tower-http"
version = "0.6.11"
@@ -3308,24 +3763,7 @@ dependencies = [
"tower-cookies",
"tower-layer",
"tower-service",
- "tower-sessions-core 0.14.0",
- "tracing",
-]
-
-[[package]]
-name = "tower-sessions"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "518dca34b74a17cadfcee06e616a09d2bd0c3984eff1769e1e76d58df978fc78"
-dependencies = [
- "async-trait",
- "http",
- "time",
- "tokio",
- "tower-cookies",
- "tower-layer",
- "tower-service",
- "tower-sessions-core 0.15.0",
+ "tower-sessions-core",
"tower-sessions-memory-store",
"tracing",
]
@@ -3337,35 +3775,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce8cce604865576b7751b7a6bc3058f754569a60d689328bb74c52b1d87e355b"
dependencies = [
"async-trait",
- "base64",
+ "axum-core",
+ "base64 0.22.1",
"futures",
"http",
"parking_lot",
"rand 0.8.7",
"serde",
"serde_json",
- "thiserror",
- "time",
- "tokio",
- "tracing",
-]
-
-[[package]]
-name = "tower-sessions-core"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "568531ec3dfcf3ffe493de1958ae5662a0284ac5d767476ecdb6a34ff8c6b06c"
-dependencies = [
- "async-trait",
- "axum-core",
- "base64",
- "futures",
- "http",
- "parking_lot",
- "rand 0.9.5",
- "serde",
- "serde_json",
- "thiserror",
+ "thiserror 2.0.19",
"time",
"tokio",
"tracing",
@@ -3373,14 +3791,45 @@ dependencies = [
[[package]]
name = "tower-sessions-memory-store"
-version = "0.15.0"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "713fabf882b6560a831e2bbed6204048b35bdd60e50bbb722902c74f8df33460"
+checksum = "fb05909f2e1420135a831dd5df9f5596d69196d0a64c3499ca474c4bd3d33242"
dependencies = [
"async-trait",
"time",
"tokio",
- "tower-sessions-core 0.15.0",
+ "tower-sessions-core",
+]
+
+[[package]]
+name = "tower-sessions-sqlx-store"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e054622079f57fc1a7d6a6089c9334f963d62028fe21dc9eddd58af9a78480b3"
+dependencies = [
+ "async-trait",
+ "rmp-serde",
+ "sqlx",
+ "thiserror 1.0.69",
+ "time",
+ "tower-sessions-core",
+]
+
+[[package]]
+name = "tower_governor"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44de9b94d849d3c46e06a883d72d408c2de6403367b39df2b1c9d9e7b6736fe6"
+dependencies = [
+ "axum",
+ "forwarded-header-value",
+ "governor",
+ "http",
+ "pin-project",
+ "thiserror 2.0.19",
+ "tonic",
+ "tower",
+ "tracing",
]
[[package]]
@@ -3538,7 +3987,9 @@ version = "1.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239"
dependencies = [
+ "getrandom 0.4.3",
"js-sys",
+ "serde_core",
"wasm-bindgen",
]
@@ -3600,6 +4051,12 @@ dependencies = [
"wit-bindgen",
]
+[[package]]
+name = "wasite"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
+
[[package]]
name = "wasm-bindgen"
version = "0.2.126"
@@ -3684,6 +4141,15 @@ dependencies = [
"rustls-pki-types",
]
+[[package]]
+name = "webpki-roots"
+version = "0.26.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
+dependencies = [
+ "webpki-roots 1.0.9",
+]
+
[[package]]
name = "webpki-roots"
version = "1.0.9"
@@ -3695,9 +4161,29 @@ dependencies = [
[[package]]
name = "whoami"
-version = "2.1.2"
+version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "998767ef88740d1f5b0682a9c53c24431453923962269c2db68ee43788c5a40d"
+checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d"
+dependencies = [
+ "libredox",
+ "wasite",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
@@ -3708,6 +4194,12 @@ dependencies = [
"windows-sys 0.61.2",
]
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
[[package]]
name = "windows-link"
version = "0.2.1"
@@ -3743,13 +4235,22 @@ dependencies = [
"windows-link",
]
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
- "windows-targets",
+ "windows-targets 0.52.6",
]
[[package]]
@@ -3761,34 +4262,67 @@ dependencies = [
"windows-link",
]
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
]
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
@@ -3801,24 +4335,48 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
diff --git a/Cargo.toml b/Cargo.toml
index fbfc0d5..5147b8b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,24 +11,44 @@ edition = "2024"
microtld-web = {path = "web"}
microtld-backend = {path = "backend"}
-tokio = {version = "1.53.1", features = ["full"]}
-lmrc-cloudflare = {version = "0.3.16"}
-anyhow = {version = "1.0.104"}
-serde = {version = "1.0.229", features = ["derive"]}
-derive_more = {version = "2.1.1", default-features = false, features = ["display"]}
+tokio = {version = "1.53", features = ["full"]}
+lmrc-cloudflare = {version = "0.3"}
+anyhow = {version = "1.0"}
+serde = {version = "1.0", features = ["derive"]}
+derive_more = {version = "2.1", default-features = false, features = ["display"]}
-axum = {version = "0.8.9", features = ["macros"]}
-axum-htmx = {version = "0.8.1"}
-axum-login = {version = "0.18.0"}
-tower-sessions = {version = "0.15.0"}
-fred = {version = "10.1.0"}
-tracing = {version = "0.1.44"}
-reqwest = {version = "0.13.4"}
-maud = {version = "0.27.0", features = ["axum"]}
-sqlx = {version = "0.9.0", features = ["runtime-tokio", "mysql"] }
+axum = {version = "0.8", features = ["macros"]}
+axum-htmx = {version = "0.8"}
+fred = {version = "10.1"}
+tracing = {version = "0.1"}
+reqwest = {version = "0.13"}
+maud = {version = "0.27", features = ["axum"]}
async-trait = {version = "0.1.91"}
tracing-subscriber = "0.3.23"
+base64 = "0.23.1"
+sha2 = "0.11"
+subtle = "2.6"
+
+# Auth
+tower-sessions = {version = "0.14"}
+tower-sessions-sqlx-store = { version = "0.15", features = ["postgres"] }
+tower-csrf = "0.1"
+argon2 = "0.5"
+sqlx = { version = "0.8", features = [
+ "runtime-tokio",
+ "tls-rustls-ring-webpki",
+ "postgres",
+ "macros",
+ "migrate",
+ "uuid",
+ "time",
+ "json",
+] }
+time = "0.3"
+uuid = { version = "1", features = ["v4", "serde"] }
+tower_governor = "0.8"
+
# TODO: DIE :)
\ No newline at end of file
diff --git a/assets/img/blinkiesCafe-HY.gif b/assets/img/blinkiesCafe-HY.gif
new file mode 100644
index 0000000..de98db3
Binary files /dev/null and b/assets/img/blinkiesCafe-HY.gif differ
diff --git a/assets/img/blinkiesCafe-eX.gif b/assets/img/blinkiesCafe-eX.gif
new file mode 100644
index 0000000..307c2a6
Binary files /dev/null and b/assets/img/blinkiesCafe-eX.gif differ
diff --git a/assets/img/blinkiesCafe-gn.gif b/assets/img/blinkiesCafe-gn.gif
new file mode 100644
index 0000000..4844531
Binary files /dev/null and b/assets/img/blinkiesCafe-gn.gif differ
diff --git a/web/Cargo.toml b/web/Cargo.toml
index 392ca04..66d229c 100644
--- a/web/Cargo.toml
+++ b/web/Cargo.toml
@@ -11,20 +11,34 @@ anyhow = {workspace = true}
axum = {workspace = true }
axum-htmx = {workspace = true }
-axum-login = {workspace = true }
-tower-sessions = {workspace = true }
fred = {workspace = true }
tracing = {workspace = true }
reqwest = {workspace = true }
maud = {workspace = true }
-sqlx = {workspace = true}
tracing-subscriber = {workspace = true, features = ["env-filter"]}
serde = {workspace = true}
-async-trait = {workspace = true}
lightningcss = "1.0.0-alpha.72"
inventory = "0.3.24"
-tower = "0.5"
tower-http = { version = "0.7.0", features = ["trace", "compression-gzip"] }
-rust-embed = "8"
-mime_guess = "2"
\ No newline at end of file
+base64 = {workspace = true}
+sha2 = {workspace = true}
+subtle = {workspace = true}
+
+#Auth
+tower-sessions = {workspace = true}
+tower-sessions-sqlx-store = {workspace = true}
+tower-csrf = {workspace = true}
+argon2 = {workspace = true}
+sqlx = {workspace = true}
+time = {workspace = true}
+uuid = {workspace = true}
+tower_governor = {workspace = true}
+tower = "0.5.3"
+
+rust-embed = {version = "8.12.0", features = ["debug-embed"]}
+mime_guess = "2"
+urlencoding = "2.1.3"
+
+[profile.release]
+debug = true
\ No newline at end of file
diff --git a/web/assets/img/blinkiesCafe-HY.gif b/web/assets/img/blinkiesCafe-HY.gif
new file mode 100644
index 0000000..de98db3
Binary files /dev/null and b/web/assets/img/blinkiesCafe-HY.gif differ
diff --git a/web/assets/img/blinkiesCafe-eX.gif b/web/assets/img/blinkiesCafe-eX.gif
new file mode 100644
index 0000000..307c2a6
Binary files /dev/null and b/web/assets/img/blinkiesCafe-eX.gif differ
diff --git a/web/assets/img/blinkiesCafe-gn.gif b/web/assets/img/blinkiesCafe-gn.gif
new file mode 100644
index 0000000..4844531
Binary files /dev/null and b/web/assets/img/blinkiesCafe-gn.gif differ
diff --git a/web/assets/img/github-mark.svg b/web/assets/img/github-mark.svg
new file mode 100644
index 0000000..17d1561
--- /dev/null
+++ b/web/assets/img/github-mark.svg
@@ -0,0 +1,3 @@
+
diff --git a/web/build.rs b/web/build.rs
new file mode 100644
index 0000000..d506869
--- /dev/null
+++ b/web/build.rs
@@ -0,0 +1,5 @@
+// generated by `sqlx migrate build-script`
+fn main() {
+ // trigger recompilation when a new migration is added
+ println!("cargo:rerun-if-changed=migrations");
+}
diff --git a/web/migrations/20260820090931_create_users.down.sql b/web/migrations/20260820090931_create_users.down.sql
new file mode 100644
index 0000000..f67aede
--- /dev/null
+++ b/web/migrations/20260820090931_create_users.down.sql
@@ -0,0 +1,2 @@
+-- Add down migration script here
+DROP TABLE users;
\ No newline at end of file
diff --git a/web/migrations/20260820090931_create_users.up.sql b/web/migrations/20260820090931_create_users.up.sql
new file mode 100644
index 0000000..f458e86
--- /dev/null
+++ b/web/migrations/20260820090931_create_users.up.sql
@@ -0,0 +1,11 @@
+-- Add up migration script here
+CREATE TABLE users (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ username TEXT UNIQUE NOT NULL,
+ email TEXT UNIQUE NOT NULL,
+ email_confirmed_at TIMESTAMPTZ,
+ password_hash TEXT NOT NULL,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
+ two_factor_secret TEXT
+);
\ No newline at end of file
diff --git a/web/migrations/20260820102145_user_confirmations.down.sql b/web/migrations/20260820102145_user_confirmations.down.sql
new file mode 100644
index 0000000..64c4249
--- /dev/null
+++ b/web/migrations/20260820102145_user_confirmations.down.sql
@@ -0,0 +1,3 @@
+-- Add down migration script here
+DROP INDEX idx_confirmations_user_id;
+DROP TABLE confirmations;
\ No newline at end of file
diff --git a/web/migrations/20260820102145_user_confirmations.up.sql b/web/migrations/20260820102145_user_confirmations.up.sql
new file mode 100644
index 0000000..73c7bba
--- /dev/null
+++ b/web/migrations/20260820102145_user_confirmations.up.sql
@@ -0,0 +1,12 @@
+-- Add up migration script here
+CREATE TABLE confirmations (
+ identifier BYTEA PRIMARY KEY,
+ verifier_hash BYTEA NOT NULL,
+ user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
+ action_type TEXT NOT NULL,
+ details JSONB,
+ expires_at TIMESTAMPTZ NOT NULL,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+
+CREATE INDEX idx_confirmations_user_id ON confirmations(user_id);
\ No newline at end of file
diff --git a/web/src/web/content/partials/footer.rs b/web/src/web/content/partials/footer.rs
index 2a884f5..c3b38fa 100644
--- a/web/src/web/content/partials/footer.rs
+++ b/web/src/web/content/partials/footer.rs
@@ -1,22 +1,87 @@
+use crate::web::content::style::CssFragment;
use super::*;
+inventory::submit! {
+ CssFragment(r#"
+ footer {
+ display: flex;
+ flex-direction: column;
+ align-items: end;
+ justify-content: center;
+ gap: 1rem;
+ padding: 1rem;
+ background: var(--footer-bg);
+
+ > .upper {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ gap: 1rem;
+ width: 100%;
+
+ > .accessibility {
+ display: flex;
+ .skip-link {
+ position: absolute;
+ top: -10000px;
+ left: -10000px;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
+ }
+
+ .skip-link:focus {
+ position: fixed;
+ top: 10px;
+ left: 10px;
+ width: auto;
+ height: auto;
+ padding: 10px 20px;
+ background-color: #fff;
+ color: #000;
+ border: 2px solid #000;
+ z-index: 9999;
+ }
+ }
+ }
+
+ > .lower {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ gap: 1rem;
+ width: 100%;
+ }
+ }
+ "#
+ )
+}
+
pub fn footer() -> Markup {
html! {
footer {
- div class="accessibility" {
- a href="#main-content" { "Skip to main content" }
- a href="#footer" { "Skip to footer" }
- a href="#navigation" { "Skip to navigation" }
+ div class="upper" {
+ div class="decoration" {
+ img src="/assets/img/blinkiesCafe-eX.gif";
+ img src="/assets/img/blinkiesCafe-gn.gif";
+ img src="/assets/img/blinkiesCafe-HY.gif";
+ }
+ div class="accessibility" {
+ nav aria-label="Skip links" {
+ a.skip-link href="#main-content" tabindex="0" { "Skip to main content" }
+ a.skip-link href="#footer" tabindex="1" { "Skip to footer" }
+ a.skip-link href="#navigation" tabindex="2" { "Skip to navigation" }
+ }
+ }
}
- div class="decoration" {
- img src="/static/img/banner-begay.gif";
- img src="/static/img/banner-docrime.gif";
- img src="/static/img/banner-hate.gif";
- }
- div class="notice" {
- span {
- "Cookies are used to store your session."
- "We do not use them to track you."
+ div class="lower" {
+ div class="notice" {
+ span {
+ "Cookies are used to store your session."
+ "We do not use them to track you."
+ }
}
}
}
diff --git a/web/src/web/content/partials/header.rs b/web/src/web/content/partials/header.rs
index f624de3..bf2e709 100644
--- a/web/src/web/content/partials/header.rs
+++ b/web/src/web/content/partials/header.rs
@@ -1,23 +1,69 @@
+use crate::web::content::style::CssFragment;
use super::*;
+inventory::submit! {
+ CssFragment(r#"
+ .nav-bar {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 1rem;
+ padding: 0.75rem 1.5rem;
+ background: var(--nav-bg);
+
+ > .spacer {
+ flex-grow: 1;
+ }
+
+ > .link {
+ color: var(--nav-link);
+ text-decoration: none;
+
+ border: none;
+ padding: 0;
+ background: none;
+
+ cursor: pointer;
+ font: inherit;
+
+ > img {
+ max-height: 1.5rem;
+ }
+ }
+
+ > .link.__active {
+ font-weight: 600;
+ color: var(--nav-link-active);
+ }
+
+ > .title {
+ color: var(--nav-link);
+
+ font-size: 1.5rem;
+ font-weight: 600;
+
+ color: var(--nav-link);
+ }
+ }
+ "#)
+}
+
pub fn header(is_auth: bool) -> Markup {
html! {
- nav class="navigation" {
- ul {
- li { a href="/" { "Home" } }
- li { a href="/regdomain" { "Register a subdomain" }}
- li { a href="/status" { "Status" }}
- div class="spacer" {}
- @if is_auth {
- li { a href="/logout" class="auth-shown" hx-get="/auth/logoutprompt" hx-target="#popup" hx-swap="innerHTML" { "Logout" }}
- } @else {
- li { a href="/login" class="auth-hidden" hx-get="/auth/loginprompt" hx-target="#popup" hx-swap="innerHTML" { "Login" }}
- li { a href="/register" class="auth-hidden" hx-get="/auth/registerprompt" hx-target="#popup" hx-swap="innerHTML" { "Register" }}
- }
- li { a href="https://github.com/microtld/microtld" {
- img src="/static/img/github-mark.svg";
- }}
+ nav.nav-bar {
+ a.title href="/" { "MicroTLD" }
+
+ a.link.__active href="/" { "Home" }
+ a.link href="/regdomain" { "Register a subdomain" }
+ a.link href="/status" { "Status" }
+ div class="spacer" {}
+ @if is_auth {
+ button.link href="/logout" class="auth-shown" hx-get="/auth/logoutprompt" hx-target="#modal-content" hx-swap="innerHTML" popovertarget="modal" { "Logout" }
+ } @else {
+ button.link href="/login" class="auth-hidden" hx-get="/auth/loginprompt" hx-target="#modal-content" hx-swap="innerHTML" popovertarget="modal" { "Login" }
+ button.link href="/register" class="auth-hidden" hx-get="/auth/registerprompt" hx-target="#modal-content" hx-swap="innerHTML" popovertarget="modal" { "Register" }
}
+ a.link href="https://github.com/microtld/microtld" {img src="/assets/img/github-mark.svg";}
}
}
}
\ No newline at end of file
diff --git a/web/src/web/content/partials/page.rs b/web/src/web/content/partials/page.rs
index ff8b928..e2a4d2d 100644
--- a/web/src/web/content/partials/page.rs
+++ b/web/src/web/content/partials/page.rs
@@ -2,8 +2,97 @@ use maud::DOCTYPE;
use crate::web::content::partials::footer::footer;
use crate::web::content::partials::head::head;
use crate::web::content::partials::header::header;
+use crate::web::content::style::CssFragment;
use super::*;
+inventory::submit! {
+ CssFragment(r#"
+ .main-content {
+ padding: 1rem;
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ }
+
+ /* Style the built-in backdrop provided by the Popover API */
+ #modal::backdrop {
+ background-color: rgba(0, 0, 0, 0.5);
+ }
+
+ #modal {
+ /* Underlay covers entire screen. */
+ top:0px;
+ bottom: 0px;
+ left:0px;
+ right:0px;
+
+ background-color: color-mix(in srgb, var(--bg) 50%, transparent);
+ border: 1px solid var(--border);
+
+ z-index: 1000;
+ color: var(--text);
+
+ justify-content: center;
+ flex-direction:column;
+ align-items:center;
+
+ > #modal-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+
+ > form {
+ display: flex;
+ flex-direction: column;
+
+ > label {
+ padding-top: 1rem;
+ }
+
+ > button {
+ margin-top: 1rem;
+ }
+ }
+ }
+
+ > .modal-close {
+ z-index: 1001;
+ background: rgba(200, 20, 20, 0.8);
+
+ color: var(--text);
+ font-weight: 600;
+
+ border: none;
+
+ margin-top: 1rem;
+
+ cursor: pointer;
+ font: inherit;
+ }
+
+ > .modal-close:hover {
+ background: rgba(200, 20, 20, 0.6);
+
+ transition: background 0.2s ease-in-out;
+ }
+
+ padding: 1rem 3rem;
+ }
+
+ #modal:popover-open {
+ display:flex;
+ }
+ "#
+ )
+}
+
+pub fn show_error(message: &str) -> Markup {
+ html! {
+ h1 { (message) }
+ }
+}
+
pub fn page(page_title: &str, page_slug: &str, is_auth: bool, content: Markup) -> Markup {
html! {
(DOCTYPE)
@@ -11,9 +100,14 @@ pub fn page(page_title: &str, page_slug: &str, is_auth: bool, content: Markup) -
(head(page_title, page_slug))
(header(is_auth))
body {
- div class="main-content" {
+ div class="main-content" tabindex="-1" {
(content)
}
+
+ div popover id="modal" {
+ div id="modal-content" {}
+ button class="modal-close" popovertarget="modal" popovertargetaction="hide" { "Close" }
+ }
}
(footer())
}
diff --git a/web/src/web/content/style/css/base.css b/web/src/web/content/style/css/base.css
index ab4df6a..38f2fc9 100644
--- a/web/src/web/content/style/css/base.css
+++ b/web/src/web/content/style/css/base.css
@@ -1,3 +1,35 @@
-html {
- background-color: #0e0e0e;
+:root {
+ --text: #f3f3f3;
+ --text-muted: #cecece;
+ --bg: #0e0e0e;
+ --border: #5f2f5f;
+ --accent: #c11292;
+ --nav-bg: #1e1e1e;
+ --nav-link: #f3f3f3;
+ --nav-link-active: #ce9ece;
+}
+
+html {
+ height: 100%;
+ width: 100%;
+ scroll-behavior: smooth;
+}
+
+body {
+ font-family: 'Roboto', system-ui, -apple-system, sans-serif;
+ color: var(--text);
+ background: var(--bg);
+ margin: 0;
+ line-height: 1.6;
+
+ background-color: #0e0e0e;
+ font-size: 16px;
+ padding: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
+ height: 100vh;
+ width: 100vw;
+
+ display: flex;
+ flex-direction: column;
}
diff --git a/web/src/web/mod.rs b/web/src/web/mod.rs
index 3d74f9e..8331c9a 100644
--- a/web/src/web/mod.rs
+++ b/web/src/web/mod.rs
@@ -1,3 +1,3 @@
pub(crate) mod content;
pub(crate) mod htmx;
-pub(crate) mod service;
\ No newline at end of file
+pub(crate) mod service;
diff --git a/web/src/web/service/auth/confirmation.rs b/web/src/web/service/auth/confirmation.rs
new file mode 100644
index 0000000..b743558
--- /dev/null
+++ b/web/src/web/service/auth/confirmation.rs
@@ -0,0 +1,106 @@
+use argon2::password_hash::rand_core::{OsRng, RngCore};
+use sha2::{Digest, Sha256};
+use sqlx::{Error, PgPool};
+use sqlx::types::Json;
+use time::{OffsetDateTime, Duration};
+use uuid::Uuid;
+
+
+#[derive(Debug, Clone, sqlx::FromRow)]
+pub struct Confirmation {
+ identifier: [u8; 16],
+
+ #[sqlx(skip)]
+ verifier: Option<[u8; 16]>,
+
+ pub verifier_hash: [u8; 32],
+ pub user_id: Uuid,
+ pub action_type: String,
+ details: Option>,
+ expires_at: OffsetDateTime,
+ created_at: OffsetDateTime,
+}
+
+impl Confirmation {
+ pub fn new(user_id: Uuid, action_type: String, expiry_duration: Duration) -> Confirmation {
+ let mut rng = OsRng::default();
+ let mut identifier = [0; 16];
+ rng.fill_bytes(&mut identifier);
+ let mut verifier = [0; 16];
+ rng.fill_bytes(&mut verifier);
+
+ let mut hasher = Sha256::default();
+ Digest::update(&mut hasher, &verifier);
+ let verifier_hash = hasher.finalize().0;
+
+ let now = OffsetDateTime::now_utc();
+
+ Confirmation {
+ identifier,
+ verifier: Some(verifier),
+ verifier_hash,
+ user_id,
+ action_type,
+ details: None,
+ expires_at: now + expiry_duration,
+ created_at: now,
+ }
+ }
+
+ /// for use in http://localhost:3000/auth/confirm?token=
+ pub fn get_url_token(&self) -> anyhow::Result {
+ Ok(base64::encode([self.identifier.as_ref(), self.verifier.ok_or_else(||anyhow::anyhow!("Cannot construct url token from non-original confirmation"))?.as_ref()].concat()))
+ }
+
+ pub fn decode_url_token(token: &str) -> anyhow::Result<(Vec, Vec)> {
+ let decoded_token = base64::decode(token)?;
+ let (identifier, verifier) = decoded_token.split_at(16);
+ Ok((identifier.to_vec(), verifier.to_vec()))
+ }
+
+ pub async fn submit(self, db: &PgPool) -> anyhow::Result {
+ let result = sqlx::query_as::<_, Confirmation>(
+ r#"
+ INSERT INTO confirmations (identifier, verifier_hash, user_id, action_type, details, expires_at, created_at)
+ VALUES ($1, $2, $3, $4, $5, $6, $7)
+ RETURNING *
+ "#,
+ )
+ .bind(&self.identifier)
+ .bind(&self.verifier_hash)
+ .bind(&self.user_id)
+ .bind(&self.action_type)
+ .bind(&self.details)
+ .bind(&self.expires_at)
+ .bind(&self.created_at)
+ .fetch_optional(db)
+ .await;
+
+ match result {
+ Ok(c) => {
+ match c {
+ None => {
+ Err(anyhow::anyhow!("Confirmation didn't make it to the database."))
+ }
+ Some(c) => {
+ Ok(c)
+ }
+ }
+ },
+ Err(Error::Database(db_err)) if db_err.is_unique_violation() => {
+ Err(anyhow::anyhow!("Confirmation already exists"))
+ }
+ Err(e) => {
+ Err(anyhow::anyhow!("Database error: {}", e))
+ }
+ }
+ }
+
+ pub fn is_expired(&self) -> bool {
+ self.expires_at < OffsetDateTime::now_utc()
+ }
+
+ pub fn is_valid(&self, verifier: &[u8; 16]) -> bool {
+ self.verifier.as_ref().map_or(false, |v| v == verifier)
+ }
+}
\ No newline at end of file
diff --git a/web/src/web/service/auth/email.rs b/web/src/web/service/auth/email.rs
new file mode 100644
index 0000000..858ef07
--- /dev/null
+++ b/web/src/web/service/auth/email.rs
@@ -0,0 +1,20 @@
+pub struct EmailHandler {
+
+}
+
+impl EmailHandler {
+ pub fn send_confirmation_email(&self, email: String, confirmation_token: String) {
+ }
+
+ pub fn send_password_reset_email(&self, email: String, reset_token: String) {
+ }
+
+ pub fn send_attempted_registration_email(&self, email: String) {
+ }
+
+ pub fn send_attempted_login_email(&self, email: String) {
+ }
+
+ pub fn send_password_changed_email(&self, email: String) {
+ }
+}
\ No newline at end of file
diff --git a/web/src/web/service/auth/hash.rs b/web/src/web/service/auth/hash.rs
new file mode 100644
index 0000000..cbabe8f
--- /dev/null
+++ b/web/src/web/service/auth/hash.rs
@@ -0,0 +1,59 @@
+use std::sync::Arc;
+use argon2::{
+ password_hash::{
+ rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString,
+ },
+ Algorithm, Argon2, Params, Version,
+};
+use tokio::task;
+// fn build_hasher() -> Argon2<'static> {
+// let params = Params::new(
+// 64 * 1024, // 64 MiB memory cost
+// 2, // 2 iterations
+// 1, // 1 degree of parallelism
+// None, // default output length (32 bytes)
+// )
+// .expect("valid argon2 params");
+//
+// Argon2::new(Algorithm::Argon2id, Version::V0x13, params)
+// }
+
+fn build_hasher_with_pepper(pepper: &[u8]) -> Argon2<'_> {
+ let params = Params::new(64 * 1024, 2, 1, None).expect("valid argon2 params");
+ Argon2::new_with_secret(pepper, Algorithm::Argon2id, Version::V0x13, params)
+ .expect("valid argon2 secret")
+}
+
+
+
+pub fn hash_password(password: &str, pepper: &[u8]) -> Result {
+ let salt = SaltString::generate(&mut OsRng);
+ let hash = build_hasher_with_pepper(pepper).hash_password(password.as_bytes(), &salt)?;
+ Ok(hash.to_string())
+}
+
+pub fn verify_password(
+ password: &str,
+ stored_hash: &str,
+ pepper: &[u8]
+) -> Result<(), argon2::password_hash::Error> {
+ let parsed = PasswordHash::new(stored_hash)?;
+ build_hasher_with_pepper(pepper).verify_password(password.as_bytes(), &parsed)
+}
+
+pub async fn hash_password_async(password: String, pepper: Arc<[u8]>) -> Result {
+ task::spawn_blocking(move || hash_password(&password, pepper.as_ref()))
+ .await?
+ .map_err(|e| anyhow::anyhow!("Failed to hash password: {}", e))
+}
+
+pub async fn verify_password_async(
+ password: String,
+ stored_hash: String,
+ pepper: Arc<[u8]>
+) -> Result<(), anyhow::Error> {
+ task::spawn_blocking(move || verify_password(&password, &stored_hash, pepper.as_ref()))
+ .await?
+ .map_err(|e|anyhow::anyhow!("Failed to verify password: {}", e))
+}
+
diff --git a/web/src/web/service/auth/mod.rs b/web/src/web/service/auth/mod.rs
index 2cb2bd9..4ae34f7 100644
--- a/web/src/web/service/auth/mod.rs
+++ b/web/src/web/service/auth/mod.rs
@@ -1,32 +1,5 @@
-use std::fmt::{Display, Formatter};
-use axum_login::{AuthnBackend, UserId};
-use crate::web::service::WebService;
-
-mod user;
-
-impl AuthnBackend for WebService {
- type User = user::User;
- type Credentials = user::Credentials;
- type Error = AuthError;
-
- async fn authenticate(&self, creds: Self::Credentials) -> Result