From 19c25138f88acf19c9a959a58de4f58e54026ebc Mon Sep 17 00:00:00 2001 From: rtkay123 Date: Sat, 4 Apr 2026 10:51:18 +0200 Subject: feat: connect to db --- Cargo.lock | 1706 +++++++++++++++++++- Cargo.toml | 12 +- compose.yaml | 29 + crates/api-auth/Cargo.toml | 23 + crates/api-auth/src/discord/mod.rs | 30 + crates/api-auth/src/error.rs | 25 + crates/api-auth/src/lib.rs | 69 + crates/api-base/Cargo.toml | 17 - crates/api-base/src/health/apidoc.rs | 12 - crates/api-base/src/health/mod.rs | 27 - crates/api-base/src/lib.rs | 3 - crates/api-base/src/version.rs | 45 - crates/api-core/Cargo.toml | 24 + crates/api-core/src/auth/mod.rs | 9 + crates/api-core/src/auth/provider.rs | 14 + crates/api-core/src/health/apidoc.rs | 12 + crates/api-core/src/health/mod.rs | 27 + crates/api-core/src/lib.rs | 7 + crates/api-core/src/models/mod.rs | 2 + crates/api-core/src/models/user.rs | 1 + crates/api-core/src/version.rs | 96 ++ crates/sellershut/Cargo.toml | 14 +- crates/sellershut/src/config/auth/discord.rs | 91 ++ crates/sellershut/src/config/auth/mod.rs | 44 + crates/sellershut/src/config/database/mod.rs | 94 ++ crates/sellershut/src/config/mod.rs | 18 +- crates/sellershut/src/main.rs | 41 +- crates/sellershut/src/server/api/mod.rs | 2 +- .../sellershut/src/server/api/routes/logs/mod.rs | 54 + crates/sellershut/src/server/api/routes/mod.rs | 36 + crates/sellershut/src/server/mod.rs | 42 + crates/sellershut/src/state/mod.rs | 20 +- 32 files changed, 2512 insertions(+), 134 deletions(-) create mode 100644 compose.yaml create mode 100644 crates/api-auth/Cargo.toml create mode 100644 crates/api-auth/src/discord/mod.rs create mode 100644 crates/api-auth/src/error.rs create mode 100644 crates/api-auth/src/lib.rs delete mode 100644 crates/api-base/Cargo.toml delete mode 100644 crates/api-base/src/health/apidoc.rs delete mode 100644 crates/api-base/src/health/mod.rs delete mode 100644 crates/api-base/src/lib.rs delete mode 100644 crates/api-base/src/version.rs create mode 100644 crates/api-core/Cargo.toml create mode 100644 crates/api-core/src/auth/mod.rs create mode 100644 crates/api-core/src/auth/provider.rs create mode 100644 crates/api-core/src/health/apidoc.rs create mode 100644 crates/api-core/src/health/mod.rs create mode 100644 crates/api-core/src/lib.rs create mode 100644 crates/api-core/src/models/mod.rs create mode 100644 crates/api-core/src/models/user.rs create mode 100644 crates/api-core/src/version.rs create mode 100644 crates/sellershut/src/config/auth/discord.rs create mode 100644 crates/sellershut/src/config/auth/mod.rs create mode 100644 crates/sellershut/src/config/database/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 6022e70..8e656c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "1.0.0" @@ -53,7 +68,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -64,7 +79,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -74,11 +89,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] -name = "api-base" +name = "api-auth" +version = "0.0.0" +dependencies = [ + "api-core", + "async-trait", + "oauth2", + "secrecy", + "serde", + "sqlx", + "thiserror 2.0.18", + "url", + "utoipa", +] + +[[package]] +name = "api-core" version = "0.0.0" dependencies = [ "axum", "serde", + "tokio", + "tower", "utoipa", ] @@ -91,12 +123,38 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + [[package]] name = "axum" version = "0.8.8" @@ -167,6 +225,21 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -207,18 +280,54 @@ version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +[[package]] +name = "cc" +version = "1.2.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" +dependencies = [ + "find-msvc-tools", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + [[package]] name = "clap" version = "4.6.0" @@ -265,6 +374,27 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[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 = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -274,6 +404,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.5.0" @@ -292,6 +437,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -342,6 +496,17 @@ dependencies = [ "syn", ] +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.5.8" @@ -369,7 +534,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -383,12 +550,55 @@ dependencies = [ "syn", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "flate2" version = "1.1.9" @@ -399,6 +609,23 @@ dependencies = [ "zlib-rs", ] +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + +[[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" @@ -415,6 +642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -423,6 +651,40 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + [[package]] name = "futures-task" version = "0.3.32" @@ -436,7 +698,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", + "futures-io", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "slab", ] @@ -451,18 +716,98 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[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]] name = "http" version = "1.4.0" @@ -526,6 +871,24 @@ dependencies = [ "pin-project-lite", "smallvec", "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", ] [[package]] @@ -534,13 +897,45 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ + "base64", "bytes", + "futures-channel", + "futures-util", "http", "http-body", "hyper", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", + "socket2", "tokio", "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", ] [[package]] @@ -659,11 +1054,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", "serde", "serde_core", ] +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -676,11 +1087,26 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "js-sys" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -689,10 +1115,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] -name = "litemap" -version = "0.8.2" +name = "libm" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +dependencies = [ + "bitflags", + "libc", + "plain", + "redox_syscall 0.7.3", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] [[package]] name = "log" @@ -700,6 +1163,12 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "matchers" version = "0.2.0" @@ -715,6 +1184,16 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.8.0" @@ -755,7 +1234,7 @@ checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -764,7 +1243,23 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys", + "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.5", + "smallvec", + "zeroize", ] [[package]] @@ -773,6 +1268,56 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "oauth2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" +dependencies = [ + "base64", + "chrono", + "getrandom 0.2.17", + "http", + "rand 0.8.5", + "reqwest", + "serde", + "serde_json", + "serde_path_to_error", + "sha2", + "thiserror 1.0.69", + "url", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -785,12 +1330,50 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + [[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -803,6 +1386,39 @@ 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.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "potential_utf" version = "0.1.5" @@ -818,6 +1434,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -837,6 +1462,61 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + [[package]] name = "quote" version = "1.0.45" @@ -846,6 +1526,89 @@ 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 = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.12.3" @@ -875,6 +1638,78 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rust-embed" version = "8.11.0" @@ -909,6 +1744,47 @@ dependencies = [ "walkdir", ] +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -930,21 +1806,43 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "serde", + "zeroize", +] + [[package]] name = "sellershut" version = "0.1.0" dependencies = [ "anyhow", - "api-base", + "api-auth", + "api-core", "axum", "bon", "clap", + "secrecy", "serde", + "serde_json", + "sqlx", "tokio", "toml", + "tower", "tracing", "tracing-appender", "tracing-subscriber", + "url", "utoipa", "utoipa-axum", "utoipa-rapidoc", @@ -1029,10 +1927,10 @@ dependencies = [ ] [[package]] -name = "sha2" -version = "0.10.9" +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -1040,7 +1938,18 @@ dependencies = [ ] [[package]] -name = "sharded-slab" +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" @@ -1048,6 +1957,22 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + [[package]] name = "simd-adler32" version = "0.3.9" @@ -1065,6 +1990,9 @@ name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -1073,7 +2001,207 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +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", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.5", + "hashlink", + "indexmap", + "log", + "memchr", + "once_cell", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror 2.0.18", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-postgres", + "syn", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "bytes", + "crc", + "digest", + "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.5", + "rsa", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.18", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.18", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde_urlencoded", + "sqlx-core", + "thiserror 2.0.18", + "tracing", + "url", ] [[package]] @@ -1082,12 +2210,29 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.117" @@ -1104,6 +2249,9 @@ name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -1116,13 +2264,33 @@ dependencies = [ "syn", ] +[[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.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.18", +] + +[[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", ] [[package]] @@ -1186,18 +2354,34 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" dependencies = [ + "bytes", "libc", "mio", "pin-project-lite", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1211,6 +2395,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "toml" version = "1.1.2+spec-1.1.0" @@ -1266,6 +2460,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -1297,7 +2509,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" dependencies = [ "crossbeam-channel", - "thiserror", + "thiserror 2.0.18", "time", "tracing-subscriber", ] @@ -1352,6 +2564,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typenum" version = "1.19.0" @@ -1364,12 +2582,39 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.8" @@ -1380,6 +2625,7 @@ dependencies = [ "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -1491,6 +2737,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -1507,19 +2759,172 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" 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.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +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.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite", +] + [[package]] name = "winapi-util" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1528,6 +2933,51 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +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 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -1537,12 +2987,204 @@ 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 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "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-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[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_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[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_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[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_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[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_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[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_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winnow" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + [[package]] name = "writeable" version = "0.6.3" @@ -1572,6 +3214,26 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zerofrom" version = "0.1.7" @@ -1593,6 +3255,12 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + [[package]] name = "zerotrie" version = "0.2.4" diff --git a/Cargo.toml b/Cargo.toml index 0326c37..a9a8c27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,20 @@ documentation = "https://books.kanjala.com/sellershut" homepage = "https://git.kanjala.com/sellershut" [workspace.dependencies] -api-base = { path = "./crates/api-base", version = "0.0.0" } +api-core = { path = "./crates/api-core", version = "0.0.0" } async-trait = "0.1.89" axum = "0.8.8" +secrecy = "0.10.3" serde = "1.0.228" +serde_json = "1.0.149" +tokio = "1.51.0" +tower = "0.5.3" thiserror = "2.0.18" tracing = "0.1.44" utoipa = "5.4.0" +url = "2.5.8" + +[workspace.dependencies.sqlx] +version = "0.8.6" +default-features = false +features = ["macros", "migrate", "postgres"] diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..ceaa5fc --- /dev/null +++ b/compose.yaml @@ -0,0 +1,29 @@ +name: sellershut + +services: + db: + image: docker.io/postgres:18.3-alpine + restart: always + shm_size: 128mb + environment: + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} + POSTGRES_DB: sellershut + PGDATA: /data/postgres + ports: + - 5432:5432 + networks: + - sellershut + volumes: + - db:/data/postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 5s + retries: 3 + +volumes: + db: + driver: local + +networks: + sellershut: diff --git a/crates/api-auth/Cargo.toml b/crates/api-auth/Cargo.toml new file mode 100644 index 0000000..7df9411 --- /dev/null +++ b/crates/api-auth/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "api-auth" +version = "0.0.0" +edition = "2024" +license.workspace = true +readme.workspace = true +documentation.workspace = true +homepage.workspace = true + +[dependencies] +api-core = { workspace = true, features = ["auth", "users"] } +async-trait.workspace = true +oauth2 = "5.0.0" +secrecy.workspace = true +serde.workspace = true +sqlx.workspace = true +thiserror.workspace = true +utoipa = { workspace = true, optional = true } +url.workspace = true + +[features] +discord = [] +utoipa = ["dep:utoipa", "serde/derive"] diff --git a/crates/api-auth/src/discord/mod.rs b/crates/api-auth/src/discord/mod.rs new file mode 100644 index 0000000..a39722d --- /dev/null +++ b/crates/api-auth/src/discord/mod.rs @@ -0,0 +1,30 @@ +use api_core::models::user::User; +use async_trait::async_trait; +use sqlx::PgPool; + +use crate::{BasicClient, OauthDriver, error::AuthError}; + +#[derive(Clone, Debug)] +pub struct AuthServiceDiscord { + database: PgPool, + client: BasicClient, +} + +impl AuthServiceDiscord { + pub fn new(database: PgPool, client: BasicClient) -> Self { + Self { database, client } + } +} + +#[async_trait] +impl OauthDriver for AuthServiceDiscord { + async fn get_auth_token(&self) -> Result { + todo!() + } + async fn get_user(&self) -> Result { + todo!() + } + async fn create_session(&self, _user: &User) { + todo!() + } +} diff --git a/crates/api-auth/src/error.rs b/crates/api-auth/src/error.rs new file mode 100644 index 0000000..ec60e51 --- /dev/null +++ b/crates/api-auth/src/error.rs @@ -0,0 +1,25 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum AuthClientError { + #[error("missing field: {0}")] + MissingField(&'static str), + #[error("invalid auth url: {0}")] + InvalidAuthUrl(#[from] oauth2::url::ParseError), + #[error("invalid token url: {0}")] + InvalidTokenUrl(#[source] oauth2::url::ParseError), + #[error("invalid redirect url: {0}")] + InvalidRedirectUrl(#[source] oauth2::url::ParseError), +} + +#[derive(Debug, Error)] +pub enum AuthError { + #[error("missing field: {0}")] + MissingField(&'static str), + #[error("invalid auth url: {0}")] + InvalidAuthUrl(#[from] oauth2::url::ParseError), + #[error("invalid token url: {0}")] + InvalidTokenUrl(#[source] oauth2::url::ParseError), + #[error("invalid redirect url: {0}")] + InvalidRedirectUrl(#[source] oauth2::url::ParseError), +} diff --git a/crates/api-auth/src/lib.rs b/crates/api-auth/src/lib.rs new file mode 100644 index 0000000..284b772 --- /dev/null +++ b/crates/api-auth/src/lib.rs @@ -0,0 +1,69 @@ +#[cfg(feature = "discord")] +pub mod discord; + +mod error; +use api_core::auth::AuthClientConfig; +use api_core::auth::provider::OauthProvider; +use api_core::models::user::User; +pub use error::AuthClientError; + +use oauth2::{EndpointNotSet, EndpointSet}; + +type C = oauth2::basic::BasicClient< + EndpointSet, + EndpointNotSet, + EndpointNotSet, + EndpointNotSet, + EndpointSet, +>; + +#[derive(Clone, Debug)] +pub struct BasicClient(C); + +#[async_trait::async_trait] +pub trait OauthDriver: Send + Sync + std::fmt::Debug { + async fn get_auth_token(&self) -> Result; + async fn get_user(&self) -> Result; + async fn create_session(&self, user: &User); +} + +use oauth2::{AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl}; +use sqlx::PgPool; +use std::collections::HashMap; +use std::sync::Arc; +use std::{convert::TryFrom, ops::Deref}; + +use crate::error::AuthError; + +pub struct OauthService { + clients: HashMap>, +} + +impl Deref for BasicClient { + type Target = C; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl TryFrom for BasicClient { + type Error = AuthClientError; + + fn try_from(value: AuthClientConfig) -> Result { + let auth_url = AuthUrl::new(value.auth_url).map_err(AuthClientError::InvalidAuthUrl)?; + + let token_url = TokenUrl::new(value.token_uri).map_err(AuthClientError::InvalidTokenUrl)?; + + let redirect_url = + RedirectUrl::new(value.redirect_uri).map_err(AuthClientError::InvalidRedirectUrl)?; + + Ok(Self( + oauth2::basic::BasicClient::new(ClientId::new(value.client_id)) + .set_client_secret(ClientSecret::new(value.client_secret)) + .set_auth_uri(auth_url) + .set_token_uri(token_url) + .set_redirect_uri(redirect_url), + )) + } +} diff --git a/crates/api-base/Cargo.toml b/crates/api-base/Cargo.toml deleted file mode 100644 index e15c19b..0000000 --- a/crates/api-base/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "api-base" -version = "0.0.0" -edition = "2024" -license.workspace = true -readme.workspace = true -documentation.workspace = true -homepage.workspace = true - -[dependencies] -axum = { workspace = true, optional = true } -serde.workspace = true -utoipa = { workspace = true, optional = true } - -[features] -axum = ["dep:axum"] -utoipa = ["dep:utoipa", "serde/derive", "axum"] diff --git a/crates/api-base/src/health/apidoc.rs b/crates/api-base/src/health/apidoc.rs deleted file mode 100644 index 45b8754..0000000 --- a/crates/api-base/src/health/apidoc.rs +++ /dev/null @@ -1,12 +0,0 @@ -use utoipa::OpenApi; - -use crate::Version; - -#[derive(OpenApi)] -#[openapi( - tags( - (name = "sellershut", description = "API health check"), - ), - components(schemas(Version)) -)] -pub struct ApiDocBase; diff --git a/crates/api-base/src/health/mod.rs b/crates/api-base/src/health/mod.rs deleted file mode 100644 index a84dc85..0000000 --- a/crates/api-base/src/health/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -#[cfg(feature = "utoipa")] -mod apidoc; - -#[cfg(feature = "utoipa")] -pub use apidoc::*; - -#[derive(Default)] -pub struct BaseService; - -impl HealthDriver for BaseService {} - -pub trait HealthDriver: Send + Sync { - fn health(&self, app: &str, version: &str) -> String { - format!("{app} v{version} is live") - } -} - -#[cfg(test)] -mod tests { - use crate::health::{BaseService, HealthDriver}; - - #[test] - fn health() { - let app = BaseService.health(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); - assert!(app.contains("is live")); - } -} diff --git a/crates/api-base/src/lib.rs b/crates/api-base/src/lib.rs deleted file mode 100644 index 9c632e0..0000000 --- a/crates/api-base/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod health; -mod version; -pub use version::*; diff --git a/crates/api-base/src/version.rs b/crates/api-base/src/version.rs deleted file mode 100644 index 0652c6e..0000000 --- a/crates/api-base/src/version.rs +++ /dev/null @@ -1,45 +0,0 @@ -#[derive(Debug)] -#[cfg_attr( - feature = "utoipa", - derive(utoipa::ToSchema, serde::Deserialize, serde::Serialize), - schema(example = "v0"), - serde(rename_all = "lowercase") -)] -pub enum Version { - V0, -} - -#[cfg(feature = "axum")] -mod request { - use super::*; - use axum::RequestPartsExt; - use axum::extract::{FromRequestParts, Path}; - use axum::http::StatusCode; - use axum::http::request::Parts; - use axum::response::{IntoResponse, Response}; - use std::collections::HashMap; - - impl FromRequestParts for Version - where - S: Send + Sync, - { - type Rejection = Response; - - async fn from_request_parts( - parts: &mut Parts, - _state: &S, - ) -> Result { - let params: Path> = - parts.extract().await.map_err(IntoResponse::into_response)?; - - let version = params - .get("apiVersion") - .ok_or_else(|| (StatusCode::NOT_FOUND, "version param missing").into_response())?; - - match version.as_str() { - "v0" => Ok(Version::V0), - _ => Err((StatusCode::NOT_FOUND, "unknown version").into_response()), - } - } - } -} diff --git a/crates/api-core/Cargo.toml b/crates/api-core/Cargo.toml new file mode 100644 index 0000000..ae9f8f7 --- /dev/null +++ b/crates/api-core/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "api-core" +version = "0.0.0" +edition = "2024" +license.workspace = true +readme.workspace = true +documentation.workspace = true +homepage.workspace = true + +[dependencies] +axum = { workspace = true, optional = true } +serde.workspace = true +utoipa = { workspace = true, optional = true } + +[features] +auth = [] +auth-discord = ["auth"] +axum = ["dep:axum"] +users = [] +utoipa = ["dep:utoipa", "serde/derive", "axum"] + +[dev-dependencies] +tokio = { workspace = true, features = ["macros"] } +tower = { workspace = true, features = ["util"] } diff --git a/crates/api-core/src/auth/mod.rs b/crates/api-core/src/auth/mod.rs new file mode 100644 index 0000000..1045122 --- /dev/null +++ b/crates/api-core/src/auth/mod.rs @@ -0,0 +1,9 @@ +pub mod provider; + +pub struct AuthClientConfig { + pub client_id: String, + pub client_secret: String, + pub redirect_uri: String, + pub token_uri: String, + pub auth_url: String, +} diff --git a/crates/api-core/src/auth/provider.rs b/crates/api-core/src/auth/provider.rs new file mode 100644 index 0000000..803472f --- /dev/null +++ b/crates/api-core/src/auth/provider.rs @@ -0,0 +1,14 @@ +#[non_exhaustive] +/// The oauth provider +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[cfg_attr( + feature = "utoipa", + derive(utoipa::ToSchema, serde::Deserialize, serde::Serialize), + schema(example = "v0"), + serde(rename_all = "camelCase") +)] +pub enum OauthProvider { + /// Discord + #[cfg(feature = "auth-discord")] + Discord, +} diff --git a/crates/api-core/src/health/apidoc.rs b/crates/api-core/src/health/apidoc.rs new file mode 100644 index 0000000..45b8754 --- /dev/null +++ b/crates/api-core/src/health/apidoc.rs @@ -0,0 +1,12 @@ +use utoipa::OpenApi; + +use crate::Version; + +#[derive(OpenApi)] +#[openapi( + tags( + (name = "sellershut", description = "API health check"), + ), + components(schemas(Version)) +)] +pub struct ApiDocBase; diff --git a/crates/api-core/src/health/mod.rs b/crates/api-core/src/health/mod.rs new file mode 100644 index 0000000..a84dc85 --- /dev/null +++ b/crates/api-core/src/health/mod.rs @@ -0,0 +1,27 @@ +#[cfg(feature = "utoipa")] +mod apidoc; + +#[cfg(feature = "utoipa")] +pub use apidoc::*; + +#[derive(Default)] +pub struct BaseService; + +impl HealthDriver for BaseService {} + +pub trait HealthDriver: Send + Sync { + fn health(&self, app: &str, version: &str) -> String { + format!("{app} v{version} is live") + } +} + +#[cfg(test)] +mod tests { + use crate::health::{BaseService, HealthDriver}; + + #[test] + fn health() { + let app = BaseService.health(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); + assert!(app.contains("is live")); + } +} diff --git a/crates/api-core/src/lib.rs b/crates/api-core/src/lib.rs new file mode 100644 index 0000000..8c22b49 --- /dev/null +++ b/crates/api-core/src/lib.rs @@ -0,0 +1,7 @@ +pub mod health; +pub mod models; +mod version; +pub use version::*; + +#[cfg(feature = "auth")] +pub mod auth; diff --git a/crates/api-core/src/models/mod.rs b/crates/api-core/src/models/mod.rs new file mode 100644 index 0000000..0f2db76 --- /dev/null +++ b/crates/api-core/src/models/mod.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "users")] +pub mod user; diff --git a/crates/api-core/src/models/user.rs b/crates/api-core/src/models/user.rs new file mode 100644 index 0000000..e6ad9f0 --- /dev/null +++ b/crates/api-core/src/models/user.rs @@ -0,0 +1 @@ +pub struct User {} diff --git a/crates/api-core/src/version.rs b/crates/api-core/src/version.rs new file mode 100644 index 0000000..5f84f3e --- /dev/null +++ b/crates/api-core/src/version.rs @@ -0,0 +1,96 @@ +#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[cfg_attr( + feature = "utoipa", + derive(utoipa::ToSchema, serde::Deserialize, serde::Serialize), + schema(example = "v0"), + serde(rename_all = "camelCase") +)] +pub enum Version { + V0, +} + +#[cfg(feature = "axum")] +mod request { + use super::*; + use axum::RequestPartsExt; + use axum::extract::{FromRequestParts, Path}; + use axum::http::StatusCode; + use axum::http::request::Parts; + use axum::response::{IntoResponse, Response}; + use std::collections::HashMap; + + impl FromRequestParts for Version + where + S: Send + Sync, + { + type Rejection = Response; + + async fn from_request_parts( + parts: &mut Parts, + _state: &S, + ) -> Result { + let params: Path> = + parts.extract().await.map_err(IntoResponse::into_response)?; + + let version = params + .get("apiVersion") + .ok_or_else(|| (StatusCode::NOT_FOUND, "version param missing").into_response())?; + + match version.as_str() { + "v0" => Ok(Version::V0), + _ => Err((StatusCode::NOT_FOUND, "unknown version").into_response()), + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use axum::{ + Router, + body::Body, + http::{Request, StatusCode}, + routing::get, + }; + use tower::ServiceExt; + + async fn handler(version: Version) -> &'static str { + match version { + Version::V0 => "ok", + } + } + + async fn check(endpoint: &str, expected: StatusCode) { + let app = app(); + let response = app + .oneshot( + Request::builder() + .uri(endpoint) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(expected, response.status()); + } + + fn app() -> Router { + Router::new().route("/{apiVersion}/test", get(handler)) + } + + #[tokio::test] + async fn valid_version_v0() { + check("/v0/test", StatusCode::OK).await + } + + #[tokio::test] + async fn unknown_version() { + check("/v1/test", StatusCode::NOT_FOUND).await + } + + #[tokio::test] + async fn missing_version_param() { + check("/test", StatusCode::NOT_FOUND).await + } +} diff --git a/crates/sellershut/Cargo.toml b/crates/sellershut/Cargo.toml index f7cd15a..14a686c 100644 --- a/crates/sellershut/Cargo.toml +++ b/crates/sellershut/Cargo.toml @@ -10,16 +10,21 @@ description = "A federated marketplace platform" [dependencies] anyhow = "1.0.102" -api-base = { workspace = true, features = ["utoipa"] } +api-auth = { path = "../api-auth", features = ["discord", "utoipa"] } +api-core = { workspace = true, features = ["auth-discord", "utoipa"] } axum = { version = "0.8.8", features = ["macros"] } bon = "3.9.1" clap = { version = "4.6.0", features = ["derive", "env"] } +secrecy = { workspace = true, features = ["serde"] } serde = { workspace = true, features = ["derive"] } -tokio = { version = "1.51.0", features = ["macros", "rt", "rt-multi-thread"] } +serde_json.workspace = true +sqlx = { workspace = true, features = ["migrate"] } +tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread"] } toml = "1.1.2" tracing.workspace = true tracing-appender = "0.2.4" tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } +url = { workspace = true, features = ["serde"] } utoipa = { workspace = true, features = ["axum_extras"] } utoipa-axum = "0.2.0" utoipa-rapidoc = { version = "6.0.0", features = ["axum"], optional = true } @@ -27,7 +32,12 @@ utoipa-redoc = { version = "6.0.0", features = ["axum"], optional = true } utoipa-scalar = { version = "0.3.0", features = ["axum"], optional = true } utoipa-swagger-ui = { version = "9.0.2", features = ["axum"], optional = true } +[dev-dependencies] +tower = { workspace = true, features = ["util"] } + [features] +default = ["auth-discord"] +auth-discord = [] swagger = ["dep:utoipa-swagger-ui"] redoc = ["dep:utoipa-redoc"] rapidoc = ["dep:utoipa-rapidoc"] diff --git a/crates/sellershut/src/config/auth/discord.rs b/crates/sellershut/src/config/auth/discord.rs new file mode 100644 index 0000000..24ad711 --- /dev/null +++ b/crates/sellershut/src/config/auth/discord.rs @@ -0,0 +1,91 @@ +use anyhow::{Context, Result}; +use api_core::auth::AuthClientConfig; +use clap::Parser; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Parser, Deserialize, Serialize, Default, PartialEq, Eq)] +#[serde(default, rename_all = "kebab-case")] +pub struct DiscordClientConfig { + /// Discord OAuth client ID. + #[arg(long, env = "HUT_DISCORD_CLIENT_ID")] + pub discord_client_id: Option, + + /// Discord OAuth client secret. + #[arg(long, env = "HUT_DISCORD_CLIENT_SECRET")] + pub discord_client_secret: Option, + + /// Redirect URI registered with Discord OAuth. + #[arg(long, env = "HUT_DISCORD_REDIRECT_URI")] + pub discord_redirect_uri: Option, + + /// Discord token endpoint URI. + #[arg(long, env = "HUT_DISCORD_TOKEN_URI")] + pub discord_token_uri: Option, + + /// Discord authorization URL. + #[arg(long, env = "HUT_DISCORD_AUTH_URL")] + pub discord_auth_url: Option, +} + +impl DiscordClientConfig { + pub(super) fn merge(self, higher: Self) -> Self { + Self { + discord_client_id: higher.discord_client_id.or(self.discord_client_id), + discord_client_secret: higher.discord_client_secret.or(self.discord_client_secret), + discord_redirect_uri: higher.discord_redirect_uri.or(self.discord_redirect_uri), + discord_token_uri: higher.discord_token_uri.or(self.discord_token_uri), + discord_auth_url: higher.discord_auth_url.or(self.discord_auth_url), + } + } + + pub(super) fn with_defaults(self) -> Self { + Self { + discord_client_id: self.discord_client_id, + discord_client_secret: self.discord_client_secret, + discord_redirect_uri: Some( + self.discord_redirect_uri + .unwrap_or_else(|| "http://localhost:2210/auth/discord/callback".to_string()), + ), + discord_token_uri: Some( + self.discord_token_uri + .unwrap_or_else(|| "https://discord.com/api/oauth2/token".to_string()), + ), + discord_auth_url: Some( + self.discord_auth_url + .unwrap_or_else(|| "https://discord.com/api/oauth2/authorize".to_string()), + ), + } + } + + pub(super) fn defaults() -> Self { + Self { + discord_client_id: None, + discord_client_secret: None, + discord_redirect_uri: Some("http://localhost:2210/auth/discord/callback".to_string()), + discord_token_uri: Some("https://discord.com/api/oauth2/token".to_string()), + discord_auth_url: Some("https://discord.com/api/oauth2/authorize".to_string()), + } + } +} + +impl TryFrom for AuthClientConfig { + type Error = anyhow::Error; + + fn try_from(value: DiscordClientConfig) -> Result { + Ok(Self { + client_id: value + .discord_client_id + .context("missing discord_client_id")?, + client_secret: value + .discord_client_secret + .context("missing discord_client_secret")?, + redirect_uri: value + .discord_redirect_uri + .context("missing discord_redirect_uri")?, + token_uri: value + .discord_token_uri + .context("missing discord_token_uri")?, + auth_url: value.discord_auth_url.context("missing discord_auth_url")?, + }) + } +} diff --git a/crates/sellershut/src/config/auth/mod.rs b/crates/sellershut/src/config/auth/mod.rs new file mode 100644 index 0000000..8fc2d5b --- /dev/null +++ b/crates/sellershut/src/config/auth/mod.rs @@ -0,0 +1,44 @@ +#[cfg(feature = "auth-discord")] +pub mod discord; +use clap::Parser; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Parser, Deserialize, Serialize, Default, PartialEq, Eq)] +#[serde(default, rename_all = "kebab-case")] +pub struct OauthConfig { + /// Discord OAuth configuration. + #[cfg(feature = "auth-discord")] + #[command(flatten)] + pub discord: Option, +} + +impl OauthConfig { + pub(super) fn merge(self, higher: Self) -> Self { + Self { + #[cfg(feature = "auth-discord")] + discord: match (self.discord, higher.discord) { + (Some(lower), Some(higher)) => Some(lower.merge(higher)), + (None, Some(higher)) => Some(higher), + (Some(lower), None) => Some(lower), + (None, None) => None, + }, + } + } + + pub(super) fn with_defaults(self) -> Self { + Self { + #[cfg(feature = "auth-discord")] + discord: self + .discord + .map(|d| d.with_defaults()) + .or_else(|| Some(discord::DiscordClientConfig::defaults())), + } + } + + pub(super) fn defaults() -> Self { + Self { + #[cfg(feature = "auth-discord")] + discord: Some(discord::DiscordClientConfig::defaults()), + } + } +} diff --git a/crates/sellershut/src/config/database/mod.rs b/crates/sellershut/src/config/database/mod.rs new file mode 100644 index 0000000..b04319b --- /dev/null +++ b/crates/sellershut/src/config/database/mod.rs @@ -0,0 +1,94 @@ +use clap::Parser; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Parser, Deserialize, Serialize, Default, PartialEq, Eq)] +#[serde(default)] +pub struct DatabaseConfig { + /// Full database connection URL. Takes precedence over the individual database fields. + #[arg(long, env = "HUT_DB_URL")] + #[serde(rename = "url", skip_serializing_if = "Option::is_none")] + pub db_url: Option, + + /// Database host name or IP address. + #[arg(long, env = "HUT_DB_HOST")] + #[serde(rename = "host")] + pub db_host: Option, + + /// Database port number. + #[arg(long, env = "HUT_DB_PORT")] + #[serde(rename = "port")] + pub db_port: Option, + + /// Database username. + #[arg(long, env = "HUT_DB_USERNAME")] + #[serde(rename = "username")] + pub db_username: Option, + + /// Database password. + #[arg(long, env = "HUT_DB_PASSWORD")] + #[serde(rename = "password")] + pub db_password: Option, + + /// Database name. + #[arg(long, env = "HUT_DB_NAME")] + #[serde(rename = "name")] + pub db_name: Option, +} + +impl DatabaseConfig { + pub(super) fn merge(self, higher: Self) -> Self { + Self { + db_url: higher.db_url.or(self.db_url), + db_host: higher.db_host.or(self.db_host), + db_port: higher.db_port.or(self.db_port), + db_username: higher.db_username.or(self.db_username), + db_password: higher.db_password.or(self.db_password), + db_name: higher.db_name.or(self.db_name), + } + } + + pub(super) fn with_defaults(self) -> Self { + Self { + db_url: self.db_url, + db_host: Some(self.db_host.unwrap_or_else(|| "127.0.0.1".to_string())), + db_port: Some(self.db_port.unwrap_or(5432)), + db_username: Some(self.db_username.unwrap_or_else(|| "postgres".to_string())), + db_password: Some(self.db_password.unwrap_or_else(|| "password".to_string())), + db_name: Some(self.db_name.unwrap_or_else(|| "sellershut".to_string())), + } + } + pub(super) fn defaults() -> Self { + Self { + db_url: None, + db_host: Some("127.0.0.1".to_string()), + db_port: Some(5432), + db_username: Some("postgres".to_string()), + db_password: Some("password".to_string()), + db_name: Some("sellershut".to_string()), + } + } + + pub fn connection_url(&self) -> String { + if let Some(url) = &self.db_url { + return url.clone(); + } + + format!( + "postgres://{}:{}@{}:{}/{}", + self.db_username + .as_deref() + .expect("database username should be set after defaults"), + self.db_password + .as_deref() + .expect("database password should be set after defaults"), + self.db_host + .as_deref() + .expect("database host should be set after defaults"), + self.db_port + .expect("database port should be set after defaults"), + self.db_name + .as_deref() + .expect("database name should be set after defaults"), + ) + } +} diff --git a/crates/sellershut/src/config/mod.rs b/crates/sellershut/src/config/mod.rs index d35ba1e..389b4bc 100644 --- a/crates/sellershut/src/config/mod.rs +++ b/crates/sellershut/src/config/mod.rs @@ -1,4 +1,6 @@ +pub mod auth; pub mod cli; +pub mod database; mod server; use anyhow::Result; @@ -14,9 +16,15 @@ pub struct Config { #[arg(long, env = "HUT_CONFIG")] #[serde(skip)] config: Option, - /// Server configuration. + /// General server configuration. #[command(flatten)] pub server: server::ServerConfig, + /// Auth configuration. + #[command(flatten)] + pub auth: auth::OauthConfig, + /// Database configuration. + #[command(flatten)] + pub database: database::DatabaseConfig, } impl Config { pub fn load(cli: Self) -> Result { @@ -33,6 +41,8 @@ impl Config { Self { config: higher.config.or(self.config), server: self.server.merge(higher.server), + auth: self.auth.merge(higher.auth), + database: self.database.merge(higher.database), } } @@ -40,13 +50,17 @@ impl Config { Self { config: self.config, server: self.server.with_defaults(), + auth: self.auth.with_defaults(), + database: self.database.with_defaults(), } } - fn defaults() -> Self { + pub fn defaults() -> Self { Self { config: None, server: server::ServerConfig::defaults(), + auth: auth::OauthConfig::defaults(), + database: database::DatabaseConfig::defaults(), } } } diff --git a/crates/sellershut/src/main.rs b/crates/sellershut/src/main.rs index cb7be07..fca10e1 100644 --- a/crates/sellershut/src/main.rs +++ b/crates/sellershut/src/main.rs @@ -3,17 +3,26 @@ mod server; mod state; use std::{ + collections::HashMap, net::{Ipv6Addr, SocketAddr}, sync::Arc, }; use anyhow::{Context, Result}; -use api_base::health::BaseService; +use api_auth::{BasicClient, OauthDriver, discord::AuthServiceDiscord}; +use api_core::{ + auth::{AuthClientConfig, provider::OauthProvider}, + health::BaseService, +}; use clap::Parser; -use tokio::net::TcpListener; +use sqlx::PgPool; +use tokio::{net::TcpListener}; use tracing::info; -use crate::{config::cli, state::AppState}; +use crate::{ + config::{auth::OauthConfig, cli}, + state::AppState, +}; #[tokio::main] async fn main() -> Result<()> { @@ -30,10 +39,16 @@ async fn main() -> Result<()> { cfg.server.log_directory.as_ref(), )?; + let database = state::postgres(&cfg.database.connection_url(), 100).await?; + + let auth_clients = build_oauth_client(&cfg.auth, database)?; + let state = AppState::builder() .log_handle(log_handle) .base_service(Arc::new(BaseService)) + .auth_clients(auth_clients) .build(); + let addr = SocketAddr::from(( Ipv6Addr::UNSPECIFIED, cfg.server.port.context("missing port")?, @@ -48,3 +63,23 @@ async fn main() -> Result<()> { Ok(()) } + +fn build_oauth_client( + config: &OauthConfig, + database: PgPool, +) -> Result>> { + let auth = config.to_owned(); + let mut collection: HashMap> = HashMap::new(); + + #[cfg(feature = "auth-discord")] + { + use api_core::auth::provider::OauthProvider; + + let c = AuthClientConfig::try_from(auth.discord.context("missing discord config")?)?; + let client = BasicClient::try_from(c)?; + let auth_service = Arc::new(AuthServiceDiscord::new(database, client)); + collection.insert(OauthProvider::Discord, auth_service); + } + + Ok(collection) +} diff --git a/crates/sellershut/src/server/api/mod.rs b/crates/sellershut/src/server/api/mod.rs index 0fd48c6..c227f59 100644 --- a/crates/sellershut/src/server/api/mod.rs +++ b/crates/sellershut/src/server/api/mod.rs @@ -1,4 +1,4 @@ -use api_base::health::ApiDocBase; +use api_core::health::ApiDocBase; use axum::Router; use utoipa::OpenApi; use utoipa_axum::router::OpenApiRouter; diff --git a/crates/sellershut/src/server/api/routes/logs/mod.rs b/crates/sellershut/src/server/api/routes/logs/mod.rs index 8718d86..9ea0a39 100644 --- a/crates/sellershut/src/server/api/routes/logs/mod.rs +++ b/crates/sellershut/src/server/api/routes/logs/mod.rs @@ -52,3 +52,57 @@ pub async fn reload(State(state): State, Json(body): Json) - StatusCode::BAD_REQUEST } } + +#[cfg(test)] +mod tests { + use axum::{ + Router, + body::Body, + http::{Request, StatusCode, header}, + }; + + use anyhow::Result; + use tower::ServiceExt; + + use crate::server::{self}; + + async fn check( + app: Router, + method: &str, + body: String, + expected_result: StatusCode, + ) -> Result<()> { + let response = app + .oneshot( + Request::builder() + .method(method) + .header(header::CONTENT_TYPE, "application/json") + .uri("/api/logging") + .body(Body::from(body))?, + ) + .await?; + let actual_result = response.status(); + assert_eq!(expected_result, actual_result); + Ok(()) + } + + #[tokio::test] + async fn log_update() -> Result<()> { + let app = server::boostrap::test_app().await; + + let info = serde_json::json!({ + "logLevel": "info", + }); + + check( + app.clone(), + "GET", + info.to_string(), + StatusCode::METHOD_NOT_ALLOWED, + ) + .await?; + + check(app.clone(), "PATCH", info.to_string(), StatusCode::OK).await?; + Ok(()) + } +} diff --git a/crates/sellershut/src/server/api/routes/mod.rs b/crates/sellershut/src/server/api/routes/mod.rs index f343742..1de8e80 100644 --- a/crates/sellershut/src/server/api/routes/mod.rs +++ b/crates/sellershut/src/server/api/routes/mod.rs @@ -36,3 +36,39 @@ pub async fn health(State(state): State) -> impl IntoResponse { .base_service .health(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")) } + +#[cfg(test)] +mod tests { + use axum::{ + Router, + body::Body, + http::{Request, StatusCode}, + }; + + use anyhow::Result; + use tower::ServiceExt; + + use crate::server::{self}; + + async fn check(app: Router, method: &str, expected_result: StatusCode) -> Result<()> { + let response = app + .oneshot( + Request::builder() + .method(method) + .uri("/api/health") + .body(Body::empty())?, + ) + .await?; + let actual_result = response.status(); + assert_eq!(expected_result, actual_result); + Ok(()) + } + + #[tokio::test] + async fn health() -> Result<()> { + let app = server::boostrap::test_app().await; + check(app.clone(), "GET", StatusCode::OK).await?; + check(app.clone(), "HEAD", StatusCode::OK).await?; + Ok(()) + } +} diff --git a/crates/sellershut/src/server/mod.rs b/crates/sellershut/src/server/mod.rs index f669af9..a66eed5 100644 --- a/crates/sellershut/src/server/mod.rs +++ b/crates/sellershut/src/server/mod.rs @@ -1,2 +1,44 @@ pub mod api; pub mod logs; + +#[cfg(test)] +mod boostrap { + use std::{collections::HashMap, sync::{Arc, OnceLock}}; + + use api_core::health::BaseService; + use tracing_subscriber::{EnvFilter, Registry, layer::SubscriberExt, reload}; + + use crate::{ + config::Config, + server::{self, logs::LogHandle}, + state::AppState, + }; + + static TEST_LOG_DATA: OnceLock = OnceLock::new(); + + pub async fn test_app() -> axum::Router { + let log_handle = TEST_LOG_DATA + .get_or_init(|| { + let filter = EnvFilter::new("warn"); + let (layer, handle) = reload::Layer::new(filter); + + let subscriber = Registry::default().with(layer); + + let _ = tracing::subscriber::set_global_default(subscriber); + + handle + }) + .clone(); + let state = Arc::new(BaseService); + let config = Config::defaults(); + let auth_clients = HashMap::default(); + + let state = AppState::builder() + .log_handle(log_handle) + .base_service(state) + .auth_clients(auth_clients) + .build(); + + server::api::router(state, config).await + } +} diff --git a/crates/sellershut/src/state/mod.rs b/crates/sellershut/src/state/mod.rs index 067cc62..821d4eb 100644 --- a/crates/sellershut/src/state/mod.rs +++ b/crates/sellershut/src/state/mod.rs @@ -1,7 +1,9 @@ -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; -use api_base::health::HealthDriver; +use api_auth::OauthDriver; +use api_core::{auth::provider::OauthProvider, health::HealthDriver}; use bon::Builder; +use sqlx::PgPool; use crate::server::logs::LogHandle; @@ -9,4 +11,18 @@ use crate::server::logs::LogHandle; pub struct AppState { pub base_service: Arc, pub log_handle: LogHandle, + pub auth_clients: HashMap>, +} + +pub async fn postgres(config: &str, pool_size: u32) -> anyhow::Result { + let pg = sqlx::postgres::PgPoolOptions::new() + // The default connection limit for a Postgres server is 100 connections, with 3 reserved for superusers. + // + // If you're deploying your application with multiple replicas, then the total + // across all replicas should not exceed the Postgres connection limit + // (max_connections postgresql.conf). + .max_connections(pool_size) + .connect(config) + .await?; + Ok(pg) } -- cgit v1.2.3