mirror of
https://forgejo.ellis.link/continuwuation/continuwuity/
synced 2026-07-20 12:50:57 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba0ec6ba70 |
@@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
- name: Setup Node.js
|
||||
if: steps.runner-env.outputs.node_major == '' || steps.runner-env.outputs.node_major < '20'
|
||||
uses: https://github.com/actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
|
||||
uses: https://github.com/actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 📦 Setup Node.js
|
||||
uses: https://github.com/actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
|
||||
uses: https://github.com/actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
|
||||
Generated
+89
-100
@@ -171,7 +171,7 @@ dependencies = [
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -227,13 +227,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.91"
|
||||
version = "0.1.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec"
|
||||
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.0",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -469,7 +469,7 @@ dependencies = [
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex 1.3.0",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -637,7 +637,7 @@ checksum = "aa61aec073ec94791433ddf3df2323ff9d1711557c2a0eefb0f99cb4f8dca520"
|
||||
dependencies = [
|
||||
"semver",
|
||||
"serde",
|
||||
"toml 1.1.3+spec-1.1.0",
|
||||
"toml 1.1.2+spec-1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -747,7 +747,7 @@ dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -996,7 +996,7 @@ dependencies = [
|
||||
"tikv-jemallocator",
|
||||
"tokio",
|
||||
"tokio-metrics",
|
||||
"toml 1.1.3+spec-1.1.0",
|
||||
"toml 1.1.2+spec-1.1.0",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-subscriber",
|
||||
@@ -1032,7 +1032,7 @@ dependencies = [
|
||||
"itertools 0.15.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1344,7 +1344,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strict",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1505,7 +1505,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1534,7 +1534,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1545,7 +1545,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1609,7 +1609,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1653,7 +1653,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1951,9 +1951,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.33"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218"
|
||||
checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -1966,9 +1966,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.33"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae"
|
||||
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@@ -1976,15 +1976,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.33"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7"
|
||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.33"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458"
|
||||
checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@@ -1993,32 +1993,32 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.33"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a"
|
||||
checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.33"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b"
|
||||
checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.33"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307"
|
||||
checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.33"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109"
|
||||
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
@@ -2028,9 +2028,9 @@ checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.33"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa"
|
||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -2409,7 +2409,7 @@ dependencies = [
|
||||
"markup5ever",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2850,7 +2850,7 @@ dependencies = [
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"simd_cesu8",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2869,7 +2869,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2941,7 +2941,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3459,7 +3459,7 @@ version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"getrandom 0.2.17",
|
||||
"http",
|
||||
@@ -3882,7 +3882,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"proc-macro2-diagnostics",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3965,7 +3965,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4098,7 +4098,7 @@ dependencies = [
|
||||
"proc-macro-error-attr3",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4118,7 +4118,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
"version_check",
|
||||
"yansi",
|
||||
]
|
||||
@@ -4143,7 +4143,7 @@ dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4392,7 +4392,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4727,8 +4727,8 @@ dependencies = [
|
||||
"quote",
|
||||
"ruma-identifiers-validation",
|
||||
"serde",
|
||||
"syn 2.0.119",
|
||||
"toml 1.1.3+spec-1.1.0",
|
||||
"syn",
|
||||
"toml 1.1.2+spec-1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5065,9 +5065,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry"
|
||||
version = "0.48.5"
|
||||
version = "0.48.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d631477761f57c76148456e55e80e9a479ff3fa4c65b2b4a0c3acf1167fd4638"
|
||||
checksum = "82719d9cd9d2686541dc49875f7944ab71348edfcc6a5686414b22ea0b6d9b29"
|
||||
dependencies = [
|
||||
"cfg_aliases",
|
||||
"httpdate",
|
||||
@@ -5085,9 +5085,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-backtrace"
|
||||
version = "0.48.5"
|
||||
version = "0.48.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "448b0981fbde6cdc9eb087ba3dc01035a253fef9a0d9e79aaf198fc26acb2e64"
|
||||
checksum = "317271b821fcca9fc661f66aa8afe93058578d05cca4bd09615fe28a16c8b4cb"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"regex",
|
||||
@@ -5096,9 +5096,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-contexts"
|
||||
version = "0.48.5"
|
||||
version = "0.48.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5e909d02170ba6d1dc5ebd05bef7999280f5d960e3eaee5d1a18d88d41b334"
|
||||
checksum = "7bae5c2f69cd0f7a1543846b4df412ba8ea1aa2ec4eb5333f125332cec8d4868"
|
||||
dependencies = [
|
||||
"hostname",
|
||||
"libc",
|
||||
@@ -5110,9 +5110,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-core"
|
||||
version = "0.48.5"
|
||||
version = "0.48.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecf0b1a4a4e9ec88395b52e6fa4868b95564c1fa96b26a0606f5f6288a0f7149"
|
||||
checksum = "b8c44ee52fa3d30581f951b57aec754ef9cd70186df5fb788367804360c48097"
|
||||
dependencies = [
|
||||
"rand 0.9.5",
|
||||
"sentry-types",
|
||||
@@ -5123,9 +5123,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-debug-images"
|
||||
version = "0.48.5"
|
||||
version = "0.48.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f81d7749c57fc78ed52134889e8121da874065bc40da788d5798cce0f8c19f15"
|
||||
checksum = "f96d38ec7e843f909e59acb0cc77452157755ad582be0386df800b6ce71350ba"
|
||||
dependencies = [
|
||||
"findshlibs",
|
||||
"sentry-core",
|
||||
@@ -5133,9 +5133,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-log"
|
||||
version = "0.48.5"
|
||||
version = "0.48.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11ffc7737b6d4f1cb3707284703c7364e9f5f056118abc523dd52e732f13cbe1"
|
||||
checksum = "227bac907069e40179ccb4de250c9de1162d3d484d36fce099c15351c81c03de"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"log",
|
||||
@@ -5144,9 +5144,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-panic"
|
||||
version = "0.48.5"
|
||||
version = "0.48.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7d93d6ecb55d2251c5fc084c55c03a2bc68904918d76117e602c999e92f00f"
|
||||
checksum = "d47aa64170cf609b948fe8f47d2690541bde11e465daa836cf81ad6e62bb3240"
|
||||
dependencies = [
|
||||
"sentry-backtrace",
|
||||
"sentry-core",
|
||||
@@ -5154,9 +5154,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-tower"
|
||||
version = "0.48.5"
|
||||
version = "0.48.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a64a8a0a33239c65f95ff719fcb56655f398f4e4e74a01af8daca725cf7c2b5f"
|
||||
checksum = "f1e77cd9e2d179445b62827f72d91a9f7edc781328d41b6c2e68da0bbcb8aaf1"
|
||||
dependencies = [
|
||||
"http",
|
||||
"pin-project",
|
||||
@@ -5168,9 +5168,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-tracing"
|
||||
version = "0.48.5"
|
||||
version = "0.48.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58d26379236c4ef97eaf081bca3c7bf0ef6f06b3aa881eca2ee8e8dbc923e5b8"
|
||||
checksum = "27bdb405dbdfb1dd8b1cca46db8afe7ddd28dd4a55108b27b893170cc614912c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"sentry-backtrace",
|
||||
@@ -5181,9 +5181,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sentry-types"
|
||||
version = "0.48.5"
|
||||
version = "0.48.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2239099d47e76857b0825a182ecdb90159add7aa1097b60247c6e7ca6bf49c6a"
|
||||
checksum = "1be93ef0435a5ab91f88178fb7681249437e875d004f996ecb35be94dc99a0e0"
|
||||
dependencies = [
|
||||
"debugid",
|
||||
"hex",
|
||||
@@ -5214,7 +5214,7 @@ checksum = "7bd22781911de0ca6debda95f073c8f18bec65d1a94f1fa9573f3102e514cea4"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"annotate-snippets",
|
||||
"base64 0.21.7",
|
||||
"base64 0.22.1",
|
||||
"encoding_rs_io",
|
||||
"getrandom 0.3.4",
|
||||
"granit-parser",
|
||||
@@ -5252,7 +5252,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5370,7 +5370,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5631,20 +5631,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.119"
|
||||
version = "2.0.118"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2fac314a64dc9a36e61a9eb4261a5e9bbfbc922b27e518af97bc32b926cf967"
|
||||
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -5668,7 +5657,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5761,7 +5750,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5772,7 +5761,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5892,7 +5881,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5955,9 +5944,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "1.1.3+spec-1.1.0"
|
||||
version = "1.1.2+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c"
|
||||
checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
|
||||
dependencies = [
|
||||
"indexmap 2.14.0",
|
||||
"serde_core",
|
||||
@@ -6029,9 +6018,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.1.2+spec-1.1.0"
|
||||
version = "1.1.1+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2"
|
||||
checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
@@ -6248,7 +6237,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6469,7 +6458,7 @@ dependencies = [
|
||||
"proc-macro-error3",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6566,7 +6555,7 @@ dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -6712,7 +6701,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6723,7 +6712,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6920,7 +6909,7 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -6941,7 +6930,7 @@ checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6961,7 +6950,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -7001,7 +6990,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Fixed requests returning `500 Internal Server Error` when the header selected by `request_ip_source` is absent, duplicated, or malformed (for example Envoy omitting `X-Envoy-External-Address` on internal requests). The client IP now falls back to the connection peer address instead of failing the request. Contributed by @eleboucher
|
||||
@@ -1 +0,0 @@
|
||||
Resolve alias service by correct name for auto-join. Contributed by @eleboucher
|
||||
@@ -1 +0,0 @@
|
||||
Fixed newly joined rooms failing to sync their full state (including the room name) to clients using legacy sync.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed `create` being returned as a supported prompt value regardless of if registration is enabled or not. Contributed by @ginger
|
||||
@@ -1 +0,0 @@
|
||||
Updated an out-of-date statement about Oracle Linux release cadences.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed high CPU usage when multiple clients from the same account were connected at once. Each sync woke the account's other sync loops, causing them to wake each other in a loop.
|
||||
@@ -1 +0,0 @@
|
||||
Fix joining restricted rooms over federation failing with signature verification error.
|
||||
@@ -15,8 +15,8 @@ ## Overview
|
||||
|
||||
:::warning Oracle Linux support
|
||||
Due to upstream limitations, Terra is only usable on Oracle Linux if you use [upstream EPEL](https://docs.fedoraproject.org/en-US/epel/getting-started/)
|
||||
rather than Oracle's rebuilds of EPEL. Oracle tends to lag behind on new EL versions, both major and minor—for example, Oracle's release of 10.2 lagged
|
||||
approximately 1.5 months behind other ELs—so you may encounter further compatibility issues with EPEL.
|
||||
rather than Oracle's rebuilds of EPEL. Oracle tends to lag behind on new EL versions, both major and minor—for example, as of the time of writing, 10.2 has been
|
||||
available for over a month through other ELs, but Oracle has not yet released corresponding updates—so you may encounter further compatibility issues with EPEL.
|
||||
**For this reason, it is recommended that you use another EL distribution if at all possible.**
|
||||
:::
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
target:
|
||||
target.fromToolchainName {
|
||||
name = (lib.importTOML "${inputs.self}/rust-toolchain.toml").toolchain.channel;
|
||||
sha256 = "sha256-A1abGIbOtcBSdrUMhDGrER3pRM1hQP4fp9gh3Y4PKc8=";
|
||||
sha256 = "sha256-OATSZm98Es5kIFuqaba+UvkQtFsVgJEBMmS+t6od5/U=";
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
@@ -60,13 +60,6 @@
|
||||
"matchPackageNames": ["rust", "rustc", "cargo"],
|
||||
"groupName": "rust-toolchain"
|
||||
},
|
||||
{
|
||||
"description": "Delay major rust toolchain updates",
|
||||
"matchManagers": ["custom.regex"],
|
||||
"matchPackageNames": ["rust", "rustc", "cargo"],
|
||||
"matchUpdateTypes": ["major"],
|
||||
"minimumReleaseAge": "30 days"
|
||||
},
|
||||
{
|
||||
"description": "Batch minor and patch GitHub Actions updates",
|
||||
"matchManagers": ["github-actions"],
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
[toolchain]
|
||||
profile = "minimal"
|
||||
channel = "1.97.1"
|
||||
channel = "1.97.0"
|
||||
components = [
|
||||
# For rust-analyzer
|
||||
"rust-src",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, err, info,
|
||||
pdu::PartialPdu,
|
||||
@@ -26,7 +27,7 @@
|
||||
use service::{mailer::messages, uiaa::UiaaInitiator, users::HashedPassword};
|
||||
|
||||
use super::DEVICE_ID_LENGTH;
|
||||
use crate::{Ruma, client_ip::ClientIp, router::ClientIdentity};
|
||||
use crate::{Ruma, router::ClientIdentity};
|
||||
|
||||
pub(crate) mod register;
|
||||
pub(crate) mod threepid;
|
||||
@@ -42,9 +43,10 @@
|
||||
///
|
||||
/// Note: This will not reserve the username, so the username might become
|
||||
/// invalid when trying to register
|
||||
#[tracing::instrument(skip_all, name = "register_available", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "register_available", level = "info")]
|
||||
pub(crate) async fn get_register_available_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_username_availability::v3::Request>,
|
||||
) -> Result<get_username_availability::v3::Response> {
|
||||
let _ = services
|
||||
@@ -78,9 +80,10 @@ pub(crate) async fn get_register_available_route(
|
||||
/// last seen ts)
|
||||
/// - Forgets to-device events
|
||||
/// - Triggers device list updates
|
||||
#[tracing::instrument(skip_all, name = "change_password", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "change_password", level = "info")]
|
||||
pub(crate) async fn change_password_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<change_password::v3::Request>,
|
||||
) -> Result<change_password::v3::Response> {
|
||||
let identity = if let Some(identity) = body.identity.as_ref() {
|
||||
@@ -245,9 +248,10 @@ pub(crate) async fn whoami_route(
|
||||
/// - Forgets all to-device events
|
||||
/// - Triggers device list updates
|
||||
/// - Removes ability to log in again
|
||||
#[tracing::instrument(skip_all, name = "deactivate", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "deactivate", level = "info")]
|
||||
pub(crate) async fn deactivate_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<deactivate::v3::Request>,
|
||||
) -> Result<deactivate::v3::Response> {
|
||||
// Authentication for this endpoint is technically optional,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, debug_info, info,
|
||||
utils::{self},
|
||||
@@ -25,7 +26,7 @@
|
||||
};
|
||||
|
||||
use super::DEVICE_ID_LENGTH;
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `POST /_matrix/client/v3/register`
|
||||
///
|
||||
@@ -35,10 +36,10 @@
|
||||
/// /_matrix/client/v3/register/available`](fn.get_register_available_route.
|
||||
/// html) to check if the user id is valid and available.
|
||||
#[allow(clippy::doc_markdown)]
|
||||
#[tracing::instrument(skip_all, name = "register", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "register", level = "info")]
|
||||
pub(crate) async fn register_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp, // NOTE: Required for metadata.
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<register::v3::Request>,
|
||||
) -> Result<register::v3::Response> {
|
||||
if body.kind != RegistrationKind::User {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result, at};
|
||||
use futures::StreamExt;
|
||||
use ruma::{
|
||||
@@ -11,16 +12,17 @@
|
||||
assign,
|
||||
};
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
const MAX_BATCH_EVENTS: usize = 50;
|
||||
|
||||
/// # `PUT /_matrix/client/../dehydrated_device`
|
||||
///
|
||||
/// Creates or overwrites the user's dehydrated device.
|
||||
#[tracing::instrument(skip_all)]
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
pub(crate) async fn put_dehydrated_device_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<put_dehydrated_device::Request>,
|
||||
) -> Result<put_dehydrated_device::Response> {
|
||||
let device_id = body.device_id.clone();
|
||||
@@ -36,9 +38,10 @@ pub(crate) async fn put_dehydrated_device_route(
|
||||
/// # `DELETE /_matrix/client/../dehydrated_device`
|
||||
///
|
||||
/// Deletes the user's dehydrated device without replacement.
|
||||
#[tracing::instrument(skip_all)]
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
pub(crate) async fn delete_dehydrated_device_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<delete_dehydrated_device::Request>,
|
||||
) -> Result<delete_dehydrated_device::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -53,9 +56,10 @@ pub(crate) async fn delete_dehydrated_device_route(
|
||||
/// # `GET /_matrix/client/../dehydrated_device`
|
||||
///
|
||||
/// Gets the user's dehydrated device
|
||||
#[tracing::instrument(skip_all)]
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
pub(crate) async fn get_dehydrated_device_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_dehydrated_device::Request>,
|
||||
) -> Result<get_dehydrated_device::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -68,9 +72,10 @@ pub(crate) async fn get_dehydrated_device_route(
|
||||
/// # `GET /_matrix/client/../dehydrated_device/{device_id}/events`
|
||||
///
|
||||
/// Paginates the events of the dehydrated device.
|
||||
#[tracing::instrument(skip_all)]
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
pub(crate) async fn get_dehydrated_events_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_events::Request>,
|
||||
) -> Result<get_events::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result, debug, err, utils};
|
||||
use futures::StreamExt;
|
||||
use ruma::{
|
||||
@@ -8,7 +9,7 @@
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{Ruma, client::DEVICE_ID_LENGTH, client_ip::ClientIp};
|
||||
use crate::{Ruma, client::DEVICE_ID_LENGTH};
|
||||
|
||||
/// # `GET /_matrix/client/r0/devices`
|
||||
///
|
||||
@@ -45,10 +46,10 @@ pub(crate) async fn get_device_route(
|
||||
/// # `PUT /_matrix/client/r0/devices/{deviceId}`
|
||||
///
|
||||
/// Updates the metadata on a given device of the sender user.
|
||||
#[tracing::instrument(skip_all, name = "update_device", level = "debug")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "update_device", level = "debug")]
|
||||
pub(crate) async fn update_device_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp, // NOTE: Required for updating device metadata
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<update_device::v3::Request>,
|
||||
) -> Result<update_device::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, err, info,
|
||||
utils::{
|
||||
@@ -27,16 +28,17 @@
|
||||
};
|
||||
use tokio::join;
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `POST /_matrix/client/v3/publicRooms`
|
||||
///
|
||||
/// Lists the public rooms on this server.
|
||||
///
|
||||
/// - Rooms are ordered by the number of joined members
|
||||
#[tracing::instrument(skip_all, name = "publicrooms", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms", level = "info")]
|
||||
pub(crate) async fn get_public_rooms_filtered_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_public_rooms_filtered::v3::Request>,
|
||||
) -> Result<get_public_rooms_filtered::v3::Response> {
|
||||
if let Some(server) = &body.server {
|
||||
@@ -69,9 +71,10 @@ pub(crate) async fn get_public_rooms_filtered_route(
|
||||
/// Lists the public rooms on this server.
|
||||
///
|
||||
/// - Rooms are ordered by the number of joined members
|
||||
#[tracing::instrument(skip_all, name = "publicrooms", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "publicrooms", level = "info")]
|
||||
pub(crate) async fn get_public_rooms_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_public_rooms::v3::Request>,
|
||||
) -> Result<get_public_rooms::v3::Response> {
|
||||
if let Some(server) = &body.server {
|
||||
@@ -103,9 +106,10 @@ pub(crate) async fn get_public_rooms_route(
|
||||
/// # `PUT /_matrix/client/r0/directory/list/room/{roomId}`
|
||||
///
|
||||
/// Sets the visibility of a given room in the room directory.
|
||||
#[tracing::instrument(skip_all, name = "room_directory", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "room_directory", level = "info")]
|
||||
pub(crate) async fn set_room_visibility_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<set_room_visibility::v3::Request>,
|
||||
) -> Result<set_room_visibility::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
+37
-1
@@ -1,6 +1,7 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, err,
|
||||
utils::{self, content_disposition::make_content_disposition, math::ruma_from_usize},
|
||||
@@ -23,7 +24,7 @@
|
||||
};
|
||||
use service::media::mxc::Mxc;
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `GET /_matrix/client/v1/media/config`
|
||||
pub(crate) async fn get_media_config_route(
|
||||
@@ -41,8 +42,15 @@ pub(crate) async fn get_media_config_route(
|
||||
///
|
||||
/// - Some metadata will be saved in the database
|
||||
/// - Media will be saved in the media/ directory
|
||||
#[tracing::instrument(
|
||||
name = "media_upload",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client),
|
||||
)]
|
||||
pub(crate) async fn create_content_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<create_content::v3::Request>,
|
||||
) -> Result<create_content::v3::Response> {
|
||||
let user = body.identity.expect_sender_user()?;
|
||||
@@ -73,8 +81,15 @@ pub(crate) async fn create_content_route(
|
||||
/// # `GET /_matrix/client/v1/media/thumbnail/{serverName}/{mediaId}`
|
||||
///
|
||||
/// Load media thumbnail from our server or over federation.
|
||||
#[tracing::instrument(
|
||||
name = "media_thumbnail_get",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client),
|
||||
)]
|
||||
pub(crate) async fn get_content_thumbnail_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_thumbnail::v1::Request>,
|
||||
) -> Result<get_content_thumbnail::v1::Response> {
|
||||
let user = body.identity.expect_sender_user()?;
|
||||
@@ -116,8 +131,15 @@ pub(crate) async fn get_content_thumbnail_route(
|
||||
/// # `GET /_matrix/client/v1/media/download/{serverName}/{mediaId}`
|
||||
///
|
||||
/// Load media from our server or over federation.
|
||||
#[tracing::instrument(
|
||||
name = "media_get",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client),
|
||||
)]
|
||||
pub(crate) async fn get_content_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content::v1::Request>,
|
||||
) -> Result<get_content::v1::Response> {
|
||||
let user = body.identity.expect_sender_user()?;
|
||||
@@ -156,8 +178,15 @@ pub(crate) async fn get_content_route(
|
||||
/// # `GET /_matrix/client/v1/media/download/{serverName}/{mediaId}/{fileName}`
|
||||
///
|
||||
/// Load media from our server or over federation as fileName.
|
||||
#[tracing::instrument(
|
||||
name = "media_get_af",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client),
|
||||
)]
|
||||
pub(crate) async fn get_content_as_filename_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_as_filename::v1::Request>,
|
||||
) -> Result<get_content_as_filename::v1::Response> {
|
||||
let user = body.identity.expect_sender_user()?;
|
||||
@@ -200,8 +229,15 @@ pub(crate) async fn get_content_as_filename_route(
|
||||
/// # `GET /_matrix/client/v1/media/preview_url`
|
||||
///
|
||||
/// Returns URL preview.
|
||||
#[tracing::instrument(
|
||||
name = "url_preview",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client),
|
||||
)]
|
||||
pub(crate) async fn get_media_preview_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_media_preview::v1::Request>,
|
||||
) -> Result<get_media_preview::v1::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![allow(deprecated)]
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, err,
|
||||
utils::{content_disposition::make_content_disposition, math::ruma_from_usize},
|
||||
@@ -16,7 +17,7 @@
|
||||
};
|
||||
use service::media::mxc::Mxc;
|
||||
|
||||
use crate::{Ruma, RumaResponse, client::create_content_route, client_ip::ClientIp};
|
||||
use crate::{Ruma, RumaResponse, client::create_content_route};
|
||||
|
||||
/// # `GET /_matrix/media/v3/config`
|
||||
///
|
||||
@@ -49,8 +50,10 @@ pub(crate) async fn get_media_config_legacy_legacy_route(
|
||||
/// # `GET /_matrix/media/v3/preview_url`
|
||||
///
|
||||
/// Returns URL preview.
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "url_preview_legacy", level = "debug")]
|
||||
pub(crate) async fn get_media_preview_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_media_preview::v3::Request>,
|
||||
) -> Result<get_media_preview::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -92,9 +95,10 @@ pub(crate) async fn get_media_preview_legacy_route(
|
||||
/// Returns URL preview.
|
||||
pub(crate) async fn get_media_preview_legacy_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_media_preview::v3::Request>,
|
||||
) -> Result<RumaResponse<get_media_preview::v3::Response>> {
|
||||
get_media_preview_legacy_route(State(services), body)
|
||||
get_media_preview_legacy_route(State(services), ClientIp(client), body)
|
||||
.await
|
||||
.map(RumaResponse)
|
||||
}
|
||||
@@ -111,9 +115,10 @@ pub(crate) async fn get_media_preview_legacy_legacy_route(
|
||||
/// - Media will be saved in the media/ directory
|
||||
pub(crate) async fn create_content_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<create_content::v3::Request>,
|
||||
) -> Result<RumaResponse<create_content::v3::Response>> {
|
||||
create_content_route(State(services), body)
|
||||
create_content_route(State(services), ClientIp(client), body)
|
||||
.await
|
||||
.map(RumaResponse)
|
||||
}
|
||||
@@ -126,8 +131,10 @@ pub(crate) async fn create_content_legacy_route(
|
||||
/// - Only redirects if `allow_redirect` is true
|
||||
/// - Uses client-provided `timeout_ms` if available, else defaults to 20
|
||||
/// seconds
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")]
|
||||
pub(crate) async fn get_content_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content::v3::Request>,
|
||||
) -> Result<get_content::v3::Response> {
|
||||
let mxc = Mxc {
|
||||
@@ -202,11 +209,13 @@ pub(crate) async fn get_content_legacy_route(
|
||||
/// - Only redirects if `allow_redirect` is true
|
||||
/// - Uses client-provided `timeout_ms` if available, else defaults to 20
|
||||
/// seconds
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")]
|
||||
pub(crate) async fn get_content_legacy_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content::v3::Request>,
|
||||
) -> Result<RumaResponse<get_content::v3::Response>> {
|
||||
get_content_legacy_route(State(services), body)
|
||||
get_content_legacy_route(State(services), ClientIp(client), body)
|
||||
.await
|
||||
.map(RumaResponse)
|
||||
}
|
||||
@@ -219,8 +228,10 @@ pub(crate) async fn get_content_legacy_legacy_route(
|
||||
/// - Only redirects if `allow_redirect` is true
|
||||
/// - Uses client-provided `timeout_ms` if available, else defaults to 20
|
||||
/// seconds
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "media_get_legacy", level = "debug")]
|
||||
pub(crate) async fn get_content_as_filename_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_as_filename::v3::Request>,
|
||||
) -> Result<get_content_as_filename::v3::Response> {
|
||||
let mxc = Mxc {
|
||||
@@ -296,9 +307,10 @@ pub(crate) async fn get_content_as_filename_legacy_route(
|
||||
/// seconds
|
||||
pub(crate) async fn get_content_as_filename_legacy_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_as_filename::v3::Request>,
|
||||
) -> Result<RumaResponse<get_content_as_filename::v3::Response>> {
|
||||
get_content_as_filename_legacy_route(State(services), body)
|
||||
get_content_as_filename_legacy_route(State(services), ClientIp(client), body)
|
||||
.await
|
||||
.map(RumaResponse)
|
||||
}
|
||||
@@ -311,8 +323,10 @@ pub(crate) async fn get_content_as_filename_legacy_legacy_route(
|
||||
/// - Only redirects if `allow_redirect` is true
|
||||
/// - Uses client-provided `timeout_ms` if available, else defaults to 20
|
||||
/// seconds
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "media_thumbnail_get_legacy", level = "debug")]
|
||||
pub(crate) async fn get_content_thumbnail_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_thumbnail::v3::Request>,
|
||||
) -> Result<get_content_thumbnail::v3::Response> {
|
||||
let mxc = Mxc {
|
||||
@@ -390,9 +404,10 @@ pub(crate) async fn get_content_thumbnail_legacy_route(
|
||||
/// seconds
|
||||
pub(crate) async fn get_content_thumbnail_legacy_legacy_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_thumbnail::v3::Request>,
|
||||
) -> Result<RumaResponse<get_content_thumbnail::v3::Response>> {
|
||||
get_content_thumbnail_legacy_route(State(services), body)
|
||||
get_content_thumbnail_legacy_route(State(services), ClientIp(client), body)
|
||||
.await
|
||||
.map(RumaResponse)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, debug_error, err, info,
|
||||
matrix::{event::gen_event_id_canonical_json, pdu::PartialPdu},
|
||||
@@ -17,14 +18,15 @@
|
||||
use service::Services;
|
||||
|
||||
use super::banned_room_check;
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/invite`
|
||||
///
|
||||
/// Tries to send an invite event into the room.
|
||||
#[tracing::instrument(skip_all, name = "invite", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "invite", level = "info")]
|
||||
pub(crate) async fn invite_user_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<invite_user::v3::Request>,
|
||||
) -> Result<invite_user::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -40,8 +42,14 @@ pub(crate) async fn invite_user_route(
|
||||
return Err!(Request(Forbidden("Invites are not allowed on this server.")));
|
||||
}
|
||||
|
||||
banned_room_check(&services, sender_user, Some(&body.room_id), body.room_id.server_name())
|
||||
.await?;
|
||||
banned_room_check(
|
||||
&services,
|
||||
sender_user,
|
||||
Some(&body.room_id),
|
||||
body.room_id.server_name(),
|
||||
client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
match &body.recipient {
|
||||
| invite_user::v3::InvitationRecipient::UserId(InviteUserId {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, debug,
|
||||
result::FlatOk,
|
||||
@@ -11,7 +12,7 @@
|
||||
};
|
||||
|
||||
use super::banned_room_check;
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/join`
|
||||
///
|
||||
@@ -21,9 +22,10 @@
|
||||
/// rules locally
|
||||
/// - If the server does not know about the room: asks other servers over
|
||||
/// federation
|
||||
#[tracing::instrument(skip_all, name = "join", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "join", level = "info")]
|
||||
pub(crate) async fn join_room_by_id_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<join_room_by_id::v3::Request>,
|
||||
) -> Result<join_room_by_id::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -31,8 +33,14 @@ pub(crate) async fn join_room_by_id_route(
|
||||
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
|
||||
}
|
||||
|
||||
banned_room_check(&services, sender_user, Some(&body.room_id), body.room_id.server_name())
|
||||
.await?;
|
||||
banned_room_check(
|
||||
&services,
|
||||
sender_user,
|
||||
Some(&body.room_id),
|
||||
body.room_id.server_name(),
|
||||
client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// There is no body.server_name for /roomId/join
|
||||
let mut servers: Vec<_> = services
|
||||
@@ -83,9 +91,10 @@ pub(crate) async fn join_room_by_id_route(
|
||||
/// - If the server does not know about the room: use the server name query
|
||||
/// param if specified. if not specified, asks other servers over federation
|
||||
/// via room alias server name and room ID server name
|
||||
#[tracing::instrument(skip_all, name = "join", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "join", level = "info")]
|
||||
pub(crate) async fn join_room_by_id_or_alias_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<join_room_by_id_or_alias::v3::Request>,
|
||||
) -> Result<join_room_by_id_or_alias::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -96,9 +105,15 @@ pub(crate) async fn join_room_by_id_or_alias_route(
|
||||
|
||||
let (servers, room_id) = match OwnedRoomId::try_from(body.room_id_or_alias.clone()) {
|
||||
| Ok(room_id) => {
|
||||
banned_room_check(&services, sender_user, Some(&room_id), room_id.server_name())
|
||||
.boxed()
|
||||
.await?;
|
||||
banned_room_check(
|
||||
&services,
|
||||
sender_user,
|
||||
Some(&room_id),
|
||||
room_id.server_name(),
|
||||
client,
|
||||
)
|
||||
.boxed()
|
||||
.await?;
|
||||
|
||||
let mut servers = body.via.clone();
|
||||
if servers.is_empty() {
|
||||
@@ -144,6 +159,7 @@ pub(crate) async fn join_room_by_id_or_alias_route(
|
||||
sender_user,
|
||||
Some(&room_id),
|
||||
Some(room_alias.server_name()),
|
||||
client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::{borrow::Borrow, collections::HashMap, iter::once, sync::Arc};
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, debug, debug_info, debug_warn, err, info,
|
||||
matrix::{
|
||||
@@ -39,14 +40,15 @@
|
||||
};
|
||||
|
||||
use super::banned_room_check;
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `POST /_matrix/client/*/knock/{roomIdOrAlias}`
|
||||
///
|
||||
/// Tries to knock the room to ask permission to join for the sender user.
|
||||
#[tracing::instrument(skip_all, name = "knock", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "knock", level = "info")]
|
||||
pub(crate) async fn knock_room_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<knock_room::v3::Request>,
|
||||
) -> Result<knock_room::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -57,8 +59,14 @@ pub(crate) async fn knock_room_route(
|
||||
|
||||
let (servers, room_id) = match OwnedRoomId::try_from(body.room_id_or_alias.clone()) {
|
||||
| Ok(room_id) => {
|
||||
banned_room_check(&services, sender_user, Some(&room_id), room_id.server_name())
|
||||
.await?;
|
||||
banned_room_check(
|
||||
&services,
|
||||
sender_user,
|
||||
Some(&room_id),
|
||||
room_id.server_name(),
|
||||
client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut servers = body.via.clone();
|
||||
servers.extend(
|
||||
@@ -101,6 +109,7 @@ pub(crate) async fn knock_room_route(
|
||||
sender_user,
|
||||
Some(&room_id),
|
||||
Some(room_alias.server_name()),
|
||||
client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
mod members;
|
||||
mod unban;
|
||||
|
||||
use std::net::IpAddr;
|
||||
|
||||
use axum::extract::State;
|
||||
use conduwuit::{Err, Result, warn};
|
||||
use futures::{FutureExt, StreamExt};
|
||||
@@ -56,6 +58,7 @@ pub(crate) async fn banned_room_check(
|
||||
user_id: &UserId,
|
||||
room_id: Option<&RoomId>,
|
||||
server_name: Option<&ServerName>,
|
||||
client_ip: IpAddr,
|
||||
) -> Result {
|
||||
if services.users.is_admin(user_id).await {
|
||||
return Ok(());
|
||||
@@ -82,7 +85,7 @@ pub(crate) async fn banned_room_check(
|
||||
.admin
|
||||
.send_text(&format!(
|
||||
"Automatically deactivating user {user_id} due to attempted banned \
|
||||
room join"
|
||||
room join from IP {client_ip}"
|
||||
))
|
||||
.await;
|
||||
}
|
||||
@@ -118,7 +121,7 @@ pub(crate) async fn banned_room_check(
|
||||
.admin
|
||||
.send_text(&format!(
|
||||
"Automatically deactivating user {user_id} due to attempted banned \
|
||||
room join"
|
||||
room join from IP {client_ip}"
|
||||
))
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Error, Result, at, debug_warn,
|
||||
matrix::{
|
||||
@@ -37,7 +38,7 @@
|
||||
};
|
||||
use ruminuwuity::invite_permission_config::FilterLevel;
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// list of safe and common non-state events to ignore if the user is ignored
|
||||
const IGNORED_MESSAGE_TYPES: &[TimelineEventType] = &[
|
||||
@@ -71,7 +72,7 @@
|
||||
/// where the user was joined, depending on `history_visibility`)
|
||||
pub(crate) async fn get_message_events_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client_ip): ClientIp, // NOTE: Required for updating device metadata
|
||||
ClientIp(client_ip): ClientIp,
|
||||
body: Ruma<get_message_events::v3::Request>,
|
||||
) -> Result<get_message_events::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -37,17 +37,6 @@ pub(crate) async fn authorization_server_metadata(services: &Services) -> Value
|
||||
.join(super::BASE_PATH)
|
||||
.unwrap();
|
||||
|
||||
let prompt_values_supported = if services
|
||||
.uiaa
|
||||
.registration_flow_status()
|
||||
.await
|
||||
.any_available()
|
||||
{
|
||||
json!(["create"])
|
||||
} else {
|
||||
json!([])
|
||||
};
|
||||
|
||||
json!({
|
||||
"account_management_uri": endpoint_base.join(ACCOUNT_MANAGEMENT_PATH).unwrap(),
|
||||
"account_management_actions_supported": [
|
||||
@@ -63,7 +52,7 @@ pub(crate) async fn authorization_server_metadata(services: &Services) -> Value
|
||||
"grant_types_supported": ["authorization_code", "refresh_token"],
|
||||
"issuer": services.config.get_client_domain(),
|
||||
"jwks_uri": endpoint_base.join(JWKS_URI_PATH).unwrap(),
|
||||
"prompt_values_supported": prompt_values_supported,
|
||||
"prompt_values_supported": ["create"],
|
||||
"registration_endpoint": endpoint_base.join(CLIENT_REGISTER_PATH).unwrap(),
|
||||
"response_modes_supported": ["query", "fragment"],
|
||||
"response_types_supported": ["code"],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, PduCount, Result, err};
|
||||
use ruma::{
|
||||
MilliSecondsSinceUnixEpoch,
|
||||
@@ -12,7 +13,7 @@
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `POST /_matrix/client/r0/rooms/{roomId}/read_markers`
|
||||
///
|
||||
@@ -116,7 +117,7 @@ pub(crate) async fn set_read_marker_route(
|
||||
/// Sets private read marker and public read receipt EDU.
|
||||
pub(crate) async fn create_receipt_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client_ip): ClientIp, // NOTE: Required for updating device metadata
|
||||
ClientIp(client_ip): ClientIp,
|
||||
body: Ruma<create_receipt::v3::Request>,
|
||||
) -> Result<create_receipt::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result, matrix::pdu::PartialPdu};
|
||||
use ruma::{
|
||||
api::client::redact::redact_event, assign, events::room::redaction::RoomRedactionEventContent,
|
||||
};
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `PUT /_matrix/client/r0/rooms/{roomId}/redact/{eventId}/{txnId}`
|
||||
///
|
||||
@@ -13,7 +14,7 @@
|
||||
/// - TODO: Handle txn id
|
||||
pub(crate) async fn redact_event_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client_ip): ClientIp, // NOTE: required for updating device metadata
|
||||
ClientIp(client_ip): ClientIp,
|
||||
body: Ruma<redact_event::v3::Request>,
|
||||
) -> Result<redact_event::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::{fmt::Write as _, time::Duration};
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Event, Result, debug_info, info, matrix::pdu::PduEvent, utils::ReadyExt};
|
||||
use conduwuit_service::Services;
|
||||
use ruma::{
|
||||
@@ -13,7 +14,7 @@
|
||||
};
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
struct Report {
|
||||
sender: OwnedUserId,
|
||||
@@ -29,9 +30,10 @@ struct Report {
|
||||
/// # `POST /_matrix/client/v3/rooms/{roomId}/report`
|
||||
///
|
||||
/// Reports an abusive room to homeserver admins
|
||||
#[tracing::instrument(skip_all, name = "report_room", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_room", level = "info")]
|
||||
pub(crate) async fn report_room_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<report_room::v3::Request>,
|
||||
) -> Result<report_room::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -83,9 +85,10 @@ pub(crate) async fn report_room_route(
|
||||
/// # `POST /_matrix/client/v3/rooms/{roomId}/report/{eventId}`
|
||||
///
|
||||
/// Reports an inappropriate event to homeserver admins
|
||||
#[tracing::instrument(skip_all, name = "report_event", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_event", level = "info")]
|
||||
pub(crate) async fn report_event_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<report_content::v3::Request>,
|
||||
) -> Result<report_content::v3::Response> {
|
||||
// user authentication
|
||||
@@ -126,9 +129,10 @@ pub(crate) async fn report_event_route(
|
||||
Ok(report_content::v3::Response::new())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, name = "report_user", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "report_user", level = "info")]
|
||||
pub(crate) async fn report_user_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<report_user::v3::Request>,
|
||||
) -> Result<report_user::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result};
|
||||
use ruma::api::client::room::get_summary;
|
||||
use service::rooms::summary::Accessibility;
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp, router::ClientIdentity};
|
||||
use crate::{Ruma, router::ClientIdentity};
|
||||
|
||||
/// # `GET /_matrix/client/v1/room_summary/{roomIdOrAlias}`
|
||||
///
|
||||
/// Returns a short description of the state of a room.
|
||||
#[tracing::instrument(skip_all, name = "room_summary", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "room_summary", level = "info")]
|
||||
pub(crate) async fn get_room_summary(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_summary::v1::Request>,
|
||||
) -> Result<get_summary::v1::Response> {
|
||||
let (room_id, servers) = services
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result, err, matrix::pdu::PartialPdu, utils};
|
||||
use ruma::{api::client::message::send_message_event, events::MessageLikeEventType};
|
||||
use serde_json::from_str;
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}`
|
||||
///
|
||||
@@ -18,7 +19,7 @@
|
||||
/// allowed
|
||||
pub(crate) async fn send_message_event_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client_ip): ClientIp, // NOTE: required for updating device metadata
|
||||
ClientIp(client_ip): ClientIp,
|
||||
body: Ruma<send_message_event::v3::Request>,
|
||||
) -> Result<send_message_event::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, debug, err, info,
|
||||
utils::{self, ReadyExt, stream::BroadbandExt},
|
||||
@@ -31,15 +32,16 @@
|
||||
use service::users::DeviceToken;
|
||||
|
||||
use super::DEVICE_ID_LENGTH;
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `GET /_matrix/client/v3/login`
|
||||
///
|
||||
/// Get the supported login types of this server. One of these should be used as
|
||||
/// the `type` field when logging in.
|
||||
#[tracing::instrument(skip_all, name = "login", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login", level = "info")]
|
||||
pub(crate) async fn get_login_types_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
_body: Ruma<get_login_types::v3::Request>,
|
||||
) -> Result<get_login_types::v3::Response> {
|
||||
if !services.config.oauth.compatibility_mode().uiaa_available() {
|
||||
@@ -113,10 +115,10 @@ pub async fn handle_login(
|
||||
/// Note: You can use [`GET
|
||||
/// /_matrix/client/r0/login`](fn.get_supported_versions_route.html) to see
|
||||
/// supported login types.
|
||||
#[tracing::instrument(skip_all, name = "login", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login", level = "info")]
|
||||
pub(crate) async fn login_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp, // NOTE: Required for device metadata
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<login::v3::Request>,
|
||||
) -> Result<login::v3::Response> {
|
||||
if !services.config.oauth.compatibility_mode().uiaa_available() {
|
||||
@@ -253,9 +255,10 @@ pub(crate) async fn login_route(
|
||||
/// to log in with the m.login.token flow.
|
||||
///
|
||||
/// <https://spec.matrix.org/v1.13/client-server-api/#post_matrixclientv1loginget_token>
|
||||
#[tracing::instrument(skip_all, name = "login_token", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "login_token", level = "info")]
|
||||
pub(crate) async fn login_token_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_login_token::v1::Request>,
|
||||
) -> Result<get_login_token::v1::Response> {
|
||||
if !services.config.login_via_existing_session {
|
||||
@@ -288,9 +291,10 @@ pub(crate) async fn login_token_route(
|
||||
/// last seen ts)
|
||||
/// - Forgets to-device events
|
||||
/// - Triggers device list updates
|
||||
#[tracing::instrument(skip_all, name = "logout", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "logout", level = "info")]
|
||||
pub(crate) async fn logout_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<logout::v3::Request>,
|
||||
) -> Result<logout::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -335,9 +339,10 @@ pub(crate) async fn logout_route(
|
||||
/// Note: This is equivalent to calling [`GET
|
||||
/// /_matrix/client/r0/logout`](fn.logout_route.html) from each device of this
|
||||
/// user.
|
||||
#[tracing::instrument(skip_all, name = "logout", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "logout", level = "info")]
|
||||
pub(crate) async fn logout_all_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<logout_all::v3::Request>,
|
||||
) -> Result<logout_all::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, err,
|
||||
matrix::{Event, pdu::PartialPdu},
|
||||
@@ -27,14 +28,14 @@
|
||||
};
|
||||
use serde_json::{json, value::to_raw_value};
|
||||
|
||||
use crate::{Ruma, RumaResponse, client_ip::ClientIp};
|
||||
use crate::{Ruma, RumaResponse};
|
||||
|
||||
/// # `PUT /_matrix/client/*/rooms/{roomId}/state/{eventType}/{stateKey}`
|
||||
///
|
||||
/// Sends a state event into the room.
|
||||
pub(crate) async fn send_state_event_for_key_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(ip): ClientIp, // NOTE: Required for updating device metadata
|
||||
ClientIp(ip): ClientIp,
|
||||
body: Ruma<send_state_event::v3::Request>,
|
||||
) -> Result<send_state_event::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
@@ -71,7 +72,7 @@ pub(crate) async fn send_state_event_for_key_route(
|
||||
/// Sends a state event into the room.
|
||||
pub(crate) async fn send_state_event_for_empty_key_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(ip): ClientIp, // NOTE: Required for updating device metadata
|
||||
ClientIp(ip): ClientIp,
|
||||
body: Ruma<send_state_event::v3::Request>,
|
||||
) -> Result<RumaResponse<send_state_event::v3::Response>> {
|
||||
send_state_event_for_key_route(State(services), ClientIp(ip), body)
|
||||
|
||||
@@ -269,22 +269,13 @@ async fn build_state_and_timeline(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (notification_counts, joined_since_last_sync) = try_join(
|
||||
let (state_events, notification_counts, joined_since_last_sync) = try_join3(
|
||||
build_state_events(services, sync_context, room_id, shortstatehashes, &timeline),
|
||||
build_notification_counts(services, sync_context, room_id, &timeline),
|
||||
check_joined_since_last_sync(services, shortstatehashes, sync_context),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let state_events = build_state_events(
|
||||
services,
|
||||
sync_context,
|
||||
room_id,
|
||||
shortstatehashes,
|
||||
&timeline,
|
||||
joined_since_last_sync,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// the timeline should always include at least one PDU if the syncing user
|
||||
// joined since the last sync, that being the syncing user's join event. if
|
||||
// it's empty something is wrong.
|
||||
@@ -468,7 +459,6 @@ async fn build_state_events(
|
||||
room_id: &RoomId,
|
||||
shortstatehashes: ShortStateHashes,
|
||||
timeline: &TimelinePdus,
|
||||
joined_since_last_sync: bool,
|
||||
) -> Result<Vec<PduEvent>> {
|
||||
let SyncContext {
|
||||
syncing_user,
|
||||
@@ -498,10 +488,9 @@ async fn build_state_events(
|
||||
/*
|
||||
if `last_sync_end_count` is Some (meaning this is an incremental sync), and `last_sync_end_shortstatehash`
|
||||
is Some (meaning the syncing user didn't just join this room for the first time ever), and `full_state` is false,
|
||||
and the user didn't just join the room since the last sync, then use `build_state_incremental`.
|
||||
then use `build_state_incremental`.
|
||||
*/
|
||||
| (Some(_), Some(last_sync_end_shortstatehash))
|
||||
if !full_state && !joined_since_last_sync =>
|
||||
| (Some(_), Some(last_sync_end_shortstatehash)) if !full_state =>
|
||||
build_state_incremental(
|
||||
services,
|
||||
syncing_user,
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
};
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Result, at, error, extract_variant,
|
||||
utils::{
|
||||
@@ -47,7 +48,6 @@
|
||||
is_ignored_invite,
|
||||
sync::v3::{joined::load_joined_room, left::load_left_room},
|
||||
},
|
||||
client_ip::ClientIp,
|
||||
};
|
||||
|
||||
/// The default maximum number of events to return in the `timeline` key of
|
||||
@@ -181,7 +181,7 @@ fn lazy_loading_enabled(&self) -> bool {
|
||||
)]
|
||||
pub(crate) async fn sync_events_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client_ip): ClientIp, // NOTE: Required for updating device metadata
|
||||
ClientIp(client_ip): ClientIp,
|
||||
body: Ruma<sync_events::v3::Request>,
|
||||
) -> Result<sync_events::v3::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
};
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Error, Result, at, error, extract_variant, is_equal_to,
|
||||
matrix::{Event, TypeStateKey, pdu::PduCount},
|
||||
@@ -48,7 +49,6 @@
|
||||
client::{
|
||||
DEFAULT_BUMP_TYPES, TimelinePdus, ignored_filter, is_ignored_invite, sync::load_timeline,
|
||||
},
|
||||
client_ip::ClientIp,
|
||||
};
|
||||
|
||||
type SyncInfo<'a> = (&'a UserId, &'a DeviceId, u64, &'a sync_events::v5::Request);
|
||||
@@ -67,7 +67,7 @@
|
||||
/// [MSC4186]: https://github.com/matrix-org/matrix-spec-proposals/pull/4186
|
||||
pub(crate) async fn sync_events_v5_route(
|
||||
State(ref services): State<crate::State>,
|
||||
ClientIp(client_ip): ClientIp, // NOTE: Required for updating device metadata
|
||||
ClientIp(client_ip): ClientIp,
|
||||
body: Ruma<sync_events::v5::Request>,
|
||||
) -> Result<sync_events::v5::Response> {
|
||||
let sender_user = body.identity.expect_sender_user()?;
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result, utils, utils::math::Tried};
|
||||
use ruma::api::client::typing::create_typing_event::{self, v3::TypingInfo};
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `PUT /_matrix/client/r0/rooms/{roomId}/typing/{userId}`
|
||||
///
|
||||
/// Sets the typing state of the sender user.
|
||||
pub(crate) async fn create_typing_event_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(ip): ClientIp, // NOTE: Required for updating device metadata
|
||||
ClientIp(ip): ClientIp,
|
||||
body: Ruma<create_typing_event::v3::Request>,
|
||||
) -> Result<create_typing_event::v3::Response> {
|
||||
use create_typing_event::v3::Typing;
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
};
|
||||
|
||||
use axum::extract::{ConnectInfo, FromRequestParts};
|
||||
use axum_client_ip::ClientIp as SourcedClientIp;
|
||||
use conduwuit::debug_warn;
|
||||
use http::request::Parts;
|
||||
|
||||
const UNKNOWN_IP: IpAddr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
|
||||
|
||||
/// [`ClientIp`] extractor that falls back to the connection peer address
|
||||
/// instead of rejecting the request when `request_ip_source` can't be resolved.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct ClientIp(pub IpAddr);
|
||||
|
||||
impl<S> FromRequestParts<S> for ClientIp
|
||||
where
|
||||
S: Sync,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let ip = match SourcedClientIp::from_request_parts(parts, state).await {
|
||||
| Ok(SourcedClientIp(ip)) => ip,
|
||||
| Err(rejection) => {
|
||||
debug_warn!(
|
||||
%rejection,
|
||||
"Could not resolve client IP from request_ip_source; using peer address"
|
||||
);
|
||||
parts
|
||||
.extensions
|
||||
.get::<ConnectInfo<SocketAddr>>()
|
||||
.map_or(UNKNOWN_IP, |ConnectInfo(addr)| addr.ip())
|
||||
},
|
||||
};
|
||||
|
||||
Ok(Self(ip))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::net::Ipv6Addr;
|
||||
|
||||
use axum_client_ip::ClientIpSource;
|
||||
|
||||
use super::*;
|
||||
|
||||
const PEER: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(198, 51, 100, 7)), 8448);
|
||||
const PEER_V6: SocketAddr =
|
||||
SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0x2001, 0xDB8, 0, 0, 0, 0, 0, 1)), 8448);
|
||||
|
||||
fn parts(
|
||||
source: Option<ClientIpSource>,
|
||||
peer: Option<SocketAddr>,
|
||||
headers: &[(&str, &str)],
|
||||
) -> Parts {
|
||||
let mut builder = http::Request::builder();
|
||||
for (name, value) in headers {
|
||||
builder = builder.header(*name, *value);
|
||||
}
|
||||
|
||||
let (mut parts, ()) = builder.body(()).unwrap().into_parts();
|
||||
if let Some(source) = source {
|
||||
parts.extensions.insert(source);
|
||||
}
|
||||
if let Some(peer) = peer {
|
||||
parts.extensions.insert(ConnectInfo(peer));
|
||||
}
|
||||
|
||||
parts
|
||||
}
|
||||
|
||||
async fn extract(mut parts: Parts) -> IpAddr {
|
||||
let ClientIp(ip) = ClientIp::from_request_parts(&mut parts, &()).await.unwrap();
|
||||
ip
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn resolves_from_configured_source() {
|
||||
let parts =
|
||||
parts(Some(ClientIpSource::XRealIp), Some(PEER), &[("x-real-ip", "203.0.113.5")]);
|
||||
|
||||
assert_eq!(extract(parts).await, IpAddr::V4(Ipv4Addr::new(203, 0, 113, 5)));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn resolves_ipv6_from_configured_source() {
|
||||
let parts =
|
||||
parts(Some(ClientIpSource::XRealIp), Some(PEER), &[("x-real-ip", "2001:db8::2")]);
|
||||
|
||||
assert_eq!(
|
||||
extract(parts).await,
|
||||
IpAddr::V6(Ipv6Addr::new(0x2001, 0xDB8, 0, 0, 0, 0, 0, 2))
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn falls_back_to_peer_when_header_missing() {
|
||||
let parts = parts(Some(ClientIpSource::XRealIp), Some(PEER), &[]);
|
||||
|
||||
assert_eq!(extract(parts).await, PEER.ip());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn falls_back_to_ipv6_peer_when_header_missing() {
|
||||
let parts = parts(Some(ClientIpSource::XRealIp), Some(PEER_V6), &[]);
|
||||
|
||||
assert_eq!(extract(parts).await, PEER_V6.ip());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn falls_back_to_peer_when_header_unparsable() {
|
||||
let parts =
|
||||
parts(Some(ClientIpSource::XRealIp), Some(PEER), &[("x-real-ip", "not-an-ip")]);
|
||||
|
||||
assert_eq!(extract(parts).await, PEER.ip());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn falls_back_to_peer_when_source_unset() {
|
||||
let parts = parts(None, Some(PEER), &[("x-real-ip", "203.0.113.5")]);
|
||||
|
||||
assert_eq!(extract(parts).await, PEER.ip());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn falls_back_to_unspecified_without_peer() {
|
||||
let parts = parts(Some(ClientIpSource::XRealIp), None, &[]);
|
||||
|
||||
assert_eq!(extract(parts).await, UNKNOWN_IP);
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,6 @@
|
||||
pub mod router;
|
||||
pub mod server;
|
||||
|
||||
pub(crate) mod client_ip;
|
||||
|
||||
pub mod admin;
|
||||
|
||||
pub(crate) use self::router::{Ruma, RumaResponse, State};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::collections::{HashMap, hash_map::Entry};
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use base64::{Engine as _, engine::general_purpose};
|
||||
use conduwuit::{
|
||||
Err, Error, EventTypeExt, PduEvent, Result, debug, err, error,
|
||||
@@ -22,14 +23,15 @@
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp, server::utils::validate_any_membership_event};
|
||||
use crate::{Ruma, server::utils::validate_any_membership_event};
|
||||
|
||||
/// # `PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`
|
||||
///
|
||||
/// Invites a remote user to a room.
|
||||
#[tracing::instrument(skip_all, name = "invite", level = "info")]
|
||||
#[tracing::instrument(skip_all, fields(%client), name = "invite", level = "info")]
|
||||
pub(crate) async fn create_invite_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<create_invite::v2::Request>,
|
||||
) -> Result<create_invite::v2::Response> {
|
||||
if !services.server.supported_room_version(&body.room_version) {
|
||||
|
||||
+16
-3
@@ -1,4 +1,5 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result, utils::content_disposition::make_content_disposition};
|
||||
use conduwuit_service::media::{Dim, FileMeta};
|
||||
use ruma::api::federation::authenticated_media::{
|
||||
@@ -6,14 +7,20 @@
|
||||
};
|
||||
use service::media::mxc::Mxc;
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `GET /_matrix/federation/v1/media/download/{mediaId}`
|
||||
///
|
||||
/// Load media from our server.
|
||||
#[tracing::instrument(name = "media_get", level = "debug", skip_all)]
|
||||
#[tracing::instrument(
|
||||
name = "media_get",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client)
|
||||
)]
|
||||
pub(crate) async fn get_content_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content::v1::Request>,
|
||||
) -> Result<get_content::v1::Response> {
|
||||
let mxc = Mxc {
|
||||
@@ -47,9 +54,15 @@ pub(crate) async fn get_content_route(
|
||||
/// # `GET /_matrix/federation/v1/media/thumbnail/{mediaId}`
|
||||
///
|
||||
/// Load media thumbnail from our server.
|
||||
#[tracing::instrument(name = "media_thumbnail_get", level = "debug", skip_all)]
|
||||
#[tracing::instrument(
|
||||
name = "media_thumbnail_get",
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%client)
|
||||
)]
|
||||
pub(crate) async fn get_content_thumbnail_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_content_thumbnail::v1::Request>,
|
||||
) -> Result<get_content_thumbnail::v1::Response> {
|
||||
let dim = Dim::from_ruma(body.width, body.height, body.method.clone())?;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{Err, Result, err};
|
||||
use ruma::{
|
||||
api::federation::directory::{get_public_rooms, get_public_rooms_filtered},
|
||||
@@ -6,14 +7,15 @@
|
||||
directory::Filter,
|
||||
};
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
/// # `POST /_matrix/federation/v1/publicRooms`
|
||||
///
|
||||
/// Lists the public rooms on this server.
|
||||
#[tracing::instrument(name = "publicrooms", level = "debug", skip_all)]
|
||||
#[tracing::instrument(name = "publicrooms", level = "debug", skip_all, fields(%client))]
|
||||
pub(crate) async fn get_public_rooms_filtered_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_public_rooms_filtered::v1::Request>,
|
||||
) -> Result<get_public_rooms_filtered::v1::Response> {
|
||||
if !services
|
||||
@@ -46,9 +48,10 @@ pub(crate) async fn get_public_rooms_filtered_route(
|
||||
/// # `GET /_matrix/federation/v1/publicRooms`
|
||||
///
|
||||
/// Lists the public rooms on this server.
|
||||
#[tracing::instrument(name = "publicrooms", level = "debug", skip_all)]
|
||||
#[tracing::instrument(name = "publicrooms", level = "debug", skip_all, fields(%client))]
|
||||
pub(crate) async fn get_public_rooms_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<get_public_rooms::v1::Request>,
|
||||
) -> Result<get_public_rooms::v1::Response> {
|
||||
if !services
|
||||
|
||||
+34
-14
@@ -1,9 +1,11 @@
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
net::IpAddr,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::ClientIp;
|
||||
use conduwuit::{
|
||||
Err, Error, Result, debug, debug_error, debug_warn, err, error,
|
||||
result::LogErr,
|
||||
@@ -45,7 +47,7 @@
|
||||
use tokio::sync::watch::{Receiver, Sender};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::{Ruma, client_ip::ClientIp};
|
||||
use crate::Ruma;
|
||||
|
||||
type ResolvedMap = BTreeMap<OwnedEventId, Result>;
|
||||
type Pdu = (OwnedRoomId, OwnedEventId, CanonicalJsonObject);
|
||||
@@ -55,6 +57,7 @@
|
||||
/// Push EDUs and PDUs to this server.
|
||||
pub(crate) async fn send_transaction_message_route(
|
||||
State(services): State<crate::State>,
|
||||
ClientIp(client): ClientIp,
|
||||
body: Ruma<send_transaction_message::v1::Request>,
|
||||
) -> Result<send_transaction_message::v1::Response> {
|
||||
if body.identity != body.body.origin {
|
||||
@@ -95,7 +98,7 @@ pub(crate) async fn send_transaction_message_route(
|
||||
services
|
||||
.server
|
||||
.runtime()
|
||||
.spawn(process_inbound_transaction(services, body, txn_key, sender));
|
||||
.spawn(process_inbound_transaction(services, body, client, txn_key, sender));
|
||||
// and wait for it
|
||||
wait_for_result(receiver).await
|
||||
},
|
||||
@@ -138,6 +141,7 @@ async fn wait_for_result(
|
||||
async fn process_inbound_transaction(
|
||||
services: crate::State,
|
||||
body: Ruma<send_transaction_message::v1::Request>,
|
||||
client: IpAddr,
|
||||
txn_key: TxnKey,
|
||||
sender: Sender<WrappedTransactionResponse>,
|
||||
) {
|
||||
@@ -159,7 +163,7 @@ async fn process_inbound_transaction(
|
||||
.stream();
|
||||
|
||||
debug!(pdus = body.pdus.len(), edus = body.edus.len(), "Processing transaction",);
|
||||
let results = match handle(&services, &body.identity, pdus, edus).await {
|
||||
let results = match handle(&services, &client, &body.identity, pdus, edus).await {
|
||||
| Ok(results) => results,
|
||||
| Err(err) => {
|
||||
fail_federation_txn(services, &txn_key, &sender, err);
|
||||
@@ -232,6 +236,7 @@ fn transaction_error_to_response(err: &TransactionError) -> Error {
|
||||
}
|
||||
async fn handle(
|
||||
services: &Services,
|
||||
client: &IpAddr,
|
||||
origin: &ServerName,
|
||||
pdus: impl Stream<Item = Pdu> + Send,
|
||||
edus: impl Stream<Item = Edu> + Send,
|
||||
@@ -252,7 +257,7 @@ async fn handle(
|
||||
.into_iter()
|
||||
.try_stream()
|
||||
.broad_and_then(|(room_id, pdus): (_, Vec<_>)| {
|
||||
handle_room(services, origin, room_id, pdus.into_iter())
|
||||
handle_room(services, client, origin, room_id, pdus.into_iter())
|
||||
.map_ok(Vec::into_iter)
|
||||
.map_ok(IterStream::try_stream)
|
||||
})
|
||||
@@ -262,7 +267,7 @@ async fn handle(
|
||||
.await?;
|
||||
|
||||
// Evaluate EDUs after PDUs in case some of the PDUs then forbid some EDUs.
|
||||
edus.for_each_concurrent(automatic_width(), |edu| handle_edu(services, origin, edu))
|
||||
edus.for_each_concurrent(automatic_width(), |edu| handle_edu(services, client, origin, edu))
|
||||
.boxed()
|
||||
.await;
|
||||
|
||||
@@ -271,6 +276,7 @@ async fn handle(
|
||||
|
||||
async fn handle_room(
|
||||
services: &Services,
|
||||
_client: &IpAddr,
|
||||
origin: &ServerName,
|
||||
room_id: OwnedRoomId,
|
||||
pdus: impl Iterator<Item = Pdu> + Send,
|
||||
@@ -317,25 +323,25 @@ async fn handle_room(
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
async fn handle_edu(services: &Services, origin: &ServerName, edu: Edu) {
|
||||
async fn handle_edu(services: &Services, client: &IpAddr, origin: &ServerName, edu: Edu) {
|
||||
match edu {
|
||||
| Edu::Presence(presence) if services.server.config.allow_incoming_presence =>
|
||||
handle_edu_presence(services, origin, presence).await,
|
||||
handle_edu_presence(services, client, origin, presence).await,
|
||||
|
||||
| Edu::Receipt(receipt) if services.server.config.allow_incoming_read_receipts =>
|
||||
handle_edu_receipt(services, origin, receipt).await,
|
||||
handle_edu_receipt(services, client, origin, receipt).await,
|
||||
|
||||
| Edu::Typing(typing) if services.server.config.allow_incoming_typing =>
|
||||
handle_edu_typing(services, origin, typing).await,
|
||||
handle_edu_typing(services, client, origin, typing).await,
|
||||
|
||||
| Edu::DeviceListUpdate(content) =>
|
||||
handle_edu_device_list_update(services, origin, content).await,
|
||||
handle_edu_device_list_update(services, client, origin, content).await,
|
||||
|
||||
| Edu::DirectToDevice(content) =>
|
||||
handle_edu_direct_to_device(services, origin, content).await,
|
||||
handle_edu_direct_to_device(services, client, origin, content).await,
|
||||
|
||||
| Edu::SigningKeyUpdate(content) =>
|
||||
handle_edu_signing_key_update(services, origin, content).await,
|
||||
handle_edu_signing_key_update(services, client, origin, content).await,
|
||||
|
||||
| Edu::_Custom(ref _custom) => debug_warn!(?edu, "received custom/unknown EDU"),
|
||||
|
||||
@@ -345,6 +351,7 @@ async fn handle_edu(services: &Services, origin: &ServerName, edu: Edu) {
|
||||
|
||||
async fn handle_edu_presence(
|
||||
services: &Services,
|
||||
_client: &IpAddr,
|
||||
origin: &ServerName,
|
||||
presence: PresenceContent,
|
||||
) {
|
||||
@@ -385,7 +392,12 @@ async fn handle_edu_presence_update(
|
||||
.ok();
|
||||
}
|
||||
|
||||
async fn handle_edu_receipt(services: &Services, origin: &ServerName, receipt: ReceiptContent) {
|
||||
async fn handle_edu_receipt(
|
||||
services: &Services,
|
||||
_client: &IpAddr,
|
||||
origin: &ServerName,
|
||||
receipt: ReceiptContent,
|
||||
) {
|
||||
receipt
|
||||
.receipts
|
||||
.into_iter()
|
||||
@@ -480,7 +492,12 @@ async fn handle_edu_receipt_room_user(
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn handle_edu_typing(services: &Services, origin: &ServerName, typing: TypingContent) {
|
||||
async fn handle_edu_typing(
|
||||
services: &Services,
|
||||
_client: &IpAddr,
|
||||
origin: &ServerName,
|
||||
typing: TypingContent,
|
||||
) {
|
||||
if typing.user_id.server_name() != origin {
|
||||
debug_warn!(
|
||||
%typing.user_id, %origin,
|
||||
@@ -540,6 +557,7 @@ async fn handle_edu_typing(services: &Services, origin: &ServerName, typing: Typ
|
||||
|
||||
async fn handle_edu_device_list_update(
|
||||
services: &Services,
|
||||
_client: &IpAddr,
|
||||
origin: &ServerName,
|
||||
content: DeviceListUpdateContent,
|
||||
) {
|
||||
@@ -558,6 +576,7 @@ async fn handle_edu_device_list_update(
|
||||
|
||||
async fn handle_edu_direct_to_device(
|
||||
services: &Services,
|
||||
_client: &IpAddr,
|
||||
origin: &ServerName,
|
||||
content: DirectDeviceContent,
|
||||
) {
|
||||
@@ -677,6 +696,7 @@ async fn handle_edu_direct_to_device_event(
|
||||
|
||||
async fn handle_edu_signing_key_update(
|
||||
services: &Services,
|
||||
_client: &IpAddr,
|
||||
origin: &ServerName,
|
||||
content: SigningKeyUpdateContent,
|
||||
) {
|
||||
|
||||
+1
-32
@@ -91,7 +91,7 @@ pub(crate) async fn validate_any_membership_event(
|
||||
expected_room_id: OwnedRoomId,
|
||||
expected_event_id: OwnedEventId,
|
||||
) -> Result<(CanonicalJsonObject, MembershipState, OwnedUserId, OwnedUserId)> {
|
||||
let (template_room_id, template_event_id, mut pdu) = services
|
||||
let (template_room_id, template_event_id, pdu) = services
|
||||
.rooms
|
||||
.event_handler
|
||||
.parse_incoming_pdu(body, Some(room_version_rules))
|
||||
@@ -109,37 +109,6 @@ pub(crate) async fn validate_any_membership_event(
|
||||
))));
|
||||
}
|
||||
|
||||
// Only `join` events carry `join_authorised_via_users_server`; co-sign
|
||||
// restricted joins so verification passes. Authorisation is enforced in
|
||||
// create_join_event.
|
||||
let membership_is_join = pdu
|
||||
.get("content")
|
||||
.and_then(|v| v.as_object())
|
||||
.and_then(|c| c.get("membership"))
|
||||
.and_then(|v| v.as_str())
|
||||
.is_some_and(|m| m == "join");
|
||||
|
||||
let authorising_user = pdu
|
||||
.get("content")
|
||||
.and_then(|v| v.as_object())
|
||||
.and_then(|c| c.get("join_authorised_via_users_server"))
|
||||
.and_then(|v| v.as_str())
|
||||
.map(UserId::parse)
|
||||
.and_then(Result::ok);
|
||||
|
||||
if room_version_rules.authorization.restricted_join_rule
|
||||
&& membership_is_join
|
||||
&& let Some(authorising_user) = authorising_user
|
||||
&& services.globals.user_is_local(&authorising_user)
|
||||
{
|
||||
services
|
||||
.server_keys
|
||||
.hash_and_sign_event(&mut pdu, room_version_rules)
|
||||
.map_err(|e| {
|
||||
err!(Request(InvalidParam("Failed to sign restricted join event: {e}")))
|
||||
})?;
|
||||
}
|
||||
|
||||
services
|
||||
.server_keys
|
||||
.verify_event(&pdu, room_version_rules)
|
||||
|
||||
+8
-22
@@ -1,10 +1,10 @@
|
||||
use std::{any::Any, sync::Arc, time::Duration};
|
||||
|
||||
use axum::{
|
||||
Router, extract,
|
||||
extract::{DefaultBodyLimit, FromRequestParts, MatchedPath},
|
||||
Router,
|
||||
extract::{DefaultBodyLimit, MatchedPath},
|
||||
};
|
||||
use axum_client_ip::{ClientIp, ClientIpSource};
|
||||
use axum_client_ip::ClientIpSource;
|
||||
use conduwuit::{Result, Server, debug, error};
|
||||
use conduwuit_service::{Services, state::Guard};
|
||||
use http::{
|
||||
@@ -20,6 +20,7 @@
|
||||
timeout::{RequestBodyTimeoutLayer, ResponseBodyTimeoutLayer, TimeoutLayer},
|
||||
trace::{DefaultOnFailure, DefaultOnRequest, DefaultOnResponse, TraceLayer},
|
||||
};
|
||||
use tracing::Level;
|
||||
|
||||
use crate::{request, router};
|
||||
|
||||
@@ -66,16 +67,15 @@ pub(crate) fn build(services: &Arc<Services>) -> Result<(Router, Guard)> {
|
||||
let services_ = services.clone();
|
||||
let layers = layers
|
||||
.layer(SetSensitiveHeadersLayer::new([header::AUTHORIZATION]))
|
||||
.layer(client_ip_layer.into_extension())
|
||||
.layer(
|
||||
TraceLayer::new_for_http()
|
||||
.make_span_with(tracing_span::<_>)
|
||||
.on_failure(DefaultOnFailure::new().level(tracing::Level::ERROR))
|
||||
.on_request(DefaultOnRequest::new().level(tracing::Level::TRACE))
|
||||
.on_response(DefaultOnResponse::new().level(tracing::Level::DEBUG)),
|
||||
.on_failure(DefaultOnFailure::new().level(Level::ERROR))
|
||||
.on_request(DefaultOnRequest::new().level(Level::TRACE))
|
||||
.on_response(DefaultOnResponse::new().level(Level::DEBUG)),
|
||||
)
|
||||
.layer(axum::middleware::from_fn(request_ip))
|
||||
.layer(axum::middleware::from_fn_with_state(Arc::clone(services), request::handle))
|
||||
.layer(client_ip_layer.into_extension())
|
||||
.layer(ResponseBodyTimeoutLayer::new(Duration::from_secs(
|
||||
server.config.client_response_timeout,
|
||||
)))
|
||||
@@ -230,25 +230,11 @@ fn tracing_span<T>(request: &http::Request<T>) -> tracing::Span {
|
||||
parent: None,
|
||||
debug::INFO_SPAN_LEVEL,
|
||||
"router",
|
||||
ip=tracing::field::Empty,
|
||||
method = %request.method(),
|
||||
%path,
|
||||
}
|
||||
}
|
||||
|
||||
/// Annotates the tracing span with the client IP
|
||||
async fn request_ip(
|
||||
request: extract::Request,
|
||||
next: axum::middleware::Next,
|
||||
) -> axum::response::Response {
|
||||
let (mut parts, body) = request.into_parts();
|
||||
if let Ok(ip) = ClientIp::from_request_parts(&mut parts, &()).await {
|
||||
let span = tracing::Span::current();
|
||||
span.record("ip", ip.0.to_string());
|
||||
}
|
||||
next.run(extract::Request::from_parts(parts, body)).await
|
||||
}
|
||||
|
||||
fn request_path_str<T>(request: &http::Request<T>) -> &str {
|
||||
request
|
||||
.uri()
|
||||
|
||||
+7
-89
@@ -5,7 +5,6 @@
|
||||
};
|
||||
|
||||
use conduwuit::{Err, Error, Result, error, utils};
|
||||
use futures::StreamExt;
|
||||
use lettre::Address;
|
||||
use ruma::{
|
||||
DeviceId, UserId,
|
||||
@@ -26,7 +25,7 @@
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{
|
||||
Dep, config, firstrun, globals,
|
||||
Dep, config, globals,
|
||||
oauth::{self, OAuthTicket},
|
||||
registration_tokens, threepid, users,
|
||||
};
|
||||
@@ -37,54 +36,25 @@ pub struct Service {
|
||||
}
|
||||
|
||||
struct Services {
|
||||
config: Dep<config::Service>,
|
||||
firstrun: Dep<firstrun::Service>,
|
||||
globals: Dep<globals::Service>,
|
||||
oauth: Dep<oauth::Service>,
|
||||
users: Dep<users::Service>,
|
||||
config: Dep<config::Service>,
|
||||
registration_tokens: Dep<registration_tokens::Service>,
|
||||
threepid: Dep<threepid::Service>,
|
||||
users: Dep<users::Service>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TrustedFlowStatus {
|
||||
Unavailable,
|
||||
Available,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UntrustedFlowStatus {
|
||||
Unavailable,
|
||||
Available {
|
||||
require_email: bool,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct FlowStatus {
|
||||
pub trusted: TrustedFlowStatus,
|
||||
pub untrusted: UntrustedFlowStatus,
|
||||
}
|
||||
|
||||
impl FlowStatus {
|
||||
#[must_use]
|
||||
pub fn any_available(&self) -> bool {
|
||||
matches!(self.trusted, TrustedFlowStatus::Available)
|
||||
|| matches!(self.untrusted, UntrustedFlowStatus::Available { .. })
|
||||
}
|
||||
oauth: Dep<oauth::Service>,
|
||||
}
|
||||
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
services: Services {
|
||||
config: args.depend::<config::Service>("config"),
|
||||
firstrun: args.depend::<firstrun::Service>("firstrun"),
|
||||
globals: args.depend::<globals::Service>("globals"),
|
||||
oauth: args.depend::<oauth::Service>("oauth"),
|
||||
users: args.depend::<users::Service>("users"),
|
||||
config: args.depend::<config::Service>("config"),
|
||||
registration_tokens: args
|
||||
.depend::<registration_tokens::Service>("registration_tokens"),
|
||||
threepid: args.depend::<threepid::Service>("threepid"),
|
||||
users: args.depend::<users::Service>("users"),
|
||||
oauth: args.depend::<oauth::Service>("oauth"),
|
||||
},
|
||||
uiaa_sessions: Mutex::new(HashMap::new()),
|
||||
}))
|
||||
@@ -625,56 +595,4 @@ async fn check_stage(
|
||||
|
||||
Ok((completed_auth_type, session_metadata))
|
||||
}
|
||||
|
||||
pub async fn registration_flow_status(&self) -> FlowStatus {
|
||||
// Allow registration if it's enabled in the config file or if this is the first
|
||||
// run (so the first user account can be created)
|
||||
let allow_registration =
|
||||
self.services.config.allow_registration || self.services.firstrun.is_first_run();
|
||||
|
||||
// Trusted flow is only available if any registration tokens exist
|
||||
let trusted = {
|
||||
if !allow_registration {
|
||||
TrustedFlowStatus::Unavailable
|
||||
} else if self
|
||||
.services
|
||||
.registration_tokens
|
||||
.iterate_tokens()
|
||||
.next()
|
||||
.await
|
||||
.is_some()
|
||||
{
|
||||
TrustedFlowStatus::Available
|
||||
} else {
|
||||
TrustedFlowStatus::Unavailable
|
||||
}
|
||||
};
|
||||
|
||||
// Untrusted flow is available if email is required for registration,
|
||||
// or reCAPTCHA is configured, or open registration is enabled
|
||||
let untrusted = {
|
||||
let require_email = self
|
||||
.services
|
||||
.config
|
||||
.smtp
|
||||
.as_ref()
|
||||
.is_some_and(|smtp| smtp.require_email_for_registration);
|
||||
|
||||
if !allow_registration || self.services.firstrun.is_first_run() {
|
||||
UntrustedFlowStatus::Unavailable
|
||||
} else if self.services.config.recaptcha_private_site_key.is_some() || require_email {
|
||||
UntrustedFlowStatus::Available { require_email }
|
||||
} else if self
|
||||
.services
|
||||
.config
|
||||
.yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse
|
||||
{
|
||||
UntrustedFlowStatus::Available { require_email: false }
|
||||
} else {
|
||||
UntrustedFlowStatus::Unavailable
|
||||
}
|
||||
};
|
||||
|
||||
FlowStatus { trusted, untrusted }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,6 +253,8 @@ pub async fn remove_to_device_events<Until>(
|
||||
self.db.todeviceid_events.del(key);
|
||||
})
|
||||
.await;
|
||||
|
||||
self.services.sync.wake(user_id).await;
|
||||
}
|
||||
|
||||
/// Updates device metadata and increments the device list version.
|
||||
|
||||
@@ -109,7 +109,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
services: Services {
|
||||
account_data: args.depend::<account_data::Service>("account_data"),
|
||||
admin: args.depend::<admin::Service>("admin"),
|
||||
alias: args.depend::<alias::Service>("rooms::alias"),
|
||||
alias: args.depend::<alias::Service>("alias"),
|
||||
appservice: args.depend::<appservice::Service>("appservice"),
|
||||
config: args.depend::<config::Service>("config"),
|
||||
firstrun: args.depend::<firstrun::Service>("firstrun"),
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
extract::{Expect, PostForm},
|
||||
pages::{
|
||||
GET_POST, Result, TemplateContext,
|
||||
account::register::{TrustedFlowStatus, UntrustedFlowStatus, registration_flow_status},
|
||||
components::UserCard,
|
||||
oidc::{OIDC_SESSION_ID_KEY, OidcSession, OidcSessionState},
|
||||
},
|
||||
@@ -100,13 +101,13 @@ async fn route_login(
|
||||
|
||||
LoginType::Oidc { redirect_url }
|
||||
} else {
|
||||
LoginType::Interactive {
|
||||
registration_available: services
|
||||
.uiaa
|
||||
.registration_flow_status()
|
||||
.await
|
||||
.any_available(),
|
||||
}
|
||||
let (trusted_flow_status, untrusted_flow_status) =
|
||||
registration_flow_status(&services).await;
|
||||
|
||||
let registration_available = matches!(trusted_flow_status, TrustedFlowStatus::Available)
|
||||
|| matches!(untrusted_flow_status, UntrustedFlowStatus::Available { .. });
|
||||
|
||||
LoginType::Interactive { registration_available }
|
||||
};
|
||||
|
||||
let body = match &user_id {
|
||||
|
||||
@@ -8,12 +8,9 @@
|
||||
};
|
||||
use conduwuit_core::{config::TermsDocument, warn};
|
||||
use conduwuit_service::{
|
||||
mailer::messages,
|
||||
registration_tokens::ValidToken,
|
||||
uiaa::{FlowStatus, TrustedFlowStatus, UntrustedFlowStatus},
|
||||
users::HashedPassword,
|
||||
mailer::messages, registration_tokens::ValidToken, users::HashedPassword,
|
||||
};
|
||||
use futures::FutureExt;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use lettre::{Address, message::Mailbox};
|
||||
use ruma::{ClientSecret, OwnedClientSecret, OwnedServerName, OwnedSessionId, OwnedUserId};
|
||||
use serde::{Deserialize, Serialize, de::IgnoredAny};
|
||||
@@ -64,6 +61,20 @@ enum RegisterBody {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) enum TrustedFlowStatus {
|
||||
Unavailable,
|
||||
Available,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) enum UntrustedFlowStatus {
|
||||
Unavailable,
|
||||
Available {
|
||||
require_email: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
pub(crate) struct RegisterQuery {
|
||||
pub username: Option<String>,
|
||||
@@ -158,10 +169,7 @@ async fn route_register(
|
||||
ValidationErrors::new()
|
||||
};
|
||||
|
||||
let FlowStatus {
|
||||
trusted: trusted_flow_status,
|
||||
untrusted: untrusted_flow_status,
|
||||
} = services.uiaa.registration_flow_status().await;
|
||||
let (trusted_flow_status, untrusted_flow_status) = registration_flow_status(&services).await;
|
||||
|
||||
if matches!(trusted_flow_status, TrustedFlowStatus::Unavailable)
|
||||
&& matches!(untrusted_flow_status, UntrustedFlowStatus::Unavailable)
|
||||
@@ -532,3 +540,54 @@ async fn complete_registration(
|
||||
|
||||
Ok(Redirect::to(&next.unwrap_or_default().target_path()))
|
||||
}
|
||||
|
||||
pub(super) async fn registration_flow_status(
|
||||
services: &crate::State,
|
||||
) -> (TrustedFlowStatus, UntrustedFlowStatus) {
|
||||
// Allow registration if it's enabled in the config file or if this is the first
|
||||
// run (so the first user account can be created)
|
||||
let allow_registration =
|
||||
services.config.allow_registration || services.firstrun.is_first_run();
|
||||
|
||||
// Trusted flow is only available if any registration tokens exist
|
||||
let trusted_flow_status = {
|
||||
if !allow_registration {
|
||||
TrustedFlowStatus::Unavailable
|
||||
} else if services
|
||||
.registration_tokens
|
||||
.iterate_tokens()
|
||||
.next()
|
||||
.await
|
||||
.is_some()
|
||||
{
|
||||
TrustedFlowStatus::Available
|
||||
} else {
|
||||
TrustedFlowStatus::Unavailable
|
||||
}
|
||||
};
|
||||
|
||||
// Untrusted flow is available if email is required for registration,
|
||||
// or reCAPTCHA is configured, or open registration is enabled
|
||||
let untrusted_flow_status = {
|
||||
let require_email = services
|
||||
.config
|
||||
.smtp
|
||||
.as_ref()
|
||||
.is_some_and(|smtp| smtp.require_email_for_registration);
|
||||
|
||||
if !allow_registration || services.firstrun.is_first_run() {
|
||||
UntrustedFlowStatus::Unavailable
|
||||
} else if services.config.recaptcha_private_site_key.is_some() || require_email {
|
||||
UntrustedFlowStatus::Available { require_email }
|
||||
} else if services
|
||||
.config
|
||||
.yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse
|
||||
{
|
||||
UntrustedFlowStatus::Available { require_email: false }
|
||||
} else {
|
||||
UntrustedFlowStatus::Unavailable
|
||||
}
|
||||
};
|
||||
|
||||
(trusted_flow_status, untrusted_flow_status)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user