diff --git a/.config/nextest.toml b/.config/nextest.toml new file mode 100644 index 000000000..428b597a6 --- /dev/null +++ b/.config/nextest.toml @@ -0,0 +1,14 @@ +[test-groups] +database = { max-threads = 1 } + +[profile.default] +retries = 1 + +# sqlx has a problem with nextest, as it uses a process-local semaphore to have +# tests use different databases. This doesn't work with nextest, as it has a +# process-per-test model, which is why we need to make sure only one test uses +# the database at a time. +# See https://github.com/launchbadge/sqlx/pull/3334 +[[profile.default.overrides]] +filter = 'package(mas-handlers) or package(mas-storage-pg)' +test-group = 'database' diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index ccc906658..e830cd90a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -61,7 +61,9 @@ jobs: version: 0.13.0 - name: Install cargo-zigbuild - run: curl -L https://github.com/rust-cross/cargo-zigbuild/releases/download/v0.19.1/cargo-zigbuild-v0.19.1.x86_64-unknown-linux-musl.tar.gz | tar -z -x -C /usr/local/bin + uses: taiki-e/install-action@v2 + with: + tool: cargo-zigbuild - name: Install frontend Node uses: actions/setup-node@v4.1.0 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3b2a6cbb8..7a10fa72a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -263,7 +263,9 @@ jobs: rustup default stable - name: Install nextest - uses: taiki-e/install-action@nextest + uses: taiki-e/install-action@v2 + with: + tool: cargo-nextest - name: Setup sccache uses: mozilla-actions/sccache-action@v0.0.7 @@ -290,7 +292,7 @@ jobs: strategy: matrix: - partition: [1, 2] + partition: [1, 2, 3] services: postgres: @@ -313,7 +315,9 @@ jobs: - run: mkdir -p ~/.cargo/bin - name: Install nextest - uses: taiki-e/install-action@nextest + uses: taiki-e/install-action@v2 + with: + tool: cargo-nextest - name: Install Node uses: actions/setup-node@v4.1.0 @@ -346,11 +350,9 @@ jobs: env: DATABASE_URL: postgresql://postgres:postgres@localhost/postgres run: | - ~/.cargo/bin/cargo-nextest nextest run --archive-file nextest-archive.tar.zst \ - --partition count:${{ matrix.partition }}/2 \ - --retries 1 - # --retries is a workaround for sqlx not playing nice with nextest - # Waiting for https://github.com/launchbadge/sqlx/pull/3334 + ~/.cargo/bin/cargo-nextest nextest run \ + --archive-file nextest-archive.tar.zst \ + --partition count:${{ matrix.partition }}/3 syn2mas: name: Check syn2mas diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 98d3a47a4..625458f7a 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -141,11 +141,10 @@ jobs: - name: Setup sccache uses: mozilla-actions/sccache-action@v0.0.7 - - name: Download grcov - run: | - mkdir -p "${HOME}/.local/bin" - curl -sL https://github.com/mozilla/grcov/releases/download/v0.8.19/grcov-x86_64-unknown-linux-gnu.tar.bz2 | tar jxf - -C "${HOME}/.local/bin" - echo "$HOME/.local/bin" >> $GITHUB_PATH + - name: Install grcov + uses: taiki-e/install-action@v2 + with: + tool: grcov - name: Run test suite with profiling enabled run: | diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index f663f34fa..28a21ebb6 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -30,10 +30,10 @@ jobs: - name: Setup sccache uses: mozilla-actions/sccache-action@v0.0.7 - - name: Setup mdBook - uses: peaceiris/actions-mdbook@v2.0.0 + - name: Install mdbook + uses: taiki-e/install-action@v2 with: - mdbook-version: '0.4.37' + tool: mdbook - name: Install Node uses: actions/setup-node@v4.1.0 diff --git a/Cargo.lock b/Cargo.lock index aec8c14da..75432ebf2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3105,15 +3105,10 @@ dependencies = [ "async-trait", "axum", "axum-extra", - "bytes", "chrono", "data-encoding", - "futures-util", "headers", "http", - "http-body", - "http-body-util", - "hyper-util", "icu_locid", "mas-data-model", "mas-http", @@ -3129,11 +3124,9 @@ dependencies = [ "sentry", "serde", "serde_json", - "serde_urlencoded", "serde_with", "thiserror 2.0.9", "tokio", - "tower", "tracing", "ulid", "url", @@ -3152,10 +3145,7 @@ dependencies = [ "dialoguer", "dotenvy", "figment", - "http", - "http-body", "http-body-util", - "httpdate", "hyper", "ipnetwork", "itertools 0.13.0", @@ -3166,20 +3156,17 @@ dependencies = [ "mas-handlers", "mas-http", "mas-i18n", - "mas-iana", "mas-keystore", "mas-listener", "mas-matrix", "mas-matrix-synapse", "mas-policy", "mas-router", - "mas-spa", "mas-storage", "mas-storage-pg", "mas-tasks", "mas-templates", "mas-tower", - "oauth2-types", "opentelemetry", "opentelemetry-http", "opentelemetry-jaeger-propagator", @@ -3237,7 +3224,6 @@ dependencies = [ "serde", "serde_json", "serde_with", - "thiserror 2.0.9", "tokio", "tracing", "ulid", @@ -3248,6 +3234,7 @@ dependencies = [ name = "mas-data-model" version = "0.12.0" dependencies = [ + "base64ct", "chrono", "crc", "mas-iana", @@ -3270,7 +3257,6 @@ name = "mas-email" version = "0.12.0" dependencies = [ "async-trait", - "headers", "lettre", "mas-templates", "thiserror 2.0.9", @@ -3314,14 +3300,12 @@ dependencies = [ "mas-oidc-client", "mas-policy", "mas-router", - "mas-spa", "mas-storage", "mas-storage-pg", "mas-templates", "mime", "minijinja", "minijinja-contrib", - "nonzero_ext", "oauth2-types", "opentelemetry", "opentelemetry-semantic-conventions", @@ -3428,7 +3412,6 @@ dependencies = [ "camino", "convert_case", "csv", - "futures-util", "reqwest", "serde", "tokio", @@ -3463,7 +3446,6 @@ dependencies = [ "sha2", "signature", "thiserror 2.0.9", - "tracing", "url", ] @@ -3476,7 +3458,6 @@ dependencies = [ "chacha20poly1305", "const-oid", "der", - "ecdsa", "elliptic-curve", "generic-array", "insta", @@ -3506,7 +3487,6 @@ dependencies = [ "http-body", "hyper", "hyper-util", - "libc", "pin-project-lite", "rustls-pemfile", "socket2", @@ -3527,10 +3507,7 @@ version = "0.12.0" dependencies = [ "anyhow", "async-trait", - "http", - "serde", "tokio", - "url", ] [[package]] @@ -3540,14 +3517,11 @@ dependencies = [ "anyhow", "async-trait", "http", - "mas-axum-utils", "mas-http", "mas-matrix", "reqwest", "serde", - "serde_json", "thiserror 2.0.9", - "tower", "tracing", "url", "urlencoding", @@ -3575,8 +3549,6 @@ dependencies = [ "mime", "oauth2-types", "p256", - "pem-rfc7468", - "pkcs8", "rand", "rand_chacha", "reqwest", @@ -3633,7 +3605,6 @@ version = "0.12.0" dependencies = [ "async-trait", "chrono", - "cron", "futures-util", "mas-data-model", "mas-iana", @@ -3667,7 +3638,6 @@ dependencies = [ "rand_chacha", "sea-query", "sea-query-binder", - "serde", "serde_json", "sqlx", "thiserror 2.0.9", @@ -3682,12 +3652,9 @@ name = "mas-tasks" version = "0.12.0" dependencies = [ "anyhow", - "async-stream", "async-trait", "chrono", "cron", - "event-listener 5.3.1", - "futures-lite", "mas-data-model", "mas-email", "mas-i18n", @@ -3696,7 +3663,6 @@ dependencies = [ "mas-storage", "mas-storage-pg", "mas-templates", - "mas-tower", "opentelemetry", "opentelemetry-semantic-conventions", "rand", @@ -3707,11 +3673,9 @@ dependencies = [ "thiserror 2.0.9", "tokio", "tokio-util", - "tower", "tracing", "tracing-opentelemetry", "ulid", - "url", ] [[package]] @@ -4014,7 +3978,6 @@ dependencies = [ "assert_matches", "chrono", "data-encoding", - "http", "language-tags", "mas-iana", "mas-jose", diff --git a/Cargo.toml b/Cargo.toml index a19d9f881..e2c37d489 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,6 +82,10 @@ version = "0.7.9" version = "0.9.6" features = ["cookie-private", "cookie-key-expansion", "typed-header"] +# Constant-time base64 +[workspace.dependencies.base64ct] +version = "1.6.0" + # Bytes [workspace.dependencies.bytes] version = "1.9.0" diff --git a/crates/axum-utils/Cargo.toml b/crates/axum-utils/Cargo.toml index a2b70c003..d778b049a 100644 --- a/crates/axum-utils/Cargo.toml +++ b/crates/axum-utils/Cargo.toml @@ -15,15 +15,10 @@ workspace = true async-trait.workspace = true axum.workspace = true axum-extra.workspace = true -bytes.workspace = true chrono.workspace = true data-encoding = "2.6.0" -futures-util.workspace = true headers.workspace = true http.workspace = true -http-body.workspace = true -http-body-util.workspace = true -hyper-util.workspace = true icu_locid = "1.4.0" mime = "0.3.17" rand.workspace = true @@ -31,11 +26,9 @@ reqwest.workspace = true sentry.workspace = true serde.workspace = true serde_with = "3.12.0" -serde_urlencoded = "0.7.1" serde_json.workspace = true thiserror.workspace = true tokio.workspace = true -tower.workspace = true tracing.workspace = true url.workspace = true ulid.workspace = true diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index acebbc56c..0d528ce44 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -23,9 +23,6 @@ console = "0.15.10" dialoguer = { version = "0.11.0", features = ["fuzzy-select"] } dotenvy = "0.15.7" figment.workspace = true -httpdate = "1.0.3" -http.workspace = true -http-body.workspace = true http-body-util.workspace = true hyper.workspace = true ipnetwork = "0.20.0" @@ -69,20 +66,17 @@ mas-email.workspace = true mas-handlers.workspace = true mas-http.workspace = true mas-i18n.workspace = true -mas-iana.workspace = true mas-keystore.workspace = true mas-listener.workspace = true mas-matrix.workspace = true mas-matrix-synapse.workspace = true mas-policy.workspace = true mas-router.workspace = true -mas-spa.workspace = true mas-storage.workspace = true mas-storage-pg.workspace = true mas-tasks.workspace = true mas-templates.workspace = true mas-tower.workspace = true -oauth2-types.workspace = true [build-dependencies] anyhow.workspace = true diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index 6bba7a6a4..4a89fdd89 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -14,8 +14,6 @@ workspace = true [dependencies] tokio.workspace = true tracing.workspace = true - -thiserror.workspace = true anyhow.workspace = true camino = { workspace = true, features = ["serde1"] } diff --git a/crates/data-model/Cargo.toml b/crates/data-model/Cargo.toml index c9f4a3a50..ee49a6c05 100644 --- a/crates/data-model/Cargo.toml +++ b/crates/data-model/Cargo.toml @@ -12,6 +12,7 @@ publish = false workspace = true [dependencies] +base64ct.workspace = true chrono.workspace = true thiserror.workspace = true serde.workspace = true diff --git a/crates/data-model/src/tokens.rs b/crates/data-model/src/tokens.rs index 9e94f7171..44fe8cc48 100644 --- a/crates/data-model/src/tokens.rs +++ b/crates/data-model/src/tokens.rs @@ -4,6 +4,7 @@ // SPDX-License-Identifier: AGPL-3.0-only // Please see LICENSE in the repository root for full details. +use base64ct::{Base64Url, Encoding}; use chrono::{DateTime, Utc}; use crc::{Crc, CRC_32_ISO_HDLC}; use mas_iana::oauth::OAuthTokenTypeHint; @@ -294,7 +295,7 @@ impl TokenType { pub fn check(token: &str) -> Result { // these are legacy tokens imported from Synapse // we don't do any validation on them and continue as is - if token.starts_with("syt_") { + if token.starts_with("syt_") || is_likely_synapse_macaroon(token) { return Ok(TokenType::CompatAccessToken); } if token.starts_with("syr_") { @@ -344,6 +345,20 @@ impl PartialEq for TokenType { } } +/// Returns true if and only if a token looks like it may be a macaroon. +/// +/// Macaroons are a standard for tokens that support attenuation. +/// Synapse used them for old sessions and for guest sessions. +/// +/// We won't bother to decode them fully, but we can check to see if the first +/// constraint is the `location` constraint. +fn is_likely_synapse_macaroon(token: &str) -> bool { + let Ok(decoded) = Base64Url::decode_vec(token) else { + return false; + }; + decoded.get(4..13) == Some(b"location ") +} + const NUM: [u8; 62] = *b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; fn base62_encode(mut num: u32) -> String { @@ -420,6 +435,25 @@ mod tests { ); } + #[test] + fn test_is_likely_synapse_macaroon() { + // This is just the prefix of a Synapse macaroon, but it's enough to make the + // sniffing work + assert!(is_likely_synapse_macaroon( + "MDAxYmxvY2F0aW9uIGxpYnJlcHVzaC5uZXQKMDAx" + )); + + // Whilst this is a macaroon, it's not a Synapse macaroon + assert!(! is_likely_synapse_macaroon("MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaWVyIHdlIHVzZWQgb3VyIHNlY3JldCBrZXkKMDAyZnNpZ25hdHVyZSDj2eApCFJsTAA5rhURQRXZf91ovyujebNCqvD2F9BVLwo")); + + // None of these are macaroons + assert!(!is_likely_synapse_macaroon( + "eyJARTOhearotnaeisahtoarsnhiasra.arsohenaor.oarnsteao" + )); + assert!(!is_likely_synapse_macaroon("....")); + assert!(!is_likely_synapse_macaroon("aaa")); + } + #[test] fn test_generate_and_check() { const COUNT: usize = 500; // Generate 500 of each token type diff --git a/crates/email/Cargo.toml b/crates/email/Cargo.toml index 905c0b98e..adaf13c77 100644 --- a/crates/email/Cargo.toml +++ b/crates/email/Cargo.toml @@ -13,7 +13,6 @@ workspace = true [dependencies] async-trait.workspace = true -headers.workspace = true lettre.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/handlers/Cargo.toml b/crates/handlers/Cargo.toml index 334ad6246..2b731c565 100644 --- a/crates/handlers/Cargo.toml +++ b/crates/handlers/Cargo.toml @@ -68,7 +68,7 @@ pbkdf2 = { version = "0.12.2", features = [ zeroize = "1.8.1" # Various data types and utilities -base64ct = "1.6.0" +base64ct.workspace = true camino.workspace = true chrono.workspace = true elliptic-curve.workspace = true @@ -81,7 +81,6 @@ url.workspace = true mime = "0.3.17" minijinja.workspace = true minijinja-contrib.workspace = true -nonzero_ext.workspace = true rand.workspace = true rand_chacha = "0.3.1" headers.workspace = true @@ -99,7 +98,6 @@ mas-matrix.workspace = true mas-oidc-client.workspace = true mas-policy.workspace = true mas-router.workspace = true -mas-spa.workspace = true mas-storage.workspace = true mas-storage-pg.workspace = true mas-templates.workspace = true diff --git a/crates/iana-codegen/Cargo.toml b/crates/iana-codegen/Cargo.toml index 6738c09b3..bf5e6145c 100644 --- a/crates/iana-codegen/Cargo.toml +++ b/crates/iana-codegen/Cargo.toml @@ -17,7 +17,6 @@ async-trait.workspace = true camino.workspace = true convert_case = "0.6.0" csv = "1.3.1" -futures-util.workspace = true reqwest.workspace = true serde.workspace = true tokio.workspace = true diff --git a/crates/jose/Cargo.toml b/crates/jose/Cargo.toml index 6b1773580..f2a9ec629 100644 --- a/crates/jose/Cargo.toml +++ b/crates/jose/Cargo.toml @@ -32,7 +32,6 @@ serde_with = "3.12.0" sha2 = { version = "0.10.8", features = ["oid"] } signature = "2.2.0" thiserror.workspace = true -tracing.workspace = true url.workspace = true mas-iana.workspace = true diff --git a/crates/keystore/Cargo.toml b/crates/keystore/Cargo.toml index 86a2ad030..d81c8b58e 100644 --- a/crates/keystore/Cargo.toml +++ b/crates/keystore/Cargo.toml @@ -15,7 +15,6 @@ workspace = true aead = { version = "0.5.2", features = ["std"] } const-oid = { version = "0.9.6", features = ["std"] } der = { version = "0.7.9", features = ["std"] } -ecdsa = { version = "0.16.9", features = ["std"] } elliptic-curve.workspace = true k256.workspace = true p256.workspace = true diff --git a/crates/listener/Cargo.toml b/crates/listener/Cargo.toml index c239021ba..5ec347035 100644 --- a/crates/listener/Cargo.toml +++ b/crates/listener/Cargo.toml @@ -17,7 +17,6 @@ futures-util.workspace = true http-body.workspace = true hyper = { workspace = true, features = ["server"] } hyper-util.workspace = true -libc = "0.2.169" pin-project-lite = "0.2.16" socket2 = "0.5.8" thiserror.workspace = true diff --git a/crates/matrix-synapse/Cargo.toml b/crates/matrix-synapse/Cargo.toml index d7ef2c854..27e0018ec 100644 --- a/crates/matrix-synapse/Cargo.toml +++ b/crates/matrix-synapse/Cargo.toml @@ -17,13 +17,10 @@ async-trait.workspace = true http.workspace = true reqwest.workspace = true serde.workspace = true -serde_json.workspace = true thiserror.workspace = true -tower.workspace = true tracing.workspace = true url.workspace = true urlencoding = "2.1.3" -mas-axum-utils.workspace = true mas-http.workspace = true mas-matrix.workspace = true diff --git a/crates/matrix/Cargo.toml b/crates/matrix/Cargo.toml index 905827307..8f7e77579 100644 --- a/crates/matrix/Cargo.toml +++ b/crates/matrix/Cargo.toml @@ -13,8 +13,5 @@ workspace = true [dependencies] anyhow.workspace = true -serde.workspace = true async-trait.workspace = true -http.workspace = true tokio.workspace = true -url.workspace = true diff --git a/crates/oauth2-types/Cargo.toml b/crates/oauth2-types/Cargo.toml index 256eb814f..a91c3960f 100644 --- a/crates/oauth2-types/Cargo.toml +++ b/crates/oauth2-types/Cargo.toml @@ -12,7 +12,6 @@ repository.workspace = true workspace = true [dependencies] -http.workspace = true serde.workspace = true serde_json.workspace = true language-tags = { version = "0.3.2", features = ["serde"] } diff --git a/crates/oidc-client/Cargo.toml b/crates/oidc-client/Cargo.toml index fd656525c..6dc9c018a 100644 --- a/crates/oidc-client/Cargo.toml +++ b/crates/oidc-client/Cargo.toml @@ -21,8 +21,6 @@ headers.workspace = true http.workspace = true language-tags = "0.3.2" mime = "0.3.17" -pem-rfc7468.workspace = true -pkcs8.workspace = true p256.workspace = true rand.workspace = true reqwest.workspace = true diff --git a/crates/storage-pg/Cargo.toml b/crates/storage-pg/Cargo.toml index 8f354184d..f839f0262 100644 --- a/crates/storage-pg/Cargo.toml +++ b/crates/storage-pg/Cargo.toml @@ -17,7 +17,6 @@ sqlx.workspace = true sea-query.workspace = true sea-query-binder.workspace = true chrono.workspace = true -serde.workspace = true serde_json.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/storage/Cargo.toml b/crates/storage/Cargo.toml index 97e06b507..22d209df0 100644 --- a/crates/storage/Cargo.toml +++ b/crates/storage/Cargo.toml @@ -14,7 +14,6 @@ workspace = true [dependencies] async-trait.workspace = true chrono.workspace = true -cron.workspace = true futures-util.workspace = true opentelemetry.workspace = true rand_core = "0.6.4" diff --git a/crates/tasks/Cargo.toml b/crates/tasks/Cargo.toml index 0ada1c856..3b57e296f 100644 --- a/crates/tasks/Cargo.toml +++ b/crates/tasks/Cargo.toml @@ -13,25 +13,20 @@ workspace = true [dependencies] anyhow.workspace = true -async-stream = "0.3.6" async-trait.workspace = true cron.workspace = true chrono.workspace = true -event-listener = "5.3.1" -futures-lite = "2.5.0" rand.workspace = true rand_chacha = "0.3.1" sqlx.workspace = true thiserror.workspace = true tokio.workspace = true tokio-util.workspace = true -tower.workspace = true tracing.workspace = true tracing-opentelemetry.workspace = true opentelemetry.workspace = true opentelemetry-semantic-conventions.workspace = true ulid.workspace = true -url.workspace = true serde.workspace = true serde_json.workspace = true @@ -43,4 +38,3 @@ mas-router.workspace = true mas-storage.workspace = true mas-storage-pg.workspace = true mas-templates.workspace = true -mas-tower.workspace = true