diff --git a/Cargo.lock b/Cargo.lock index c98d8a023..6dd2194ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3124,7 +3124,7 @@ dependencies = [ [[package]] name = "mas-axum-utils" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "anyhow", "axum", @@ -3158,7 +3158,7 @@ dependencies = [ [[package]] name = "mas-cli" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "anyhow", "axum", @@ -3232,7 +3232,7 @@ dependencies = [ [[package]] name = "mas-config" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "anyhow", "camino", @@ -3264,7 +3264,7 @@ dependencies = [ [[package]] name = "mas-context" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "console", "opentelemetry", @@ -3280,7 +3280,7 @@ dependencies = [ [[package]] name = "mas-data-model" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "base64ct", "chrono", @@ -3301,7 +3301,7 @@ dependencies = [ [[package]] name = "mas-email" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "async-trait", "lettre", @@ -3312,7 +3312,7 @@ dependencies = [ [[package]] name = "mas-handlers" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "aide", "anyhow", @@ -3390,7 +3390,7 @@ dependencies = [ [[package]] name = "mas-http" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "futures-util", "headers", @@ -3411,7 +3411,7 @@ dependencies = [ [[package]] name = "mas-i18n" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "camino", "icu_calendar", @@ -3433,7 +3433,7 @@ dependencies = [ [[package]] name = "mas-i18n-scan" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "camino", "clap", @@ -3447,7 +3447,7 @@ dependencies = [ [[package]] name = "mas-iana" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "schemars 0.8.22", "serde", @@ -3455,7 +3455,7 @@ dependencies = [ [[package]] name = "mas-iana-codegen" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "anyhow", "async-trait", @@ -3471,7 +3471,7 @@ dependencies = [ [[package]] name = "mas-jose" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "base64ct", "chrono", @@ -3501,7 +3501,7 @@ dependencies = [ [[package]] name = "mas-keystore" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "aead", "base64ct", @@ -3529,7 +3529,7 @@ dependencies = [ [[package]] name = "mas-listener" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "anyhow", "bytes", @@ -3554,7 +3554,7 @@ dependencies = [ [[package]] name = "mas-matrix" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "anyhow", "async-trait", @@ -3564,7 +3564,7 @@ dependencies = [ [[package]] name = "mas-matrix-synapse" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "anyhow", "async-trait", @@ -3581,7 +3581,7 @@ dependencies = [ [[package]] name = "mas-oidc-client" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "assert_matches", "async-trait", @@ -3617,7 +3617,7 @@ dependencies = [ [[package]] name = "mas-policy" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "anyhow", "arc-swap", @@ -3634,7 +3634,7 @@ dependencies = [ [[package]] name = "mas-router" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "axum", "serde", @@ -3645,7 +3645,7 @@ dependencies = [ [[package]] name = "mas-spa" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "camino", "serde", @@ -3654,7 +3654,7 @@ dependencies = [ [[package]] name = "mas-storage" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "async-trait", "chrono", @@ -3676,7 +3676,7 @@ dependencies = [ [[package]] name = "mas-storage-pg" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "async-trait", "chrono", @@ -3703,7 +3703,7 @@ dependencies = [ [[package]] name = "mas-tasks" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "anyhow", "async-trait", @@ -3735,7 +3735,7 @@ dependencies = [ [[package]] name = "mas-templates" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "anyhow", "arc-swap", @@ -3765,7 +3765,7 @@ dependencies = [ [[package]] name = "mas-tower" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "http", "opentelemetry", @@ -4035,7 +4035,7 @@ dependencies = [ [[package]] name = "oauth2-types" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "assert_matches", "base64ct", @@ -6214,7 +6214,7 @@ dependencies = [ [[package]] name = "syn2mas" -version = "0.19.0-rc.0" +version = "0.19.0-rc.1" dependencies = [ "anyhow", "arc-swap", diff --git a/Cargo.toml b/Cargo.toml index 82f48901e..8d40308bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = ["crates/*"] resolver = "2" # Updated in the CI with a `sed` command -package.version = "0.19.0-rc.0" +package.version = "0.19.0-rc.1" package.license = "AGPL-3.0-only OR LicenseRef-Element-Commercial" package.authors = ["Element Backend Team"] package.edition = "2024" @@ -33,35 +33,35 @@ broken_intra_doc_links = "deny" [workspace.dependencies] # Workspace crates -mas-axum-utils = { path = "./crates/axum-utils/", version = "=0.19.0-rc.0" } -mas-cli = { path = "./crates/cli/", version = "=0.19.0-rc.0" } -mas-config = { path = "./crates/config/", version = "=0.19.0-rc.0" } -mas-context = { path = "./crates/context/", version = "=0.19.0-rc.0" } -mas-data-model = { path = "./crates/data-model/", version = "=0.19.0-rc.0" } -mas-email = { path = "./crates/email/", version = "=0.19.0-rc.0" } -mas-graphql = { path = "./crates/graphql/", version = "=0.19.0-rc.0" } -mas-handlers = { path = "./crates/handlers/", version = "=0.19.0-rc.0" } -mas-http = { path = "./crates/http/", version = "=0.19.0-rc.0" } -mas-i18n = { path = "./crates/i18n/", version = "=0.19.0-rc.0" } -mas-i18n-scan = { path = "./crates/i18n-scan/", version = "=0.19.0-rc.0" } -mas-iana = { path = "./crates/iana/", version = "=0.19.0-rc.0" } -mas-iana-codegen = { path = "./crates/iana-codegen/", version = "=0.19.0-rc.0" } -mas-jose = { path = "./crates/jose/", version = "=0.19.0-rc.0" } -mas-keystore = { path = "./crates/keystore/", version = "=0.19.0-rc.0" } -mas-listener = { path = "./crates/listener/", version = "=0.19.0-rc.0" } -mas-matrix = { path = "./crates/matrix/", version = "=0.19.0-rc.0" } -mas-matrix-synapse = { path = "./crates/matrix-synapse/", version = "=0.19.0-rc.0" } -mas-oidc-client = { path = "./crates/oidc-client/", version = "=0.19.0-rc.0" } -mas-policy = { path = "./crates/policy/", version = "=0.19.0-rc.0" } -mas-router = { path = "./crates/router/", version = "=0.19.0-rc.0" } -mas-spa = { path = "./crates/spa/", version = "=0.19.0-rc.0" } -mas-storage = { path = "./crates/storage/", version = "=0.19.0-rc.0" } -mas-storage-pg = { path = "./crates/storage-pg/", version = "=0.19.0-rc.0" } -mas-tasks = { path = "./crates/tasks/", version = "=0.19.0-rc.0" } -mas-templates = { path = "./crates/templates/", version = "=0.19.0-rc.0" } -mas-tower = { path = "./crates/tower/", version = "=0.19.0-rc.0" } -oauth2-types = { path = "./crates/oauth2-types/", version = "=0.19.0-rc.0" } -syn2mas = { path = "./crates/syn2mas", version = "=0.19.0-rc.0" } +mas-axum-utils = { path = "./crates/axum-utils/", version = "=0.19.0-rc.1" } +mas-cli = { path = "./crates/cli/", version = "=0.19.0-rc.1" } +mas-config = { path = "./crates/config/", version = "=0.19.0-rc.1" } +mas-context = { path = "./crates/context/", version = "=0.19.0-rc.1" } +mas-data-model = { path = "./crates/data-model/", version = "=0.19.0-rc.1" } +mas-email = { path = "./crates/email/", version = "=0.19.0-rc.1" } +mas-graphql = { path = "./crates/graphql/", version = "=0.19.0-rc.1" } +mas-handlers = { path = "./crates/handlers/", version = "=0.19.0-rc.1" } +mas-http = { path = "./crates/http/", version = "=0.19.0-rc.1" } +mas-i18n = { path = "./crates/i18n/", version = "=0.19.0-rc.1" } +mas-i18n-scan = { path = "./crates/i18n-scan/", version = "=0.19.0-rc.1" } +mas-iana = { path = "./crates/iana/", version = "=0.19.0-rc.1" } +mas-iana-codegen = { path = "./crates/iana-codegen/", version = "=0.19.0-rc.1" } +mas-jose = { path = "./crates/jose/", version = "=0.19.0-rc.1" } +mas-keystore = { path = "./crates/keystore/", version = "=0.19.0-rc.1" } +mas-listener = { path = "./crates/listener/", version = "=0.19.0-rc.1" } +mas-matrix = { path = "./crates/matrix/", version = "=0.19.0-rc.1" } +mas-matrix-synapse = { path = "./crates/matrix-synapse/", version = "=0.19.0-rc.1" } +mas-oidc-client = { path = "./crates/oidc-client/", version = "=0.19.0-rc.1" } +mas-policy = { path = "./crates/policy/", version = "=0.19.0-rc.1" } +mas-router = { path = "./crates/router/", version = "=0.19.0-rc.1" } +mas-spa = { path = "./crates/spa/", version = "=0.19.0-rc.1" } +mas-storage = { path = "./crates/storage/", version = "=0.19.0-rc.1" } +mas-storage-pg = { path = "./crates/storage-pg/", version = "=0.19.0-rc.1" } +mas-tasks = { path = "./crates/tasks/", version = "=0.19.0-rc.1" } +mas-templates = { path = "./crates/templates/", version = "=0.19.0-rc.1" } +mas-tower = { path = "./crates/tower/", version = "=0.19.0-rc.1" } +oauth2-types = { path = "./crates/oauth2-types/", version = "=0.19.0-rc.1" } +syn2mas = { path = "./crates/syn2mas", version = "=0.19.0-rc.1" } # OpenAPI schema generation and validation [workspace.dependencies.aide] diff --git a/crates/storage-pg/migrations/20250709142230_id_token_claims_trigger.sql b/crates/storage-pg/migrations/20250709142230_id_token_claims_trigger.sql new file mode 100644 index 000000000..32d304721 --- /dev/null +++ b/crates/storage-pg/migrations/20250709142230_id_token_claims_trigger.sql @@ -0,0 +1,51 @@ +-- Copyright 2025 New Vector Ltd. +-- +-- SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +-- Please see LICENSE in the repository root for full details. + +-- We may be running an older version of the app that doesn't fill in the +-- id_token_claims column when the id_token column is populated. So we add a +-- trigger to fill in the id_token_claims column if it's NULL. +-- +-- We will be able to remove this trigger in a future version of the app. +-- +-- We backfill in a second migration after this one to make sure we don't miss +-- any rows, and don't lock the table for too long. +CREATE OR REPLACE FUNCTION fill_id_token_claims() +RETURNS TRIGGER AS $$ +BEGIN + -- Only process if id_token_claims is NULL but id_token is not NULL + IF NEW.id_token_claims IS NULL AND NEW.id_token IS NOT NULL AND NEW.id_token != '' THEN + BEGIN + -- Decode JWT payload inline + NEW.id_token_claims := ( + CASE + WHEN split_part(NEW.id_token, '.', 2) = '' THEN NULL + ELSE + (convert_from( + decode( + replace(replace(split_part(NEW.id_token, '.', 2), '-', '+'), '_', '/') || + repeat('=', (4 - length(split_part(NEW.id_token, '.', 2)) % 4) % 4), + 'base64' + ), + 'UTF8' + ))::JSONB + END + ); + EXCEPTION + WHEN OTHERS THEN + -- If JWT decoding fails, leave id_token_claims as NULL + NEW.id_token_claims := NULL; + END; + END IF; + + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Create the trigger +CREATE TRIGGER trg_fill_id_token_claims + BEFORE INSERT OR UPDATE ON upstream_oauth_authorization_sessions + FOR EACH ROW + WHEN (NEW.id_token_claims IS NULL AND NEW.id_token IS NOT NULL AND NEW.id_token <> '') + EXECUTE FUNCTION fill_id_token_claims(); diff --git a/crates/storage-pg/migrations/20250709142240_backfill_id_token_claims.sql b/crates/storage-pg/migrations/20250709142240_backfill_id_token_claims.sql new file mode 100644 index 000000000..c2fa067af --- /dev/null +++ b/crates/storage-pg/migrations/20250709142240_backfill_id_token_claims.sql @@ -0,0 +1,22 @@ +-- Copyright 2025 New Vector Ltd. +-- +-- SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +-- Please see LICENSE in the repository root for full details. + +-- This backfills the id_token_claims column in the upstream_oauth_authorization_sessions table +-- by decoding the id_token column and storing the decoded claims in the id_token_claims column. +UPDATE upstream_oauth_authorization_sessions +SET id_token_claims = CASE + WHEN id_token IS NULL OR id_token = '' THEN NULL + WHEN split_part(id_token, '.', 2) = '' THEN NULL + ELSE + (convert_from( + decode( + replace(replace(split_part(id_token, '.', 2), '-', '+'), '_', '/') || + repeat('=', (4 - length(split_part(id_token, '.', 2)) % 4) % 4), + 'base64' + ), + 'UTF8' + ))::JSONB +END +WHERE id_token IS NOT NULL AND id_token_claims IS NULL;