diff --git a/crates/handlers/src/oauth2/discovery.rs b/crates/handlers/src/oauth2/discovery.rs index 61dfc1ba5..b1d000f8f 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,15 @@ 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..86f0bd8ed 100644 --- a/frontend/src/routes/_account.index.tsx +++ b/frontend/src/routes/_account.index.tsx @@ -62,17 +62,29 @@ 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 +105,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 +124,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 +134,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" }); }