From ca9cedcfda386543e4cab012a11096286e201197 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 3 Dec 2025 10:43:39 +0000 Subject: [PATCH 1/2] Stabilisation of supported MSC4191 account management actions - Support the stable names and the unstable names - Advertise both the stable names and the unstable names This means that MAS supports either names. We can remove the unstable names once the is enough client adoption of the stable names. n.b. this does not change the oauth2-types crate as not used by MAS. --- crates/handlers/src/oauth2/discovery.rs | 8 +++++-- crates/router/src/endpoints.rs | 15 ++++++++++++- frontend/src/routes/_account.index.tsx | 29 ++++++++++++++----------- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/crates/handlers/src/oauth2/discovery.rs b/crates/handlers/src/oauth2/discovery.rs index 61dfc1ba5..3827ffbc0 100644 --- a/crates/handlers/src/oauth2/discovery.rs +++ b/crates/handlers/src/oauth2/discovery.rs @@ -29,7 +29,7 @@ struct DiscoveryResponse { #[serde(rename = "org.matrix.matrix-authentication-service.graphql_endpoint")] graphql_endpoint: url::Url, - // As per MSC2965 + // As per MSC4191 account_management_uri: url::Url, account_management_actions_supported: Vec, } @@ -183,10 +183,14 @@ pub(crate) async fn get( // see frontend/src/routes/__root.tsx account_management_actions_supported: vec![ "org.matrix.profile".to_owned(), + "org.matrix.devices_list".to_owned(), + "org.matrix.device_view".to_owned(), + "org.matrix.device_delete".to_owned(), + "org.matrix.cross_signing_reset".to_owned(), + // These are unstable versions from MSC4191 and we will remove them once the above stable values have enough adoption by clients "org.matrix.sessions_list".to_owned(), "org.matrix.session_view".to_owned(), "org.matrix.session_end".to_owned(), - "org.matrix.cross_signing_reset".to_owned(), ], }) } diff --git a/crates/router/src/endpoints.rs b/crates/router/src/endpoints.rs index 3440f8bc6..b6b4b5650 100644 --- a/crates/router/src/endpoints.rs +++ b/crates/router/src/endpoints.rs @@ -478,27 +478,40 @@ impl Route for RegisterFinish { } } -/// Actions parameters as defined by MSC2965 +/// Actions parameters as defined by MSC4191 #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "action")] pub enum AccountAction { #[serde(rename = "org.matrix.profile")] OrgMatrixProfile, + /// DEPRECATED: Use `OrgMatrixProfile` instead #[serde(rename = "profile")] Profile, + #[serde(rename = "org.matrix.devices_list")] + OrgMatrixDevicesList, + /// DEPRECATED: Use `OrgMatrixDevicesList` instead #[serde(rename = "org.matrix.sessions_list")] OrgMatrixSessionsList, + /// DEPRECATED: Use `OrgMatrixDevicesList` instead #[serde(rename = "sessions_list")] SessionsList, + #[serde(rename = "org.matrix.device_view")] + OrgMatrixDeviceView { device_id: String }, + /// DEPRECATED: Use `OrgMatrixDeviceView` instead #[serde(rename = "org.matrix.session_view")] OrgMatrixSessionView { device_id: String }, + /// DEPRECATED: Use `OrgMatrixDeviceView` instead #[serde(rename = "session_view")] SessionView { device_id: String }, + #[serde(rename = "org.matrix.device_delete")] + OrgMatrixDeviceDelete { device_id: String }, + /// DEPRECATED: Use `OrgMatrixDeviceDelete` instead #[serde(rename = "org.matrix.session_end")] OrgMatrixSessionEnd { device_id: String }, + /// DEPRECATED: Use `OrgMatrixDeviceDelete` instead #[serde(rename = "session_end")] SessionEnd { device_id: String }, diff --git a/frontend/src/routes/_account.index.tsx b/frontend/src/routes/_account.index.tsx index a4cdc2aa0..3c155b0fc 100644 --- a/frontend/src/routes/_account.index.tsx +++ b/frontend/src/routes/_account.index.tsx @@ -62,17 +62,17 @@ const query = queryOptions({ const actionSchema = v.variant("action", [ v.object({ - action: v.picklist(["profile", "org.matrix.profile"]), + action: v.picklist(["org.matrix.profile", "profile"]), }), v.object({ - action: v.picklist(["sessions_list", "org.matrix.sessions_list"]), + action: v.picklist(["org.matrix.devices_list", "sessions_list", "org.matrix.sessions_list"]), }), v.object({ - action: v.picklist(["session_view", "org.matrix.session_view"]), + action: v.picklist(["org.matrix.device_view", "session_view", "org.matrix.session_view"]), device_id: v.optional(v.string()), }), v.object({ - action: v.picklist(["session_end", "org.matrix.session_end"]), + action: v.picklist(["org.matrix.device_delete", "session_end", "org.matrix.session_end"]), device_id: v.optional(v.string()), }), v.object({ @@ -93,16 +93,18 @@ export const Route = createFileRoute({ beforeLoad({ search }) { switch (search.action) { - case "profile": // This is an unspecced alias for org.matrix.profile that can be removed - case "org.matrix.profile": // This is from unstable MSC4191 + case "org.matrix.profile": + case "profile": // This is an unspecced alias that can be removed throw redirect({ to: "/", search: {} }); - case "sessions_list": // This is an unspecced alias for org.matrix.sessions_list that can be removed - case "org.matrix.sessions_list": // This is from unstable MSC4191 + case "org.matrix.devices_list": + case "sessions_list": // This is an unspecced alias that can be removed + case "org.matrix.sessions_list": // This is an unstable value from MSC4191 that can be removed once we have enough client adoption of the stable value throw redirect({ to: "/sessions" }); - case "session_view": // This is an unspecced alias for org.matrix.session_view that can be removed - case "org.matrix.session_view": // This is from unstable MSC4191 + case "org.matrix.device_view": + case "session_view": // This is an unspecced alias that can be removed + case "org.matrix.session_view": // This is an unstable value from MSC4191 that can be removed once we have enough client adoption of the stable value if (search.device_id) throw redirect({ to: "/devices/$", @@ -110,8 +112,9 @@ export const Route = createFileRoute({ }); throw redirect({ to: "/sessions" }); + case "org.matrix.device_delete": case "session_end": // This is the unstable MSC3824 alias for org.matrix.session_end - case "org.matrix.session_end": // This is from unstable MSC4191 + case "org.matrix.session_end": // This is an unstable value from MSC4191 that can be removed once we have enough client adoption of the stable value if (search.device_id) throw redirect({ to: "/devices/$", @@ -119,14 +122,14 @@ export const Route = createFileRoute({ }); throw redirect({ to: "/sessions" }); - case "org.matrix.cross_signing_reset": // This is from unstable MSC4191 + case "org.matrix.cross_signing_reset": throw redirect({ to: "/reset-cross-signing", search: { deepLink: true }, }); case "org.matrix.plan_management": { // This is an unspecced experimental value - // We don't both checking if the plan management iframe is actually available and + // We don't bother checking if the plan management iframe is actually available and // instead rely on the plan tab handling it. throw redirect({ to: "/plan" }); } From fd62b80df82e86dfd55fc4bb46e9d3a20fa84232 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 3 Dec 2025 11:50:52 +0000 Subject: [PATCH 2/2] Lint --- crates/handlers/src/oauth2/discovery.rs | 3 ++- frontend/src/routes/_account.index.tsx | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/crates/handlers/src/oauth2/discovery.rs b/crates/handlers/src/oauth2/discovery.rs index 3827ffbc0..b1d000f8f 100644 --- a/crates/handlers/src/oauth2/discovery.rs +++ b/crates/handlers/src/oauth2/discovery.rs @@ -187,7 +187,8 @@ pub(crate) async fn get( "org.matrix.device_view".to_owned(), "org.matrix.device_delete".to_owned(), "org.matrix.cross_signing_reset".to_owned(), - // These are unstable versions from MSC4191 and we will remove them once the above stable values have enough adoption by clients + // These are unstable versions from MSC4191 and we will remove them once the above + // stable values have enough adoption by clients "org.matrix.sessions_list".to_owned(), "org.matrix.session_view".to_owned(), "org.matrix.session_end".to_owned(), diff --git a/frontend/src/routes/_account.index.tsx b/frontend/src/routes/_account.index.tsx index 3c155b0fc..86f0bd8ed 100644 --- a/frontend/src/routes/_account.index.tsx +++ b/frontend/src/routes/_account.index.tsx @@ -65,14 +65,26 @@ const actionSchema = v.variant("action", [ action: v.picklist(["org.matrix.profile", "profile"]), }), v.object({ - action: v.picklist(["org.matrix.devices_list", "sessions_list", "org.matrix.sessions_list"]), + action: v.picklist([ + "org.matrix.devices_list", + "sessions_list", + "org.matrix.sessions_list", + ]), }), v.object({ - action: v.picklist(["org.matrix.device_view", "session_view", "org.matrix.session_view"]), + action: v.picklist([ + "org.matrix.device_view", + "session_view", + "org.matrix.session_view", + ]), device_id: v.optional(v.string()), }), v.object({ - action: v.picklist(["org.matrix.device_delete", "session_end", "org.matrix.session_end"]), + action: v.picklist([ + "org.matrix.device_delete", + "session_end", + "org.matrix.session_end", + ]), device_id: v.optional(v.string()), }), v.object({