aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1692
-rw-r--r--Cargo.toml12
-rw-r--r--compose.yaml29
-rw-r--r--crates/api-auth/Cargo.toml23
-rw-r--r--crates/api-auth/src/discord/mod.rs30
-rw-r--r--crates/api-auth/src/error.rs25
-rw-r--r--crates/api-auth/src/lib.rs69
-rw-r--r--crates/api-base/src/lib.rs3
-rw-r--r--crates/api-base/src/version.rs45
-rw-r--r--crates/api-core/Cargo.toml (renamed from crates/api-base/Cargo.toml)9
-rw-r--r--crates/api-core/src/auth/mod.rs9
-rw-r--r--crates/api-core/src/auth/provider.rs14
-rw-r--r--crates/api-core/src/health/apidoc.rs (renamed from crates/api-base/src/health/apidoc.rs)0
-rw-r--r--crates/api-core/src/health/mod.rs (renamed from crates/api-base/src/health/mod.rs)0
-rw-r--r--crates/api-core/src/lib.rs7
-rw-r--r--crates/api-core/src/models/mod.rs2
-rw-r--r--crates/api-core/src/models/user.rs1
-rw-r--r--crates/api-core/src/version.rs96
-rw-r--r--crates/sellershut/Cargo.toml14
-rw-r--r--crates/sellershut/src/config/auth/discord.rs91
-rw-r--r--crates/sellershut/src/config/auth/mod.rs44
-rw-r--r--crates/sellershut/src/config/database/mod.rs94
-rw-r--r--crates/sellershut/src/config/mod.rs18
-rw-r--r--crates/sellershut/src/main.rs41
-rw-r--r--crates/sellershut/src/server/api/mod.rs2
-rw-r--r--crates/sellershut/src/server/api/routes/logs/mod.rs54
-rw-r--r--crates/sellershut/src/server/api/routes/mod.rs36
-rw-r--r--crates/sellershut/src/server/mod.rs42
-rw-r--r--crates/sellershut/src/state/mod.rs20
29 files changed, 2450 insertions, 72 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6022e70..8e656c7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -18,6 +18,21 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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",
]
@@ -92,12 +124,38 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -168,6 +226,21 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -208,18 +281,54 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -266,6 +375,27 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -275,6 +405,21 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -293,6 +438,15 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -343,6 +497,17 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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]]
@@ -384,12 +551,55 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -400,6 +610,23 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -415,6 +642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
dependencies = [
"futures-core",
+ "futures-sink",
]
[[package]]
@@ -424,6 +652,40 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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",
]
@@ -452,18 +717,98 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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,12 +1054,28 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -677,10 +1088,25 @@ 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,18 +1115,61 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af"
[[package]]
+name = "libm"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+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"
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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -716,6 +1185,16 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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]]
@@ -774,6 +1269,56 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -786,12 +1331,50 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -804,6 +1387,39 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -819,6 +1435,15 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -838,6 +1463,61 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -847,6 +1527,89 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -876,6 +1639,78 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -910,6 +1745,47 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -931,20 +1807,42 @@ dependencies = [
]
[[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,6 +1927,17 @@ dependencies = [
]
[[package]]
+name = "sha1"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1049,6 +1958,22 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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]]
@@ -1083,12 +2211,29 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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"
@@ -1118,11 +2266,31 @@ dependencies = [
[[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]]
@@ -1187,17 +2355,33 @@ dependencies = [
]
[[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]]
@@ -1212,6 +2396,16 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1267,6 +2461,24 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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",
]
@@ -1353,6 +2565,12 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1365,12 +2583,39 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1380,6 +2625,7 @@ dependencies = [
"idna",
"percent-encoding",
"serde",
+ "serde_derive",
]
[[package]]
@@ -1492,6 +2738,12 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1508,18 +2760,171 @@ dependencies = [
]
[[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]]
@@ -1529,6 +2934,51 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1538,12 +2988,204 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1573,6 +3215,26 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1594,6 +3256,12 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
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<String, AuthError> {
+ todo!()
+ }
+ async fn get_user(&self) -> Result<User, AuthError> {
+ 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<String, AuthError>;
+ async fn get_user(&self) -> Result<User, AuthError>;
+ 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<OauthProvider, Arc<dyn OauthDriver>>,
+}
+
+impl Deref for BasicClient {
+ type Target = C;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl TryFrom<AuthClientConfig> for BasicClient {
+ type Error = AuthClientError;
+
+ fn try_from(value: AuthClientConfig) -> Result<Self, Self::Error> {
+ 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/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<S> FromRequestParts<S> for Version
- where
- S: Send + Sync,
- {
- type Rejection = Response;
-
- async fn from_request_parts(
- parts: &mut Parts,
- _state: &S,
- ) -> Result<Self, Self::Rejection> {
- let params: Path<HashMap<String, String>> =
- 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-base/Cargo.toml b/crates/api-core/Cargo.toml
index e15c19b..ae9f8f7 100644
--- a/crates/api-base/Cargo.toml
+++ b/crates/api-core/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "api-base"
+name = "api-core"
version = "0.0.0"
edition = "2024"
license.workspace = true
@@ -13,5 +13,12 @@ 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-base/src/health/apidoc.rs b/crates/api-core/src/health/apidoc.rs
index 45b8754..45b8754 100644
--- a/crates/api-base/src/health/apidoc.rs
+++ b/crates/api-core/src/health/apidoc.rs
diff --git a/crates/api-base/src/health/mod.rs b/crates/api-core/src/health/mod.rs
index a84dc85..a84dc85 100644
--- a/crates/api-base/src/health/mod.rs
+++ b/crates/api-core/src/health/mod.rs
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<S> FromRequestParts<S> for Version
+ where
+ S: Send + Sync,
+ {
+ type Rejection = Response;
+
+ async fn from_request_parts(
+ parts: &mut Parts,
+ _state: &S,
+ ) -> Result<Self, Self::Rejection> {
+ let params: Path<HashMap<String, String>> =
+ 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<String>,
+
+ /// Discord OAuth client secret.
+ #[arg(long, env = "HUT_DISCORD_CLIENT_SECRET")]
+ pub discord_client_secret: Option<String>,
+
+ /// Redirect URI registered with Discord OAuth.
+ #[arg(long, env = "HUT_DISCORD_REDIRECT_URI")]
+ pub discord_redirect_uri: Option<String>,
+
+ /// Discord token endpoint URI.
+ #[arg(long, env = "HUT_DISCORD_TOKEN_URI")]
+ pub discord_token_uri: Option<String>,
+
+ /// Discord authorization URL.
+ #[arg(long, env = "HUT_DISCORD_AUTH_URL")]
+ pub discord_auth_url: Option<String>,
+}
+
+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<DiscordClientConfig> for AuthClientConfig {
+ type Error = anyhow::Error;
+
+ fn try_from(value: DiscordClientConfig) -> Result<Self> {
+ 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<discord::DiscordClientConfig>,
+}
+
+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<String>,
+
+ /// Database host name or IP address.
+ #[arg(long, env = "HUT_DB_HOST")]
+ #[serde(rename = "host")]
+ pub db_host: Option<String>,
+
+ /// Database port number.
+ #[arg(long, env = "HUT_DB_PORT")]
+ #[serde(rename = "port")]
+ pub db_port: Option<u16>,
+
+ /// Database username.
+ #[arg(long, env = "HUT_DB_USERNAME")]
+ #[serde(rename = "username")]
+ pub db_username: Option<String>,
+
+ /// Database password.
+ #[arg(long, env = "HUT_DB_PASSWORD")]
+ #[serde(rename = "password")]
+ pub db_password: Option<String>,
+
+ /// Database name.
+ #[arg(long, env = "HUT_DB_NAME")]
+ #[serde(rename = "name")]
+ pub db_name: Option<String>,
+}
+
+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<PathBuf>,
- /// 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<Self> {
@@ -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<HashMap<OauthProvider, Arc<dyn OauthDriver>>> {
+ let auth = config.to_owned();
+ let mut collection: HashMap<OauthProvider, Arc<dyn OauthDriver>> = 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<AppState>, Json(body): Json<LogLevel>) -
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<AppState>) -> 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<LogHandle> = 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<dyn HealthDriver>,
pub log_handle: LogHandle,
+ pub auth_clients: HashMap<OauthProvider, Arc<dyn OauthDriver>>,
+}
+
+pub async fn postgres(config: &str, pool_size: u32) -> anyhow::Result<PgPool> {
+ 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)
}