diff options
| author | rtkay123 <dev@kanjala.com> | 2026-02-02 13:05:49 +0200 |
|---|---|---|
| committer | rtkay123 <dev@kanjala.com> | 2026-02-02 13:05:49 +0200 |
| commit | e06094f23ca861ea5ae4864d11fa8ce8b7d7aa2c (patch) | |
| tree | 27bbff5fd21711f99aaf579a76b1a0aca7869003 | |
| parent | 78f61ccdf66572d7432b5b627994038479103653 (diff) | |
| download | sellershut-e06094f23ca861ea5ae4864d11fa8ce8b7d7aa2c.tar.bz2 sellershut-e06094f23ca861ea5ae4864d11fa8ce8b7d7aa2c.zip | |
feat: oauth route
| -rw-r--r-- | Cargo.lock | 621 | ||||
| -rw-r--r-- | Cargo.toml | 21 | ||||
| -rw-r--r-- | src/config/cli.rs | 1 | ||||
| -rw-r--r-- | src/config/mod.rs | 23 | ||||
| -rw-r--r-- | src/main.rs | 10 | ||||
| -rw-r--r-- | src/server/driver/mod.rs | 29 | ||||
| -rw-r--r-- | src/server/error/mod.rs | 27 | ||||
| -rw-r--r-- | src/server/middleware/mod.rs | 1 | ||||
| -rw-r--r-- | src/server/middleware/request_id.rs | 20 | ||||
| -rw-r--r-- | src/server/mod.rs | 125 | ||||
| -rw-r--r-- | src/server/routes/auth/discord.rs | 11 | ||||
| -rw-r--r-- | src/server/routes/auth/mod.rs | 59 | ||||
| -rw-r--r-- | src/server/routes/mod.rs | 49 | ||||
| -rw-r--r-- | src/server/state/database.rs | 2 | ||||
| -rw-r--r-- | src/server/state/federation.rs | 65 | ||||
| -rw-r--r-- | src/server/state/mod.rs | 17 |
16 files changed, 1020 insertions, 61 deletions
@@ -3,6 +3,56 @@ version = 4 [[package]] +name = "activitypub_federation" +version = "0.7.0-beta.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05f124225de07889f93f0e49ac23d6877c4e63c628c19cc936929643be28a61" +dependencies = [ + "activitystreams-kinds", + "async-trait", + "axum", + "base64", + "bytes", + "chrono", + "derive_builder", + "dyn-clone", + "either", + "enum_delegate", + "futures", + "futures-core", + "http", + "http-signature-normalization", + "http-signature-normalization-reqwest", + "httpdate", + "itertools", + "moka", + "pin-project-lite", + "rand 0.8.5", + "regex", + "reqwest", + "reqwest-middleware", + "rsa", + "serde", + "serde_json", + "sha2", + "thiserror 2.0.18", + "tokio", + "tower", + "tracing", + "url", +] + +[[package]] +name = "activitystreams-kinds" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97dfe76efd8c0b113cc3580a6b5f4acba47662e3cfbbfcce081c9ac89798990" +dependencies = [ + "serde", + "url", +] + +[[package]] name = "adler2" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -98,6 +148,28 @@ dependencies = [ ] [[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[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 2.0.114", +] + +[[package]] name = "atoi" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -125,6 +197,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", + "axum-macros", "bytes", "form_urlencoded", "futures-util", @@ -171,12 +244,29 @@ dependencies = [ ] [[package]] +name = "axum-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -207,13 +297,13 @@ version = "3.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89ec27229c38ed0eb3c0feee3d2c1d6a4379ae44f418a29a658890e062d8f365" dependencies = [ - "darling", + "darling 0.23.0", "ident_case", "prettyplease", "proc-macro2", "quote", "rustversion", - "syn", + "syn 2.0.114", ] [[package]] @@ -301,7 +391,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -326,6 +416,12 @@ dependencies = [ ] [[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" @@ -365,6 +461,24 @@ dependencies = [ ] [[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] name = "crossbeam-queue" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -391,12 +505,36 @@ dependencies = [ [[package]] name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.114", ] [[package]] @@ -409,7 +547,18 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 2.0.114", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.114", ] [[package]] @@ -418,9 +567,20 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "darling_core", + "darling_core 0.23.0", "quote", - "syn", + "syn 2.0.114", +] + +[[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]] @@ -431,7 +591,38 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.114", ] [[package]] @@ -441,6 +632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -453,7 +645,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -463,6 +655,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -472,6 +670,30 @@ dependencies = [ ] [[package]] +name = "enum_delegate" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8ea75f31022cba043afe037940d73684327e915f88f62478e778c3de914cd0a" +dependencies = [ + "enum_delegate_lib", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "enum_delegate_lib" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1f6c3800b304a6be0012039e2a45a322a093539c45ab818d9e6895a39c90fe" +dependencies = [ + "proc-macro2", + "quote", + "rand 0.8.5", + "syn 1.0.109", +] + +[[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -510,6 +732,16 @@ dependencies = [ ] [[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] name = "find-msvc-tools" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -527,6 +759,12 @@ dependencies = [ ] [[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -542,6 +780,21 @@ dependencies = [ ] [[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] name = "futures-channel" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -558,6 +811,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +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" @@ -575,6 +839,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] name = "futures-sink" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -592,8 +867,10 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -738,6 +1015,32 @@ dependencies = [ ] [[package]] +name = "http-signature-normalization" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95e3149194de5f3f9d5225bcc6a8677979f8ff8ce39c85654730ad4824f101e" +dependencies = [ + "httpdate", +] + +[[package]] +name = "http-signature-normalization-reqwest" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "981cd4def046db1dfe4546471d3d2747ebf4b5ec384d0cfc12ab59745aba03df" +dependencies = [ + "async-trait", + "base64", + "http-signature-normalization", + "httpdate", + "reqwest", + "reqwest-middleware", + "sha2", + "thiserror 2.0.18", + "tokio", +] + +[[package]] name = "httparse" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -979,6 +1282,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] name = "itoa" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -999,6 +1311,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -1007,6 +1322,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[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.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1113,6 +1434,26 @@ dependencies = [ ] [[package]] +name = "moka" +version = "0.12.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac832c50ced444ef6be0767a008b02c106a909ba79d1d830501e94b96f6b7e" +dependencies = [ + "async-lock", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "event-listener", + "futures-util", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", +] + +[[package]] name = "nu-ansi-term" version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1122,12 +1463,49 @@ dependencies = [ ] [[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]] +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]] @@ -1192,6 +1570,21 @@ dependencies = [ ] [[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" @@ -1210,6 +1603,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[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 = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] name = "potential_utf" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1234,7 +1654,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.114", ] [[package]] @@ -1431,6 +1851,7 @@ dependencies = [ "base64", "bytes", "futures-core", + "futures-util", "http", "http-body", "http-body-util", @@ -1450,17 +1871,34 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-rustls", + "tokio-util", "tower", "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "webpki-roots 1.0.5", ] [[package]] +name = "reqwest-middleware" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" +dependencies = [ + "anyhow", + "async-trait", + "http", + "reqwest", + "serde", + "thiserror 1.0.69", + "tower-service", +] + +[[package]] name = "ring" version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1475,6 +1913,26 @@ dependencies = [ ] [[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" @@ -1494,7 +1952,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn", + "syn 2.0.114", "walkdir", ] @@ -1590,7 +2048,9 @@ dependencies = [ name = "sellershut" version = "0.1.0" dependencies = [ + "activitypub_federation", "anyhow", + "async-trait", "axum", "clap", "oauth2", @@ -1601,14 +2061,18 @@ dependencies = [ "sqlx", "tokio", "toml", + "tower", + "tower-http", "tracing", "tracing-subscriber", "url", "utoipa", + "utoipa-axum", "utoipa-rapidoc", "utoipa-redoc", "utoipa-scalar", "utoipa-swagger-ui", + "uuid", ] [[package]] @@ -1649,7 +2113,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -1658,6 +2122,7 @@ version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ + "indexmap", "itoa", "memchr", "serde", @@ -1734,6 +2199,16 @@ dependencies = [ ] [[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.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1765,6 +2240,22 @@ dependencies = [ ] [[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[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" @@ -1821,7 +2312,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn", + "syn 2.0.114", ] [[package]] @@ -1842,7 +2333,7 @@ dependencies = [ "sha2", "sqlx-core", "sqlx-postgres", - "syn", + "syn 2.0.114", "tokio", "url", ] @@ -1915,6 +2406,17 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" @@ -1941,10 +2443,16 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1970,7 +2478,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -1981,7 +2489,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -2042,7 +2550,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -2067,6 +2575,19 @@ dependencies = [ ] [[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] name = "toml" version = "0.9.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2134,9 +2655,12 @@ dependencies = [ "http-body", "iri-string", "pin-project-lite", + "tokio", "tower", "tower-layer", "tower-service", + "tracing", + "uuid", ] [[package]] @@ -2171,7 +2695,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -2302,6 +2826,19 @@ dependencies = [ ] [[package]] +name = "utoipa-axum" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c25bae5bccc842449ec0c5ddc5cbb6a3a1eaeac4503895dc105a1138f8234a0" +dependencies = [ + "axum", + "paste", + "tower-layer", + "tower-service", + "utoipa", +] + +[[package]] name = "utoipa-gen" version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2309,7 +2846,7 @@ checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -2318,6 +2855,7 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5f8f5abd341cce16bb4f09a8bafc087d4884a004f25fb980e538d51d6501dab" dependencies = [ + "axum", "serde", "serde_json", "utoipa", @@ -2329,6 +2867,7 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6427547f6db7ec006cbbef95f7565952a16f362e298b416d2d497d9706fef72d" dependencies = [ + "axum", "serde", "serde_json", "utoipa", @@ -2340,6 +2879,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59559e1509172f6b26c1cdbc7247c4ddd1ac6560fe94b584f81ee489b141f719" dependencies = [ + "axum", "serde", "serde_json", "utoipa", @@ -2351,6 +2891,7 @@ version = "9.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d047458f1b5b65237c2f6dc6db136945667f40a7668627b3490b9513a3d43a55" dependencies = [ + "axum", "base64", "mime_guess", "regex", @@ -2363,6 +2904,17 @@ dependencies = [ ] [[package]] +name = "uuid" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "wasm-bindgen", +] + +[[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2460,7 +3012,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.114", "wasm-bindgen-shared", ] @@ -2474,6 +3026,19 @@ dependencies = [ ] [[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] name = "web-sys" version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2551,7 +3116,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -2562,7 +3127,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -2848,7 +3413,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", "synstructure", ] @@ -2869,7 +3434,7 @@ checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -2889,7 +3454,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", "synstructure", ] @@ -2929,7 +3494,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -10,6 +10,7 @@ license = "AGPL-3.0-only" [workspace.dependencies] anyhow = "1.0.100" +async-trait = "0.1.89" bon = "3.8.2" oauth2 = "5.0.0" rand = "0.9.2" @@ -18,6 +19,7 @@ serde = "1.0.228" thiserror = "2.0.18" tracing = "0.1.44" url = "2.5.8" +uuid = "1.20.0" [package] name = "sellershut" @@ -29,8 +31,10 @@ homepage.workspace = true license.workspace = true [dependencies] +activitypub_federation = { version = "0.7.0-beta.8", default-features = false, features = ["axum"] } anyhow.workspace = true -axum = "0.8.8" +async-trait.workspace = true +axum = { version = "0.8.8", features = ["macros"] } clap = { version = "4.5.56", features = ["derive", "env"] } oauth2.workspace = true secrecy = { workspace = true, features = ["serde"] } @@ -38,14 +42,18 @@ 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" +tower = "0.5.3" +tower-http = { version = "0.6.8", features = ["cors", "request-id", "timeout", "trace"] } tracing.workspace = true tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } url = { workspace = true, features = ["serde"] } utoipa = "5.4.0" +utoipa-axum = "0.2.0" utoipa-rapidoc = { version = "6.0.0", optional = true } utoipa-redoc = { version = "6.0.0", optional = true } utoipa-scalar = { version = "0.3.0", optional = true } utoipa-swagger-ui = { version = "9.0.2", optional = true } +uuid = { workspace = true, features = ["v7"] } [dependencies.sqlx] version = "0.8.6" @@ -54,11 +62,12 @@ features = ["postgres", "runtime-tokio-rustls"] [features] default = ["oauth-discord"] -oauth-discord = [] -utoipa-rapidoc = ["dep:utoipa-rapidoc"] -utoipa-redoc = ["dep:utoipa-redoc"] -utoipa-scalar = ["dep:utoipa-scalar"] -utoipa-swagger-ui = ["dep:utoipa-swagger-ui"] +oauth = [] +oauth-discord = ["oauth"] +rapidoc = ["dep:utoipa-rapidoc", "utoipa-rapidoc/axum"] +redoc = ["dep:utoipa-redoc", "utoipa-redoc/axum"] +scalar = ["dep:utoipa-scalar", "utoipa-scalar/axum"] +swagger = ["dep:utoipa-swagger-ui", "utoipa-swagger-ui/axum"] [profile.dev.package.sqlx-macros] opt-level = 3 diff --git a/src/config/cli.rs b/src/config/cli.rs index 5254135..7bc6312 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -47,6 +47,7 @@ pub struct Cli { /// Oauth optionas #[command(flatten)] + #[cfg(feature = "oauth")] pub oauth: Option<OAuth>, } diff --git a/src/config/mod.rs b/src/config/mod.rs index 19ee241..01af6d8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -2,7 +2,7 @@ mod cli; mod logging; mod port; pub use cli::Cli; -#[cfg(feature = "oauth-discord")] +#[cfg(feature = "oauth")] use secrecy::SecretString; use serde::Deserialize; use url::Url; @@ -25,6 +25,7 @@ pub struct Config { #[serde(default)] pub server: Api, #[serde(default)] + #[cfg(feature = "oauth")] pub oauth: OAuth, } @@ -84,16 +85,16 @@ fn redirect_url() -> 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(), - } -} + 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 { diff --git a/src/main.rs b/src/main.rs index 8ee10a1..c529379 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,11 @@ 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::{driver::Services, state::AppState}, +}; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -23,7 +27,9 @@ async fn main() -> anyhow::Result<()> { initialise_logging(&config); - let state = AppState::new(&config).await?; + let driver = Services::new(&config.database).await?; + let state = AppState::new(&config, driver).await?; + let router = server::router(&config, state).await?; let addr = SocketAddr::from((Ipv6Addr::UNSPECIFIED, config.server.port)); diff --git a/src/server/driver/mod.rs b/src/server/driver/mod.rs new file mode 100644 index 0000000..4c540cb --- /dev/null +++ b/src/server/driver/mod.rs @@ -0,0 +1,29 @@ +use async_trait::async_trait; +use sqlx::PgPool; + +use crate::{config::DatabaseOptions, server::state::database}; + +pub struct Services { + database: PgPool, + // oauth: OauthClient, +} + +impl Services { + pub async fn new(database: &DatabaseOptions) -> anyhow::Result<Self> { + let database = database::connect(database).await?; + + Ok(Self { database }) + } +} + +#[async_trait] +pub trait SellershutDriver: Send + Sync + 'static { + async fn hello(&self); +} + +#[async_trait] +impl SellershutDriver for Services { + async fn hello(&self) { + todo!() + } +} diff --git a/src/server/error/mod.rs b/src/server/error/mod.rs new file mode 100644 index 0000000..6d07f9f --- /dev/null +++ b/src/server/error/mod.rs @@ -0,0 +1,27 @@ +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, +}; + +#[derive(Debug)] +pub struct AppError(anyhow::Error); + +// Tell axum how to convert `AppError` into a response. +impl IntoResponse for AppError { + fn into_response(self) -> Response { + tracing::error!("Application error: {:#}", self.0); + + (StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong").into_response() + } +} + +// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into +// `Result<_, AppError>`. That way you don't need to do that manually. +impl<E> From<E> for AppError +where + E: Into<anyhow::Error>, +{ + fn from(err: E) -> Self { + Self(err.into()) + } +} diff --git a/src/server/middleware/mod.rs b/src/server/middleware/mod.rs new file mode 100644 index 0000000..f68f27a --- /dev/null +++ b/src/server/middleware/mod.rs @@ -0,0 +1 @@ +pub(super) mod request_id; diff --git a/src/server/middleware/request_id.rs b/src/server/middleware/request_id.rs new file mode 100644 index 0000000..7163c86 --- /dev/null +++ b/src/server/middleware/request_id.rs @@ -0,0 +1,20 @@ +use axum::{ + extract::Request, + http::{HeaderValue, StatusCode}, + middleware::Next, + response::Response, +}; +use uuid::Uuid; + +pub const REQUEST_ID_HEADER: &str = "x-request-id"; + +pub async fn add_request_id(mut request: Request, next: Next) -> Result<Response, StatusCode> { + let headers = request.headers_mut(); + let id = Uuid::now_v7().to_string(); + tracing::trace!(id = id, "attaching request id"); + let bytes = id.as_bytes(); + + headers.insert(REQUEST_ID_HEADER, HeaderValue::from_bytes(bytes).unwrap()); + + Ok(next.run(request).await) +} diff --git a/src/server/mod.rs b/src/server/mod.rs index 803135f..3301035 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,10 +1,125 @@ -use axum::Router; - -use crate::{config::Config, server::state::AppState}; - +pub mod driver; +pub mod error; +mod middleware; +pub mod routes; pub mod shutdown; pub mod state; +use std::time::Duration; + +use activitypub_federation::config::{FederationConfig, FederationMiddleware}; +use axum::{ + Router, + http::{HeaderName, StatusCode}, +}; +use tower_http::{ + cors::{self, CorsLayer}, + request_id::PropagateRequestIdLayer, + timeout::TimeoutLayer, + trace::TraceLayer, +}; +use tracing::{error, info_span}; +use utoipa::OpenApi; +use utoipa_axum::router::OpenApiRouter; + +use crate::{ + config::Config, + server::{ + middleware::request_id::{REQUEST_ID_HEADER, add_request_id}, + routes::auth::OAuthDoc, + state::{AppState, federation}, + }, +}; + +#[derive(OpenApi)] +#[openapi( + tags( + (name = routes::HEALTH, description = "Check API health"), + ), +)] +pub struct ApiDoc; + pub async fn router(config: &Config, state: AppState) -> anyhow::Result<Router<()>> { - todo!() + let state = federation::add_federation(state, config).await?; + + let mut doc = ApiDoc::openapi(); + doc.merge(OAuthDoc::openapi()); + + let (router, _api) = OpenApiRouter::with_openapi(doc) + .routes(utoipa_axum::routes!(routes::health_check)) + .routes(utoipa_axum::routes!(routes::auth::auth)) + .split_for_parts(); + + #[cfg(feature = "swagger")] + let router = router.merge( + utoipa_swagger_ui::SwaggerUi::new("/swagger-ui") + .url("/api-docs/swaggerdoc.json", _api.clone()), + ); + + #[cfg(feature = "redoc")] + let router = { + use utoipa_redoc::Servable as _; + router.merge(utoipa_redoc::Redoc::with_url("/redoc", _api.clone())) + }; + + #[cfg(feature = "scalar")] + let router = { + use utoipa_scalar::Servable as _; + router.merge(utoipa_scalar::Scalar::with_url("/scalar", _api.clone())) + }; + + #[cfg(feature = "rapidoc")] + let router = router.merge( + utoipa_rapidoc::RapiDoc::with_openapi("/api-docs/rapidoc.json", _api).path("/rapidoc"), + ); + + let router = router + .layer( + TraceLayer::new_for_http().make_span_with(|request: &axum::http::Request<_>| { + if let Some(request_id) = request.headers().get(REQUEST_ID_HEADER) { + info_span!( + "http_request", + request_id = ?request_id, + ) + } else { + error!("could not extract request_id"); + info_span!("http_request") + } + }), + ) + .layer(TimeoutLayer::with_status_code( + StatusCode::REQUEST_TIMEOUT, + Duration::from_secs(config.server.request_timeout), + )) + .layer(FederationMiddleware::new(state)) + // send headers from request to response headers + .layer(PropagateRequestIdLayer::new(HeaderName::from_static( + REQUEST_ID_HEADER, + ))) + .layer(axum::middleware::from_fn(add_request_id)) + .layer( + CorsLayer::new() + .allow_origin(cors::Any) + .allow_headers(cors::Any) + .allow_methods(cors::Any), + ); + + Ok(router) +} + +#[cfg(test)] +pub mod bootstrap { + use async_trait::async_trait; + + use crate::server::driver::SellershutDriver; + + #[derive(Debug, Default)] + pub struct TestDriver {} + + #[async_trait] + impl SellershutDriver for TestDriver { + async fn hello(&self) { + todo!() + } + } } diff --git a/src/server/routes/auth/discord.rs b/src/server/routes/auth/discord.rs new file mode 100644 index 0000000..036a35a --- /dev/null +++ b/src/server/routes/auth/discord.rs @@ -0,0 +1,11 @@ +use std::sync::Arc; + +use axum::{extract::State, response::IntoResponse}; + +use crate::server::{driver::SellershutDriver, error::AppError}; + +async fn auth( + State(client): State<Arc<dyn SellershutDriver>>, +) -> Result<impl IntoResponse, AppError> { + Ok(()) +} diff --git a/src/server/routes/auth/mod.rs b/src/server/routes/auth/mod.rs new file mode 100644 index 0000000..b80c565 --- /dev/null +++ b/src/server/routes/auth/mod.rs @@ -0,0 +1,59 @@ +use activitypub_federation::config::Data; + +use serde::Deserialize; + +#[cfg(feature = "oauth-discord")] +pub mod discord; + +#[derive(Deserialize, Debug, Clone, Copy, ToSchema)] +#[serde(rename_all = "lowercase")] +pub enum OauthProvider { + /// Discord + #[cfg(feature = "oauth-discord")] + Discord, +} + +#[derive(Deserialize, Debug, Clone, Copy, IntoParams)] +#[into_params(parameter_in = Query)] +pub struct Params { + /// Set OAuth provider name + provider: OauthProvider, +} + +use axum::{extract::Query, response::IntoResponse}; +use utoipa::{IntoParams, OpenApi, ToSchema}; + +use crate::server::{error::AppError, state::AppState}; + +pub const AUTH: &str = "AUTH"; + +#[derive(OpenApi)] +#[openapi( + tags( + (name = AUTH, description = "OAuth integration") + ), + components( + schemas(OauthProvider) + ) +)] +pub struct OAuthDoc; + +#[utoipa::path( + method(get), + path = "/auth", + params( + Params + ), + tag = AUTH, + responses( + (status = OK, description = "Routes to oauth provider for login", body = str, content_type = "text/plain") + ) +)] +#[axum::debug_handler] +pub async fn auth( + Query(params): Query<Params>, + data: Data<AppState>, +) -> Result<impl IntoResponse, AppError> { + dbg!(¶ms); + Ok(String::default()) +} diff --git a/src/server/routes/mod.rs b/src/server/routes/mod.rs new file mode 100644 index 0000000..edd6fdf --- /dev/null +++ b/src/server/routes/mod.rs @@ -0,0 +1,49 @@ +#[cfg(feature = "oauth")] +pub mod auth; + +pub(super) const HEALTH: &str = "HEALTH"; + +#[utoipa::path( + method(get), + path = "/", + tag = HEALTH, + responses( + (status = OK, description = "Checks if the server is running", body = str, content_type = "text/plain") + ) +)] +pub async fn health_check() -> impl axum::response::IntoResponse { + let name = env!("CARGO_PKG_NAME"); + let version = env!("CARGO_PKG_VERSION"); + + format!("{name} v{version} is live") +} + +#[cfg(test)] +mod tests { + use crate::{ + config::Config, + server::{self, bootstrap::TestDriver, state::AppState}, + }; + + use axum::{ + body::Body, + http::{Request, StatusCode}, + }; + use tower::ServiceExt; + + #[tokio::test] + async fn health_check() { + let config = Config::default(); + let driver = TestDriver::default(); + let state = AppState::new(&config, driver).await.unwrap(); + + let app = server::router(&config, state).await.unwrap(); + + let response = app + .oneshot(Request::builder().uri("/").body(Body::empty()).unwrap()) + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::OK); + } +} diff --git a/src/server/state/database.rs b/src/server/state/database.rs index f8fd332..156de0f 100644 --- a/src/server/state/database.rs +++ b/src/server/state/database.rs @@ -4,7 +4,7 @@ use tracing::{debug, trace}; use crate::config::DatabaseOptions; -pub(super) async fn connect(opts: &DatabaseOptions) -> Result<PgPool> { +pub async fn connect(opts: &DatabaseOptions) -> Result<PgPool> { trace!(host = ?opts.url.host(), "connecting to database"); let pg = PgPoolOptions::new() .max_connections(opts.pool_size) diff --git a/src/server/state/federation.rs b/src/server/state/federation.rs new file mode 100644 index 0000000..083741c --- /dev/null +++ b/src/server/state/federation.rs @@ -0,0 +1,65 @@ +use activitypub_federation::config::FederationConfig; +use url::Url; + +use crate::{ + config::{Config, Environment}, + server::state::AppState, +}; + +pub async fn add_federation( + state: AppState, + config: &Config, +) -> anyhow::Result<FederationConfig<AppState>> { + let url = match config.server.environment { + Environment::Dev => { + format!("http://{}", config.server.domain) + } + Environment::Prod => { + format!("https://{}", config.server.domain) + } + }; + let mut url = Url::parse(&url)?; + + if Environment::Dev == config.server.environment { + let _ = url.set_port(Some(config.server.port)); + } + + let mut ap_id = url.clone(); + + { + let mut ps = ap_id.path_segments_mut().expect("path segments in url"); + ps.push("users"); + ps.push(&config.server.system_name); + } + + // let user = if let Some(user) = state.users_service.get_by_ap_id(ap_id.as_str()).await? { + // user + // } else { + // let mut inbox = ap_id.clone(); + // { + // let mut ps = inbox.path_segments_mut().expect("path segments in url"); + // ps.push("inbox"); + // } + // state + // .users_service + // .create_user( + // &ap_id, + // &config.server.system_name, + // PersonType::Service, + // &inbox, + // true, + // ) + // .await? + // }; + // + // let user = User::from(user); + + let config = FederationConfig::builder() + .domain(url.domain().expect("system domain")) + //.signed_fetch_actor(&user) + .app_data(state) + .build() + .await?; + + Ok(config) +} diff --git a/src/server/state/mod.rs b/src/server/state/mod.rs index 0726689..f5f731e 100644 --- a/src/server/state/mod.rs +++ b/src/server/state/mod.rs @@ -1,33 +1,34 @@ pub mod database; +pub mod federation; + +use std::sync::Arc; use sellershut_auth::{ClientOptions, OauthClient}; -use sqlx::PgPool; #[cfg(feature = "oauth-discord")] use url::Url; -use crate::config::Config; #[cfg(feature = "oauth-discord")] use crate::config::DiscordOauth; +use crate::{config::Config, server::driver::SellershutDriver}; +#[derive(Clone)] pub struct AppState { - database: PgPool, + driver: Arc<dyn SellershutDriver>, #[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?; - + pub async fn new(config: &Config, driver: impl SellershutDriver) -> anyhow::Result<Self> { Ok(Self { - database, + driver: Arc::new(driver), 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> { +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()) |
