From db32adf84058fc71069dddb7b966acb8d6cd251a Mon Sep 17 00:00:00 2001 From: arrelin Date: Tue, 9 Dec 2025 16:31:26 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 983 ++++++++++-------- Cargo.toml | 16 +- src/auth.rs | 90 ++ src/main.rs | 49 +- src/middleware.rs | 23 + .../m20241209_000002_create_users.rs | 57 + src/migration/m20241209_000003_seed_admin.rs | 48 + src/migration/mod.rs | 8 +- src/models/mod.rs | 2 + src/models/user.rs | 18 + src/routes/auth.rs | 75 ++ src/routes/mod.rs | 1 + 12 files changed, 936 insertions(+), 434 deletions(-) create mode 100644 src/auth.rs create mode 100644 src/middleware.rs create mode 100644 src/migration/m20241209_000002_create_users.rs create mode 100644 src/migration/m20241209_000003_seed_admin.rs create mode 100644 src/models/user.rs create mode 100644 src/routes/auth.rs diff --git a/Cargo.lock b/Cargo.lock index 8055c57..ce7e949 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,11 +14,24 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom", + "getrandom 0.2.16", "once_cell", "version_check", ] +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -49,56 +62,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anstream" -version = "0.6.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - -[[package]] -name = "anstyle-parse" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.61.2", -] - [[package]] name = "arbitrary" version = "1.4.2" @@ -108,6 +71,18 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + [[package]] name = "arrayvec" version = "0.7.6" @@ -170,13 +145,13 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axum" -version = "0.8.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ + "async-trait", "axum-core", "bytes", - "form_urlencoded", "futures-util", "http", "http-body", @@ -189,7 +164,8 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "serde_core", + "rustversion", + "serde", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -203,23 +179,51 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.5" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ + "async-trait", "bytes", - "futures-core", + "futures-util", "http", "http-body", "http-body-util", "mime", "pin-project-lite", + "rustversion", "sync_wrapper", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "axum-login" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4012877d9672b7902aa6567960208756f68a09de81e988fa18fe369e92f90471" +dependencies = [ + "async-trait", + "axum", + "form_urlencoded", + "serde", + "subtle", + "thiserror 1.0.69", + "tower-cookies", + "tower-layer", + "tower-service", + "tower-sessions", + "tracing", + "urlencoding", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -234,16 +238,13 @@ checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" [[package]] name = "bigdecimal" -version = "0.4.9" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560f42649de9fa436b73517378a147ec21f6c997a546581df4b4b31677828934" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" dependencies = [ - "autocfg", - "libm", "num-bigint", "num-integer", "num-traits", - "serde", ] [[package]] @@ -267,6 +268,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -375,67 +385,23 @@ dependencies = [ "windows-link", ] -[[package]] -name = "clap" -version = "4.5.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.111", -] - -[[package]] -name = "clap_lex" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" - -[[package]] -name = "colorchoice" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -566,28 +532,6 @@ dependencies = [ "syn 2.0.111", ] -[[package]] -name = "derive_more" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" -dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.111", - "unicode-xid", -] - [[package]] name = "digest" version = "0.10.7" @@ -617,6 +561,18 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "educe" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "either" version = "1.15.0" @@ -626,12 +582,42 @@ dependencies = [ "serde", ] +[[package]] +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "etcetera" version = "0.8.0" @@ -645,31 +631,40 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.4.1" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "family_budget" version = "0.1.0" dependencies = [ + "argon2", + "async-trait", "axum", + "axum-login", "chrono", "dotenvy", "sea-orm", "sea-orm-migration", "serde", "serde_json", + "sqlx", + "thiserror 2.0.17", + "time", "tokio", + "tower-sessions", + "tower-sessions-sqlx-store", "utoipa", "utoipa-swagger-ui", ] +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "find-msvc-tools" version = "0.1.5" @@ -683,7 +678,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", - "libz-rs-sys", "miniz_oxide", ] @@ -704,12 +698,6 @@ 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 = "form_urlencoded" version = "1.2.2" @@ -725,6 +713,20 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.31" @@ -769,6 +771,17 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "futures-sink" version = "0.3.31" @@ -787,8 +800,10 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -819,10 +834,16 @@ dependencies = [ ] [[package]] -name = "glob" -version = "0.3.3" +name = "getrandom" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] [[package]] name = "hashbrown" @@ -830,18 +851,17 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.8", ] [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ + "ahash 0.8.12", "allocator-api2", - "equivalent", - "foldhash", ] [[package]] @@ -852,11 +872,11 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "hashlink" -version = "0.10.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.15.5", + "hashbrown 0.14.5", ] [[package]] @@ -864,12 +884,9 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +dependencies = [ + "unicode-segmentation", +] [[package]] name = "hex" @@ -1130,15 +1147,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "indoc" -version = "2.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" -dependencies = [ - "rustversion", -] - [[package]] name = "inherent" version = "1.0.13" @@ -1150,21 +1158,6 @@ dependencies = [ "syn 2.0.111", ] -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.15" @@ -1215,22 +1208,20 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.30.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" dependencies = [ + "cc", "pkg-config", "vcpkg", ] [[package]] -name = "libz-rs-sys" -version = "0.5.3" +name = "linux-raw-sys" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b484ba8d4f775eeca644c452a56650e544bf7e617f1d170fe7298122ead5222" -dependencies = [ - "zlib-rs", -] +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" @@ -1245,6 +1236,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ "scopeguard", + "serde", ] [[package]] @@ -1264,9 +1256,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.8.4" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "md-5" @@ -1300,6 +1292,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1321,6 +1319,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -1389,26 +1397,20 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - [[package]] name = "ordered-float" -version = "4.6.0" +version = "3.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" dependencies = [ "num-traits", ] [[package]] name = "ouroboros" -version = "0.18.5" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" +checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" dependencies = [ "aliasable", "ouroboros_macro", @@ -1417,23 +1419,17 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.18.5" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" +checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" dependencies = [ - "heck 0.4.1", + "heck", + "proc-macro-error", "proc-macro2", - "proc-macro2-diagnostics", "quote", "syn 2.0.111", ] -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - [[package]] name = "parking_lot" version = "0.12.5" @@ -1457,6 +1453,23 @@ dependencies = [ "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", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1472,15 +1485,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "pgvector" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc58e2d255979a31caa7cabfa7aac654af0354220719ab7a68520ae7a91e8c0b" -dependencies = [ - "serde", -] - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1520,16 +1524,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "pluralizer" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b3eba432a00a1f6c16f39147847a870e94e2e9b992759b503e330efec778cbe" -dependencies = [ - "once_cell", - "regex", -] - [[package]] name = "potential_utf" version = "0.1.4" @@ -1563,6 +1557,30 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -1594,19 +1612,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", - "version_check", - "yansi", -] - [[package]] name = "ptr_meta" version = "0.1.4" @@ -1636,6 +1641,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "radium" version = "0.7.0" @@ -1669,7 +1680,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", ] [[package]] @@ -1727,7 +1738,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -1762,6 +1773,28 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + [[package]] name = "rsa" version = "0.9.9" @@ -1833,45 +1866,45 @@ dependencies = [ ] [[package]] -name = "rustc_version" -version = "0.4.1" +name = "rustix" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "semver", + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.35" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ - "once_cell", "ring", - "rustls-pki-types", "rustls-webpki", - "subtle", - "zeroize", + "sct", ] [[package]] -name = "rustls-pki-types" -version = "1.13.1" +name = "rustls-pemfile" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "zeroize", + "base64 0.21.7", ] [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", - "rustls-pki-types", "untrusted", ] @@ -1902,13 +1935,23 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "sea-bae" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f694a6ab48f14bc063cfadff30ab551d3c7e46d8f81836c51989d548f44a2a25" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro-error2", "proc-macro2", "quote", @@ -1917,61 +1960,39 @@ dependencies = [ [[package]] name = "sea-orm" -version = "2.0.0-rc.20" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "880cc0a64f1ee0320d7d6cd2b9290c27e89750669cfc5b6afdce1654755a2983" +checksum = "ea1fee0cf8528dbe6eda29d5798afc522a63b75e44c5b15721e6e64af9c7cc4b" dependencies = [ "async-stream", "async-trait", "bigdecimal", "chrono", - "derive_more", - "futures-util", - "itertools", + "futures", "log", "ouroboros", - "pgvector", "rust_decimal", "sea-orm-macros", "sea-query", - "sea-query-sqlx", - "sea-schema", + "sea-query-binder", "serde", "serde_json", "sqlx", "strum", - "thiserror", + "thiserror 1.0.69", "time", "tracing", "url", "uuid", ] -[[package]] -name = "sea-orm-cli" -version = "2.0.0-rc.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce69601010a0507a7e465a63bb63064984f7cfd05d04af39df70834e5713aeb6" -dependencies = [ - "chrono", - "clap", - "dotenvy", - "glob", - "indoc", - "regex", - "tracing", - "tracing-subscriber", - "url", -] - [[package]] name = "sea-orm-macros" -version = "2.0.0-rc.20" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aae91cb86cf389da96119df71967ffb1b3caf1687303def77336f8dc9d33e78" +checksum = "8737b566799ed0444f278d13c300c4c6f1a91782f60ff5825a591852d5502030" dependencies = [ - "heck 0.5.0", - "pluralizer", + "heck", "proc-macro2", "quote", "sea-bae", @@ -1981,15 +2002,13 @@ dependencies = [ [[package]] name = "sea-orm-migration" -version = "2.0.0-rc.20" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab8128cb63269debc8a88dbef5577076a5b53f8d0055d2d0939f1533154e2ef" +checksum = "216643749e26ce27ab6c51d3475f2692981d4a902d34455bcd322f412900df5c" dependencies = [ "async-trait", - "clap", - "dotenvy", + "futures", "sea-orm", - "sea-orm-cli", "sea-schema", "tracing", "tracing-subscriber", @@ -1997,12 +2016,13 @@ dependencies = [ [[package]] name = "sea-query" -version = "1.0.0-rc.22" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58df33eded14fba318338034b4bd197973fd7570a9f93ee5f88a27a7731f44f3" +checksum = "b4fd043b8117af233e221f73e3ea8dfbc8e8c3c928017c474296db45c649105c" dependencies = [ "bigdecimal", "chrono", + "educe", "inherent", "ordered-float", "rust_decimal", @@ -2013,24 +2033,10 @@ dependencies = [ ] [[package]] -name = "sea-query-derive" -version = "1.0.0-rc.11" +name = "sea-query-binder" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "365d236217f5daa4f40d3c9998ff3921351b53472da50308e384388162353b3a" -dependencies = [ - "darling", - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.111", - "thiserror", -] - -[[package]] -name = "sea-query-sqlx" -version = "0.8.0-rc.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68873fa1776b4c25a26e7679f8ee22332978c721168ec1b0b32b6583d5a9381d" +checksum = "754965d4aee6145bec25d0898e5c931e6c22859789ce62fd85a42a15ed5a8ce3" dependencies = [ "bigdecimal", "chrono", @@ -2043,16 +2049,28 @@ dependencies = [ ] [[package]] -name = "sea-schema" -version = "0.17.0-rc.16" +name = "sea-query-derive" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "845b7ed3e7a4f4458fe7218931b54e92be0dce01fc3c310d996c7b76d9a37ea5" +checksum = "bae0cbad6ab996955664982739354128c58d16e126114fe88c2a493642502aab" dependencies = [ - "async-trait", + "darling", + "heck", + "proc-macro2", + "quote", + "syn 2.0.111", + "thiserror 2.0.17", +] + +[[package]] +name = "sea-schema" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad52149fc81836ea7424c3425d8f6ed8ad448dd16d2e4f6a3907ba46f3f2fd78" +dependencies = [ + "futures", "sea-query", - "sea-query-sqlx", "sea-schema-derive", - "sqlx", ] [[package]] @@ -2061,7 +2079,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", "syn 2.0.111", @@ -2073,12 +2091,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - [[package]] name = "serde" version = "1.0.228" @@ -2224,9 +2236,6 @@ name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -dependencies = [ - "serde", -] [[package]] name = "socket2" @@ -2258,10 +2267,20 @@ dependencies = [ ] [[package]] -name = "sqlx" -version = "0.8.6" +name = "sqlformat" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" +dependencies = [ + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2272,67 +2291,73 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.6" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" dependencies = [ - "base64", + "ahash 0.8.12", + "atoi", "bigdecimal", + "byteorder", "bytes", "chrono", "crc", "crossbeam-queue", "either", "event-listener", + "futures-channel", "futures-core", "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.5", "hashlink", + "hex", "indexmap", "log", "memchr", "once_cell", + "paste", "percent-encoding", "rust_decimal", "rustls", + "rustls-pemfile", "serde", "serde_json", "sha2", "smallvec", - "thiserror", + "sqlformat", + "thiserror 1.0.69", "time", "tokio", "tokio-stream", "tracing", "url", "uuid", - "webpki-roots 0.26.11", + "webpki-roots", ] [[package]] name = "sqlx-macros" -version = "0.8.6" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.111", + "syn 1.0.109", ] [[package]] name = "sqlx-macros-core" -version = "0.8.6" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" dependencies = [ "dotenvy", "either", - "heck 0.5.0", + "heck", "hex", "once_cell", "proc-macro2", @@ -2344,19 +2369,20 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.111", + "syn 1.0.109", + "tempfile", "tokio", "url", ] [[package]] name = "sqlx-mysql" -version = "0.8.6" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" dependencies = [ "atoi", - "base64", + "base64 0.21.7", "bigdecimal", "bitflags", "byteorder", @@ -2389,7 +2415,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 1.0.69", "time", "tracing", "uuid", @@ -2398,12 +2424,12 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.8.6" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" dependencies = [ "atoi", - "base64", + "base64 0.21.7", "bigdecimal", "bitflags", "byteorder", @@ -2413,6 +2439,7 @@ dependencies = [ "etcetera", "futures-channel", "futures-core", + "futures-io", "futures-util", "hex", "hkdf", @@ -2432,7 +2459,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 1.0.69", "time", "tracing", "uuid", @@ -2441,9 +2468,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.6" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" dependencies = [ "atoi", "chrono", @@ -2457,12 +2484,11 @@ dependencies = [ "log", "percent-encoding", "serde", - "serde_urlencoded", "sqlx-core", - "thiserror", "time", "tracing", "url", + "urlencoding", "uuid", ] @@ -2489,17 +2515,11 @@ dependencies = [ "unicode-properties", ] -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - [[package]] name = "strum" -version = "0.27.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" [[package]] name = "subtle" @@ -2552,13 +2572,46 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[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.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.17", +] + +[[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.111", ] [[package]] @@ -2722,6 +2775,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-cookies" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fd0118512cf0b3768f7fcccf0bef1ae41d68f2b45edc1e77432b36c97c56c6d" +dependencies = [ + "async-trait", + "axum-core", + "cookie", + "futures-util", + "http", + "parking_lot", + "pin-project-lite", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -2734,6 +2804,71 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" +[[package]] +name = "tower-sessions" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50571505955aaa8b73f2f40489953d92b4d7ff9eb9b2a8b4e11fee0dcdb2760e" +dependencies = [ + "async-trait", + "http", + "time", + "tokio", + "tower-cookies", + "tower-layer", + "tower-service", + "tower-sessions-core", + "tower-sessions-memory-store", + "tracing", +] + +[[package]] +name = "tower-sessions-core" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6293bf33f1977d5ef422c2e02f909eb2c3d7bf921d93557c40d4f1b130b84aa4" +dependencies = [ + "async-trait", + "axum-core", + "base64 0.22.1", + "futures", + "http", + "parking_lot", + "rand", + "serde", + "serde_json", + "thiserror 1.0.69", + "time", + "tokio", + "tracing", +] + +[[package]] +name = "tower-sessions-memory-store" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec5f88eeef0f036e6900217034efbce733cbdf0528a85204eaaed90bc34c354" +dependencies = [ + "async-trait", + "time", + "tokio", + "tower-sessions-core", +] + +[[package]] +name = "tower-sessions-sqlx-store" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9442116d8ec67af57e2213f5b4007b6bb55d74c19eae429cd6525b7527844807" +dependencies = [ + "async-trait", + "rmp-serde", + "sqlx", + "thiserror 1.0.69", + "time", + "tower-sessions-core", +] + [[package]] name = "tracing" version = "0.1.43" @@ -2821,10 +2956,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] -name = "unicode-xid" -version = "0.2.6" +name = "unicode-segmentation" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "untrusted" @@ -2844,18 +2985,18 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - [[package]] name = "utoipa" version = "5.4.0" @@ -2882,12 +3023,12 @@ dependencies = [ [[package]] name = "utoipa-swagger-ui" -version = "9.0.2" +version = "8.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d047458f1b5b65237c2f6dc6db136945667f40a7668627b3490b9513a3d43a55" +checksum = "db4b5ac679cc6dfc5ea3f2823b0291c777750ffd5e13b21137e0f7ac0e8f9617" dependencies = [ "axum", - "base64", + "base64 0.22.1", "mime_guess", "regex", "rust-embed", @@ -2937,6 +3078,15 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasite" version = "0.1.0" @@ -2990,21 +3140,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.11" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.4", -] - -[[package]] -name = "webpki-roots" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" -dependencies = [ - "rustls-pki-types", -] +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "whoami" @@ -3315,6 +3453,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + [[package]] name = "writeable" version = "0.6.2" @@ -3330,12 +3474,6 @@ dependencies = [ "tap", ] -[[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" - [[package]] name = "yoke" version = "0.8.1" @@ -3441,24 +3579,21 @@ dependencies = [ [[package]] name = "zip" -version = "3.0.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308" +checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" dependencies = [ "arbitrary", "crc32fast", + "crossbeam-utils", + "displaydoc", "flate2", "indexmap", "memchr", + "thiserror 2.0.17", "zopfli", ] -[[package]] -name = "zlib-rs" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36134c44663532e6519d7a6dfdbbe06f6f8192bde8ae9ed076e9b213f0e31df7" - [[package]] name = "zopfli" version = "0.8.3" diff --git a/Cargo.toml b/Cargo.toml index a2a0417..e4ee190 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,12 +5,20 @@ edition = "2024" [dependencies] tokio = { version = "1.48.0", features = ["full"] } -sea-orm = { version = "2.0.0-rc.20", features = ["sqlx-postgres", "runtime-tokio-rustls", "macros"] } -sea-orm-migration = "2.0.0-rc.20" +sea-orm = { version = "1.0", features = ["sqlx-postgres", "runtime-tokio-rustls", "macros"] } +sea-orm-migration = { version = "1.0", default-features = false, features = ["sqlx-postgres", "runtime-tokio-rustls"] } dotenvy = "0.15.7" -axum = { version = "0.8.7", features = ["json"] } +axum = { version = "0.7", features = ["json"] } chrono = { version = "0.4.42", features = ["serde"] } serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0" utoipa = { version = "5.4.0", features = ["axum_extras", "chrono", "decimal_float"] } -utoipa-swagger-ui = { version = "9.0.2", features = ["axum"] } \ No newline at end of file +utoipa-swagger-ui = { version = "8.0", features = ["axum"] } +axum-login = "0.15" +tower-sessions = "0.12" +tower-sessions-sqlx-store = { version = "0.12", features = ["postgres"] } +sqlx = { version = "0.7", features = ["postgres", "runtime-tokio-rustls"] } +argon2 = "0.5" +async-trait = "0.1" +thiserror = "2.0" +time = "0.3" \ No newline at end of file diff --git a/src/auth.rs b/src/auth.rs new file mode 100644 index 0000000..03667d3 --- /dev/null +++ b/src/auth.rs @@ -0,0 +1,90 @@ +use axum_login::{AuthUser, AuthnBackend, UserId}; +use sea_orm::{DatabaseConnection, EntityTrait, ColumnTrait, QueryFilter}; +use argon2::{ + password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Argon2, +}; + +use crate::models::{user, User}; + +#[derive(Debug, Clone)] +pub struct AuthBackend { + pub db: DatabaseConnection, +} + +impl AuthUser for user::Model { + type Id = i32; + + fn id(&self) -> Self::Id { + self.id + } + + fn session_auth_hash(&self) -> &[u8] { + self.password_hash.as_bytes() + } +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Database error: {0}")] + Database(#[from] sea_orm::DbErr), + #[error("Password hashing error")] + PasswordHash, + #[error("Invalid credentials")] + InvalidCredentials, +} + +#[derive(Debug, Clone)] +pub struct Credentials { + pub username: String, + pub password: String, +} + +#[async_trait::async_trait] +impl AuthnBackend for AuthBackend { + type User = user::Model; + type Credentials = Credentials; + type Error = Error; + + async fn authenticate( + &self, + creds: Self::Credentials, + ) -> Result, Self::Error> { + let user = User::find() + .filter(user::Column::Username.eq(&creds.username)) + .one(&self.db) + .await?; + + if let Some(user) = user { + let parsed_hash = PasswordHash::new(&user.password_hash) + .map_err(|_| Error::PasswordHash)?; + + let is_valid = Argon2::default() + .verify_password(creds.password.as_bytes(), &parsed_hash) + .is_ok(); + + if is_valid { + Ok(Some(user)) + } else { + Err(Error::InvalidCredentials) + } + } else { + Err(Error::InvalidCredentials) + } + } + + async fn get_user(&self, user_id: &UserId) -> Result, Self::Error> { + let user = User::find_by_id(*user_id).one(&self.db).await?; + Ok(user) + } +} + +pub fn hash_password(password: &str) -> Result { + let salt = SaltString::generate(&mut OsRng); + let argon2 = Argon2::default(); + + argon2 + .hash_password(password.as_bytes(), &salt) + .map(|hash| hash.to_string()) + .map_err(|_| Error::PasswordHash) +} diff --git a/src/main.rs b/src/main.rs index 1d8647a..d5a768b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,29 @@ use axum::{ routing::{get, post, put, delete}, - Router, + Router, middleware as axum_middleware, }; use sea_orm::{Database, DatabaseConnection, DbErr}; use sea_orm_migration::prelude::*; use std::net::SocketAddr; use utoipa::OpenApi; use utoipa_swagger_ui::SwaggerUi; +use tower_sessions::{Expiry, SessionManagerLayer}; +use tower_sessions_sqlx_store::PostgresStore; +use axum_login::AuthManagerLayerBuilder; +use time::Duration; mod models; mod services; mod migration; mod routes; +mod auth; +mod middleware; #[derive(OpenApi)] #[openapi( paths( + routes::auth::login, + routes::auth::logout, routes::family::create_family, routes::family::get_family, routes::family::get_all_families, @@ -38,6 +46,8 @@ mod routes; models::family::Model, models::category::Model, models::expense::Model, + routes::auth::LoginRequest, + routes::auth::LoginResponse, routes::family::CreateFamilyRequest, routes::family::UpdateFamilyRequest, routes::category::CreateCategoryRequest, @@ -48,6 +58,7 @@ mod routes; ) ), tags( + (name = "auth", description = "Authentication endpoints"), (name = "families", description = "Family management endpoints"), (name = "categories", description = "Category management endpoints"), (name = "expenses", description = "Expense management endpoints") @@ -79,8 +90,34 @@ async fn main() -> Result<(), DbErr> { crate::migration::Migrator::up(&db, None).await?; println!("Migrations completed!"); - let api_routes = Router::new() + let database_url = std::env::var("DATABASE_URL") + .expect("DATABASE_URL must be set in .env file"); + + let session_store = PostgresStore::new( + sqlx::PgPool::connect(&database_url) + .await + .expect("Failed to connect to database for sessions"), + ); + session_store + .migrate() + .await + .expect("Failed to run session store migrations"); + + let session_layer = SessionManagerLayer::new(session_store) + .with_secure(false) + .with_expiry(Expiry::OnInactivity(Duration::days(1))); + + let backend = auth::AuthBackend { db: db.clone() }; + let auth_layer = AuthManagerLayerBuilder::new(backend, session_layer).build(); + + let protected_routes = Router::new() .route("/families", post(routes::family::create_family)) + .route_layer(axum_middleware::from_fn(middleware::require_admin)); + + let api_routes = Router::new() + .route("/login", post(routes::auth::login)) + .route("/logout", post(routes::auth::logout)) + .merge(protected_routes) .route("/families", get(routes::family::get_all_families)) .route("/families/{id}", get(routes::family::get_family)) .route("/families/{id}", put(routes::family::update_family)) @@ -96,11 +133,13 @@ async fn main() -> Result<(), DbErr> { .route("/families/{family_id}/categories/{category_id}/expenses/{expense_id}", put(routes::expense::update_expense)) .route("/families/{family_id}/categories/{category_id}/expenses/{expense_id}", delete(routes::expense::delete_expense)) .route("/families/{family_id}/categories/{category_id}/remaining", get(routes::expense::get_remaining_limit)) + .layer(auth_layer) .with_state(db); - let app = api_routes - .merge(SwaggerUi::new("/swagger-ui") - .url("/api-docs/openapi.json", ApiDoc::openapi())); + let swagger_ui = SwaggerUi::new("/swagger-ui") + .url("/api-docs/openapi.json", ApiDoc::openapi()); + + let app = api_routes.merge(swagger_ui); let addr = SocketAddr::from(([0, 0, 0, 0], 8080)); println!("Server running on http://{}", addr); diff --git a/src/middleware.rs b/src/middleware.rs new file mode 100644 index 0000000..f5d4ea0 --- /dev/null +++ b/src/middleware.rs @@ -0,0 +1,23 @@ +use axum::{ + extract::Request, + http::StatusCode, + middleware::Next, + response::Response, +}; +use axum_login::AuthSession; + +use crate::auth::AuthBackend; + +pub async fn require_admin( + auth_session: AuthSession, + request: Request, + next: Next, +) -> Result { + let user = auth_session.user.ok_or(StatusCode::UNAUTHORIZED)?; + + if !user.is_admin { + return Err(StatusCode::FORBIDDEN); + } + + Ok(next.run(request).await) +} diff --git a/src/migration/m20241209_000002_create_users.rs b/src/migration/m20241209_000002_create_users.rs new file mode 100644 index 0000000..ebac8d9 --- /dev/null +++ b/src/migration/m20241209_000002_create_users.rs @@ -0,0 +1,57 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(User::Table) + .if_not_exists() + .col( + ColumnDef::new(User::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col( + ColumnDef::new(User::Username) + .string() + .not_null() + .unique_key(), + ) + .col(ColumnDef::new(User::PasswordHash).string().not_null()) + .col( + ColumnDef::new(User::IsAdmin) + .boolean() + .not_null() + .default(false), + ) + .to_owned(), + ) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(User::Table).to_owned()) + .await?; + + Ok(()) + } +} + +#[derive(DeriveIden)] +enum User { + Table, + Id, + Username, + PasswordHash, + IsAdmin, +} diff --git a/src/migration/m20241209_000003_seed_admin.rs b/src/migration/m20241209_000003_seed_admin.rs new file mode 100644 index 0000000..28dc524 --- /dev/null +++ b/src/migration/m20241209_000003_seed_admin.rs @@ -0,0 +1,48 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + use argon2::{ + password_hash::{rand_core::OsRng, PasswordHasher, SaltString}, + Argon2, + }; + + let salt = SaltString::generate(&mut OsRng); + let argon2 = Argon2::default(); + let password_hash = argon2 + .hash_password("2123".as_bytes(), &salt) + .map_err(|_| DbErr::Migration("Failed to hash password".to_string()))? + .to_string(); + + let insert = Query::insert() + .into_table(User::Table) + .columns([User::Username, User::PasswordHash, User::IsAdmin]) + .values_panic(["admin".into(), password_hash.into(), true.into()]) + .to_owned(); + + manager.exec_stmt(insert).await?; + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let delete = Query::delete() + .from_table(User::Table) + .and_where(Expr::col(User::Username).eq("admin")) + .to_owned(); + + manager.exec_stmt(delete).await?; + Ok(()) + } +} + +#[derive(DeriveIden)] +enum User { + Table, + Username, + PasswordHash, + IsAdmin, +} diff --git a/src/migration/mod.rs b/src/migration/mod.rs index a435222..60a373c 100644 --- a/src/migration/mod.rs +++ b/src/migration/mod.rs @@ -1,12 +1,18 @@ pub use sea_orm_migration::prelude::*; mod m20241209_000001_create_tables; +mod m20241209_000002_create_users; +mod m20241209_000003_seed_admin; pub struct Migrator; #[async_trait::async_trait] impl MigratorTrait for Migrator { fn migrations() -> Vec> { - vec![Box::new(m20241209_000001_create_tables::Migration)] + vec![ + Box::new(m20241209_000001_create_tables::Migration), + Box::new(m20241209_000002_create_users::Migration), + Box::new(m20241209_000003_seed_admin::Migration), + ] } } diff --git a/src/models/mod.rs b/src/models/mod.rs index 3914efe..9767ee1 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,7 +1,9 @@ pub mod family; pub mod category; pub mod expense; +pub mod user; pub use family::Entity as Family; pub use category::Entity as Category; pub use expense::Entity as Expense; +pub use user::Entity as User; diff --git a/src/models/user.rs b/src/models/user.rs new file mode 100644 index 0000000..2e5914c --- /dev/null +++ b/src/models/user.rs @@ -0,0 +1,18 @@ +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "user")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(unique)] + pub username: String, + pub password_hash: String, + pub is_admin: bool, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/routes/auth.rs b/src/routes/auth.rs new file mode 100644 index 0000000..ff74dec --- /dev/null +++ b/src/routes/auth.rs @@ -0,0 +1,75 @@ +use axum::{ + extract::State, + http::StatusCode, + Json, +}; +use axum_login::AuthSession; +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + +use crate::auth::{AuthBackend, Credentials}; + +#[derive(Debug, Deserialize, ToSchema)] +pub struct LoginRequest { + pub username: String, + pub password: String, +} + +#[derive(Debug, Serialize, ToSchema)] +pub struct LoginResponse { + pub success: bool, + pub is_admin: bool, +} + +#[utoipa::path( + post, + path = "/login", + tag = "auth", + request_body = LoginRequest, + responses( + (status = 200, description = "Login successful", body = LoginResponse), + (status = 401, description = "Invalid credentials") + ) +)] +pub async fn login( + mut auth_session: AuthSession, + Json(payload): Json, +) -> Result, StatusCode> { + let user = auth_session + .authenticate(Credentials { + username: payload.username, + password: payload.password, + }) + .await + .map_err(|_| StatusCode::UNAUTHORIZED)? + .ok_or(StatusCode::UNAUTHORIZED)?; + + auth_session + .login(&user) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + Ok(Json(LoginResponse { + success: true, + is_admin: user.is_admin, + })) +} + +#[utoipa::path( + post, + path = "/logout", + tag = "auth", + responses( + (status = 200, description = "Logout successful") + ) +)] +pub async fn logout( + mut auth_session: AuthSession, +) -> Result { + auth_session + .logout() + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + Ok(StatusCode::OK) +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 845a752..892ea92 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,3 +1,4 @@ pub mod family; pub mod category; pub mod expense; +pub mod auth;