diff options
| author | rtkay123 <dev@kanjala.com> | 2026-02-01 15:20:13 +0200 |
|---|---|---|
| committer | rtkay123 <dev@kanjala.com> | 2026-02-01 15:20:13 +0200 |
| commit | 78f61ccdf66572d7432b5b627994038479103653 (patch) | |
| tree | 3b752267d04d041c35efe5a9f5c732988179f020 | |
| parent | ce65d9eeafcd1f9d5c3adef1c9b1af6258ee711a (diff) | |
| download | sellershut-78f61ccdf66572d7432b5b627994038479103653.tar.bz2 sellershut-78f61ccdf66572d7432b5b627994038479103653.zip | |
feat: oauth from config
| -rw-r--r-- | .env.example | 1 | ||||
| -rw-r--r-- | Cargo.lock | 625 | ||||
| -rw-r--r-- | Cargo.toml | 42 | ||||
| -rw-r--r-- | README.md | 5 | ||||
| -rw-r--r-- | lib/auth/Cargo.toml | 13 | ||||
| -rw-r--r-- | lib/auth/src/lib.rs | 41 | ||||
| -rw-r--r-- | misc/compose.yaml | 36 | ||||
| -rw-r--r-- | misc/sellershut.toml (renamed from sellershut.toml) | 6 | ||||
| -rw-r--r-- | src/config/cli.rs | 23 | ||||
| -rw-r--r-- | src/config/mod.rs | 60 | ||||
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/server/state/database.rs | 1 | ||||
| -rw-r--r-- | src/server/state/mod.rs | 27 |
13 files changed, 846 insertions, 36 deletions
diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..36fa84f --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +DATABASE_URL=postgres://postgres:password@localhost:5432/sellershut @@ -24,6 +24,15 @@ 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 = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -183,6 +192,31 @@ dependencies = [ ] [[package]] +name = "bon" +version = "3.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234655ec178edd82b891e262ea7cf71f6584bcd09eff94db786be23f1821825c" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "3.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ec27229c38ed0eb3c0feee3d2c1d6a4379ae44f418a29a658890e062d8f365" +dependencies = [ + "darling", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] name = "bumpalo" version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -217,6 +251,26 @@ 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.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] name = "clap" version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -272,6 +326,12 @@ dependencies = [ ] [[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" @@ -330,6 +390,40 @@ dependencies = [ ] [[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] name = "derive_arbitrary" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -525,8 +619,24 @@ 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]] @@ -658,6 +768,24 @@ dependencies = [ "pin-utils", "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 1.0.5", ] [[package]] @@ -666,14 +794,46 @@ version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ + "base64", "bytes", + "futures-channel", "futures-core", + "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]] @@ -758,6 +918,12 @@ dependencies = [ ] [[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] name = "idna" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -791,6 +957,22 @@ dependencies = [ ] [[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + +[[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -803,6 +985,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -847,6 +1039,12 @@ 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" @@ -933,6 +1131,26 @@ dependencies = [ ] [[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.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1010,6 +1228,16 @@ dependencies = [ ] [[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] name = "proc-macro2" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1019,6 +1247,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.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +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.44" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1028,14 +1311,30 @@ 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", - "rand_core", + "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]] @@ -1045,7 +1344,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "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]] @@ -1054,7 +1363,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "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]] @@ -1105,6 +1423,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[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 1.0.5", +] + +[[package]] name = "ring" version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1112,7 +1468,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -1153,6 +1509,12 @@ dependencies = [ ] [[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] name = "rustls" version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1172,6 +1534,7 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ + "web-time", "zeroize", ] @@ -1187,6 +1550,12 @@ dependencies = [ ] [[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] name = "ryu" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1208,12 +1577,26 @@ 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", "axum", "clap", + "oauth2", + "rand 0.9.2", + "secrecy", + "sellershut-auth", "serde", "sqlx", "tokio", @@ -1229,6 +1612,17 @@ dependencies = [ ] [[package]] +name = "sellershut-auth" +version = "0.1.0" +dependencies = [ + "bon", + "oauth2", + "secrecy", + "thiserror 2.0.18", + "url", +] + +[[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1409,7 +1803,7 @@ dependencies = [ "serde_json", "sha2", "smallvec", - "thiserror", + "thiserror 2.0.18", "tokio", "tokio-stream", "tracing", @@ -1478,14 +1872,14 @@ dependencies = [ "md-5", "memchr", "once_cell", - "rand", + "rand 0.8.5", "serde", "serde_json", "sha2", "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 2.0.18", "tracing", "whoami", ] @@ -1535,6 +1929,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" @@ -1549,11 +1946,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]] @@ -1629,6 +2046,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 = "tokio-stream" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1695,6 +2122,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" @@ -1769,6 +2214,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" @@ -1934,18 +2385,115 @@ 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.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +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 = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1983,12 +2531,65 @@ dependencies = [ ] [[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]] name = "windows-link" 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" @@ -2217,6 +2818,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" [[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.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1,21 +1,46 @@ +[workspace] +resolver = "3" +members = [ ".", "lib/*" ] + +[workspace.package] +description = "A federated marketplace platform" +documentation = "https://books.kanjala.com/sellershut" +homepage = "https://git.kanjala.com/sellershut" +license = "AGPL-3.0-only" + +[workspace.dependencies] +anyhow = "1.0.100" +bon = "3.8.2" +oauth2 = "5.0.0" +rand = "0.9.2" +secrecy = "0.10.3" +serde = "1.0.228" +thiserror = "2.0.18" +tracing = "0.1.44" +url = "2.5.8" + [package] name = "sellershut" version = "0.1.0" edition = "2024" -license = "AGPL-3.0-only" -description = "A federated marketplace platform" -homepage = "https://git.kanjala.com/sellershut" +description.workspace = true +documentation.workspace = true +homepage.workspace = true +license.workspace = true [dependencies] -anyhow = "1.0.100" +anyhow.workspace = true axum = "0.8.8" clap = { version = "4.5.56", features = ["derive", "env"] } -serde = { version = "1.0.228", features = ["derive"] } +oauth2.workspace = true +secrecy = { workspace = true, features = ["serde"] } +sellershut-auth = { path = "lib/auth" } +serde = { workspace = true, features = ["derive"] } tokio = { version = "1.49.0", features = ["rt-multi-thread", "macros", "signal"] } toml = "0.9.11" -tracing = "0.1.44" +tracing.workspace = true tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } -url = { version = "2.5.8", features = ["serde"] } +url = { workspace = true, features = ["serde"] } utoipa = "5.4.0" utoipa-rapidoc = { version = "6.0.0", optional = true } utoipa-redoc = { version = "6.0.0", optional = true } @@ -37,3 +62,6 @@ utoipa-swagger-ui = ["dep:utoipa-swagger-ui"] [profile.dev.package.sqlx-macros] opt-level = 3 + +[dev-dependencies] +rand.workspace = true @@ -1 +1,6 @@ # sellershut + +```sh +cp .env.example .env +cargo sqlx database create +``` diff --git a/lib/auth/Cargo.toml b/lib/auth/Cargo.toml new file mode 100644 index 0000000..0852935 --- /dev/null +++ b/lib/auth/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "sellershut-auth" +version = "0.1.0" +edition = "2024" +license.workspace = true +documentation.workspace = true + +[dependencies] +bon.workspace = true +oauth2.workspace = true +secrecy.workspace = true +thiserror.workspace = true +url.workspace = true diff --git a/lib/auth/src/lib.rs b/lib/auth/src/lib.rs new file mode 100644 index 0000000..2a1390e --- /dev/null +++ b/lib/auth/src/lib.rs @@ -0,0 +1,41 @@ +use bon::Builder; +use oauth2::{AuthUrl, ClientId, ClientSecret, EndpointNotSet, EndpointSet, RedirectUrl, TokenUrl}; +use secrecy::{ExposeSecret, SecretString}; +use thiserror::Error; + +#[derive(Builder)] +pub struct ClientOptions { + client_id: String, + client_secret: SecretString, + token_url: String, + auth_url: String, + redirect_url: String, +} + +#[derive(Error, Debug)] +pub enum OauthError { + #[error("invalid url")] + InvalidUrl(#[from] url::ParseError), +} + +pub type OauthClient = oauth2::basic::BasicClient< + EndpointSet, + EndpointNotSet, + EndpointNotSet, + EndpointNotSet, + EndpointSet, +>; + +pub fn oauth_client(opts: &ClientOptions) -> Result<OauthClient, OauthError> { + let redirect_url = RedirectUrl::new(opts.redirect_url.to_owned())?; + let client_id = ClientId::new(opts.client_id.to_owned()); + let auth_url = AuthUrl::new(opts.auth_url.to_owned())?; + let token_url = TokenUrl::new(opts.token_url.to_owned())?; + let client_secret = ClientSecret::new(opts.client_secret.expose_secret().to_string()); + + Ok(oauth2::basic::BasicClient::new(client_id) + .set_client_secret(client_secret) + .set_auth_uri(auth_url) + .set_token_uri(token_url) + .set_redirect_uri(redirect_url)) +} diff --git a/misc/compose.yaml b/misc/compose.yaml new file mode 100644 index 0000000..1fccb81 --- /dev/null +++ b/misc/compose.yaml @@ -0,0 +1,36 @@ +name: sellershut + +services: + database: + image: docker.io/postgres:18.1-alpine + restart: always + shm_size: 128mb + environment: + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} + 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 + + adminer: + image: docker.io/adminer:5.4.1 + restart: always + ports: + - 8080:8080 + networks: + - sellershut + +volumes: + db: + driver: local + +networks: + sellershut: diff --git a/sellershut.toml b/misc/sellershut.toml index 15225f5..0fdef72 100644 --- a/sellershut.toml +++ b/misc/sellershut.toml @@ -7,13 +7,13 @@ system-name = "sellershut" environment = "dev" [oauth] -redirect-url = "" +redirect-url = "https://example.com" [oauth.discord] client-id = "" client-secret = "" -token-url = "" -auth-url = "" +token-url = "https://example.com" +auth-url = "https://example.com" [database] url = "postgres://postres:password@localhost:5432/sellershut" diff --git a/src/config/cli.rs b/src/config/cli.rs index dab7216..5254135 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -1,6 +1,7 @@ use std::path::PathBuf; use clap::Parser; +use serde::Deserialize; use url::Url; use crate::config::{logging::LogLevel, port::port_in_range}; @@ -49,25 +50,33 @@ pub struct Cli { pub oauth: Option<OAuth>, } -#[derive(Debug, Clone, Parser)] +#[derive(Debug, Clone, Parser, Deserialize)] pub struct OAuth { #[cfg(feature = "oauth-discord")] #[command(flatten)] discord: DiscordOauth, - #[arg(long)] + #[arg(long, env = "OAUTH_REDIRECT_URL")] oauth_redirect_url: Option<Url>, } #[cfg(feature = "oauth-discord")] -#[derive(Debug, Clone, Parser)] +#[derive(Debug, Clone, Parser, Deserialize)] pub struct DiscordOauth { - #[arg(long)] + #[arg(long, env = "OAUTH_DISCORD_CLIENT_ID")] discord_client_id: Option<String>, - #[arg(long)] + #[arg(long, env = "OAUTH_DISCORD_CLIENT_SECRET")] discord_client_secret: Option<String>, - #[arg(long)] + #[arg( + long, + env = "OAUTH_DISCORD_TOKEN_URL", + default_value = "https://discord.com/api/oauth2/token" + )] discord_token_url: Option<Url>, - #[arg(long)] + #[arg( + long, + env = "OAUTH_DISCORD_AUTH_URL", + default_value = "https://discord.com/api/oauth2/authorize?response_type=code" + )] discord_auth_url: Option<Url>, } diff --git a/src/config/mod.rs b/src/config/mod.rs index 45e12c3..19ee241 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -2,10 +2,12 @@ mod cli; mod logging; mod port; pub use cli::Cli; +#[cfg(feature = "oauth-discord")] +use secrecy::SecretString; use serde::Deserialize; use url::Url; -use crate::{config::logging::LogLevel}; +use crate::config::logging::LogLevel; #[derive(Default, Deserialize, Debug, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] @@ -22,6 +24,8 @@ pub struct Config { pub database: DatabaseOptions, #[serde(default)] pub server: Api, + #[serde(default)] + pub oauth: OAuth, } #[derive(Debug, Deserialize)] @@ -46,6 +50,52 @@ pub struct Api { pub environment: Environment, } +#[derive(Debug, Clone, Deserialize)] +pub struct OAuth { + #[cfg(feature = "oauth-discord")] + pub discord: DiscordOauth, + #[serde(rename = "redirect-url")] + pub oauth_redirect_url: Url, +} + +#[cfg(feature = "oauth-discord")] +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct DiscordOauth { + pub client_id: String, + pub client_secret: SecretString, + #[serde(default = "discord_token_url")] + pub token_url: Url, + #[serde(default = "discord_auth_url")] + pub auth_url: Url, +} + +fn discord_token_url() -> Url { + Url::parse("https://discord.com/api/oauth2/authorize?response_type=code").expect("valid url") +} + +fn discord_auth_url() -> Url { + Url::parse("https://discord.com/api/oauth2/authorize?response_type=code").expect("valid url") +} + +fn redirect_url() -> Url { + Url::parse("http://127.0.0.1:2210/auth/authorised").expect("valid url") +} + +impl Default for OAuth { + fn default() -> Self { + Self { + discord: DiscordOauth { + client_id: String::default(), + client_secret: SecretString::default(), + token_url: discord_token_url(), + auth_url: discord_auth_url(), + }, + oauth_redirect_url: redirect_url(), + } +} +} + impl Default for Api { fn default() -> Self { Self { @@ -68,7 +118,7 @@ pub struct DatabaseOptions { } impl DatabaseOptions { - pub fn create(url: & Url, pool_size: Option<u32>) -> Self { + pub fn create(url: &Url, pool_size: Option<u32>) -> Self { Self { url: url.to_owned(), pool_size: pool_size.unwrap_or_else(|| { @@ -89,8 +139,7 @@ impl Default for DatabaseOptions { fn default() -> Self { Self { url: default_database(), - pool_size: 100 - + pool_size: 100, } } } @@ -115,7 +164,6 @@ fn default_log_level() -> LogLevel { LogLevel::Debug } - impl Config { pub fn merge_with_cli(&mut self, cli: &Cli) { let server = &mut self.server; @@ -149,7 +197,7 @@ mod tests { #[test] fn config_file() { - let s = include_str!("../../sellershut.toml"); + let s = include_str!("../../misc/sellershut.toml"); assert!(toml::from_str::<Config>(s).is_ok()) } } diff --git a/src/main.rs b/src/main.rs index cb8c2a9..8ee10a1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ use clap::Parser; use tokio::net::TcpListener; use tracing::info; -use crate::{config::Config, logging::initialise_logging, server::state::{AppState }}; +use crate::{config::Config, logging::initialise_logging, server::state::AppState}; #[tokio::main] async fn main() -> anyhow::Result<()> { diff --git a/src/server/state/database.rs b/src/server/state/database.rs index 32d3f98..f8fd332 100644 --- a/src/server/state/database.rs +++ b/src/server/state/database.rs @@ -4,7 +4,6 @@ use tracing::{debug, trace}; use crate::config::DatabaseOptions; - pub(super) async fn connect(opts: &DatabaseOptions) -> Result<PgPool> { trace!(host = ?opts.url.host(), "connecting to database"); let pg = PgPoolOptions::new() diff --git a/src/server/state/mod.rs b/src/server/state/mod.rs index f4bf029..0726689 100644 --- a/src/server/state/mod.rs +++ b/src/server/state/mod.rs @@ -1,17 +1,40 @@ pub mod database; +use sellershut_auth::{ClientOptions, OauthClient}; use sqlx::PgPool; +#[cfg(feature = "oauth-discord")] +use url::Url; -use crate::{config::Config}; +use crate::config::Config; +#[cfg(feature = "oauth-discord")] +use crate::config::DiscordOauth; pub struct AppState { database: PgPool, + #[cfg(feature = "oauth-discord")] + oauth_discord: OauthClient, } impl AppState { pub async fn new(config: &Config) -> anyhow::Result<Self> { let database = database::connect(&config.database).await?; - Ok(Self{database}) + Ok(Self { + database, + oauth_discord: discord_client(&config.oauth.discord, &config.oauth.oauth_redirect_url)?, + }) } } + +#[cfg(feature = "oauth-discord")] +fn discord_client(disc: &DiscordOauth, redirect: &Url)->anyhow::Result<OauthClient> { + let discord_opts = ClientOptions::builder() + .client_id(disc.client_id.to_owned()) + .redirect_url(redirect.to_string()) + .auth_url(disc.auth_url.to_string()) + .client_secret(disc.client_secret.clone()) + .token_url(disc.token_url.to_string()) + .build(); + + Ok(sellershut_auth::oauth_client(&discord_opts)?) +} |
