You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-08-07 17:03:01 +03:00
Implement account management discovery as per MSC2965
This commit is contained in:
@@ -34,6 +34,10 @@ struct DiscoveryResponse {
|
|||||||
|
|
||||||
#[serde(rename = "org.matrix.matrix-authentication-service.graphql_endpoint")]
|
#[serde(rename = "org.matrix.matrix-authentication-service.graphql_endpoint")]
|
||||||
graphql_endpoint: url::Url,
|
graphql_endpoint: url::Url,
|
||||||
|
|
||||||
|
// As per MSC2965
|
||||||
|
account_management_uri: url::Url,
|
||||||
|
account_management_actions_supported: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(name = "handlers.oauth2.discovery.get", skip_all)]
|
#[tracing::instrument(name = "handlers.oauth2.discovery.get", skip_all)]
|
||||||
@@ -168,6 +172,15 @@ pub(crate) async fn get(
|
|||||||
Json(DiscoveryResponse {
|
Json(DiscoveryResponse {
|
||||||
standard,
|
standard,
|
||||||
graphql_endpoint: url_builder.graphql_endpoint(),
|
graphql_endpoint: url_builder.graphql_endpoint(),
|
||||||
|
account_management_uri: url_builder.account_management_uri(),
|
||||||
|
// This needs to be kept in sync with what is supported in the frontend,
|
||||||
|
// see frontend/src/routing/actions.ts
|
||||||
|
account_management_actions_supported: vec![
|
||||||
|
"org.matrix.profile".to_owned(),
|
||||||
|
"org.matrix.sessions_list".to_owned(),
|
||||||
|
"org.matrix.session_view".to_owned(),
|
||||||
|
"org.matrix.session_end".to_owned(),
|
||||||
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -429,11 +429,26 @@ impl AccountAddEmail {
|
|||||||
|
|
||||||
/// Actions parameters as defined by MSC2965
|
/// Actions parameters as defined by MSC2965
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case", tag = "action")]
|
#[serde(tag = "action")]
|
||||||
pub enum AccountAction {
|
pub enum AccountAction {
|
||||||
|
#[serde(rename = "org.matrix.profile")]
|
||||||
|
OrgMatrixProfile,
|
||||||
|
#[serde(rename = "profile")]
|
||||||
Profile,
|
Profile,
|
||||||
|
|
||||||
|
#[serde(rename = "org.matrix.sessions_list")]
|
||||||
|
OrgMatrixSessionsList,
|
||||||
|
#[serde(rename = "sessions_list")]
|
||||||
SessionsList,
|
SessionsList,
|
||||||
|
|
||||||
|
#[serde(rename = "org.matrix.session_view")]
|
||||||
|
OrgMatrixSessionView { device_id: String },
|
||||||
|
#[serde(rename = "session_view")]
|
||||||
SessionView { device_id: String },
|
SessionView { device_id: String },
|
||||||
|
|
||||||
|
#[serde(rename = "org.matrix.session_end")]
|
||||||
|
OrgMatrixSessionEnd { device_id: String },
|
||||||
|
#[serde(rename = "session_end")]
|
||||||
SessionEnd { device_id: String },
|
SessionEnd { device_id: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -195,6 +195,12 @@ impl UrlBuilder {
|
|||||||
pub fn upstream_oauth_authorize(&self, id: Ulid) -> Url {
|
pub fn upstream_oauth_authorize(&self, id: Ulid) -> Url {
|
||||||
self.absolute_url_for(&crate::endpoints::UpstreamOAuth2Authorize::new(id))
|
self.absolute_url_for(&crate::endpoints::UpstreamOAuth2Authorize::new(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Account management URI
|
||||||
|
#[must_use]
|
||||||
|
pub fn account_management_uri(&self) -> Url {
|
||||||
|
self.absolute_url_for(&crate::endpoints::Account::default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@@ -95,4 +95,61 @@ describe("getRouteActionRedirection()", () => {
|
|||||||
searchParams: new URLSearchParams(),
|
searchParams: new URLSearchParams(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("redirects to session detail when location has a action=org.matrix.session_end", () => {
|
||||||
|
const searchParams = new URLSearchParams();
|
||||||
|
searchParams.set("action", "org.matrix.session_end");
|
||||||
|
searchParams.set("device_id", "test-device-id");
|
||||||
|
searchParams.set("something_else", "should-remain");
|
||||||
|
expect(
|
||||||
|
getRouteActionRedirection({ pathname: "/account/", searchParams }),
|
||||||
|
).toEqual({
|
||||||
|
route: {
|
||||||
|
type: "session",
|
||||||
|
id: "test-device-id",
|
||||||
|
},
|
||||||
|
searchParams: new URLSearchParams("?something_else=should-remain"),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("redirects to session detail when location has a action=org.matrix.session_view", () => {
|
||||||
|
const searchParams = new URLSearchParams();
|
||||||
|
searchParams.set("action", "org.matrix.session_view");
|
||||||
|
searchParams.set("device_id", "test-device-id");
|
||||||
|
expect(
|
||||||
|
getRouteActionRedirection({ pathname: "/account/", searchParams }),
|
||||||
|
).toEqual({
|
||||||
|
route: {
|
||||||
|
type: "session",
|
||||||
|
id: "test-device-id",
|
||||||
|
},
|
||||||
|
searchParams: new URLSearchParams(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("redirects to sessions overview when location has a action=org.matrix.sessions_list", () => {
|
||||||
|
const searchParams = new URLSearchParams();
|
||||||
|
searchParams.set("action", "org.matrix.sessions_list");
|
||||||
|
expect(
|
||||||
|
getRouteActionRedirection({ pathname: "/account/", searchParams }),
|
||||||
|
).toEqual({
|
||||||
|
route: {
|
||||||
|
type: "sessions-overview",
|
||||||
|
},
|
||||||
|
searchParams: new URLSearchParams(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("redirects to profile when location has a action=org.matrix.profile", () => {
|
||||||
|
const searchParams = new URLSearchParams();
|
||||||
|
searchParams.set("action", "org.matrix.profile");
|
||||||
|
expect(
|
||||||
|
getRouteActionRedirection({ pathname: "/account/", searchParams }),
|
||||||
|
).toEqual({
|
||||||
|
route: {
|
||||||
|
type: "profile",
|
||||||
|
},
|
||||||
|
searchParams: new URLSearchParams(),
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -32,11 +32,17 @@ export const getRouteActionRedirection = (
|
|||||||
} => {
|
} => {
|
||||||
// Clone the search params so we can modify them
|
// Clone the search params so we can modify them
|
||||||
const searchParams = new URLSearchParams(location.searchParams?.toString());
|
const searchParams = new URLSearchParams(location.searchParams?.toString());
|
||||||
const action = searchParams.get("action");
|
let action = searchParams.get("action");
|
||||||
const deviceId = searchParams.get("device_id");
|
const deviceId = searchParams.get("device_id");
|
||||||
searchParams.delete("action");
|
searchParams.delete("action");
|
||||||
searchParams.delete("device_id");
|
searchParams.delete("device_id");
|
||||||
|
|
||||||
|
// Actions are actually prefixed with org.matrix. in the latest version of MSC2965
|
||||||
|
// but we still want to support non-prefixed actions for backwards compatibility
|
||||||
|
if (action) {
|
||||||
|
action = action.replace(/^org.matrix./, "");
|
||||||
|
}
|
||||||
|
|
||||||
let route: Route;
|
let route: Route;
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case RouteAction.EndSession:
|
case RouteAction.EndSession:
|
||||||
|
Reference in New Issue
Block a user