diff --git a/crates/handlers/src/admin/v1/users/add.rs b/crates/handlers/src/admin/v1/users/add.rs index 299012d91..d67737526 100644 --- a/crates/handlers/src/admin/v1/users/add.rs +++ b/crates/handlers/src/admin/v1/users/add.rs @@ -166,10 +166,7 @@ pub async fn handler( let user = repo.user().add(&mut rng, &clock, params.username).await?; homeserver - .provision_user(&ProvisionRequest::new( - homeserver.mxid(&user.username), - &user.sub, - )) + .provision_user(&ProvisionRequest::new(&user.username, &user.sub)) .await .map_err(RouteError::Homeserver)?; @@ -222,8 +219,7 @@ mod tests { assert_eq!(user.username, "alice"); // Check that the user was created on the homeserver - let mxid = state.homeserver_connection.mxid("alice"); - let result = state.homeserver_connection.query_user(&mxid).await; + let result = state.homeserver_connection.query_user("alice").await; assert!(result.is_ok()); } diff --git a/crates/handlers/src/admin/v1/users/reactivate.rs b/crates/handlers/src/admin/v1/users/reactivate.rs index 37b38c6b6..0be687a39 100644 --- a/crates/handlers/src/admin/v1/users/reactivate.rs +++ b/crates/handlers/src/admin/v1/users/reactivate.rs @@ -83,9 +83,8 @@ pub async fn handler( .ok_or(RouteError::NotFound(id))?; // Call the homeserver synchronously to reactivate the user - let mxid = homeserver.mxid(&user.username); homeserver - .reactivate_user(&mxid) + .reactivate_user(&user.username) .await .map_err(RouteError::Homeserver)?; @@ -127,20 +126,23 @@ mod tests { // Provision and immediately deactivate the user on the homeserver, // because this endpoint will try to reactivate it - let mxid = state.homeserver_connection.mxid(&user.username); state .homeserver_connection - .provision_user(&ProvisionRequest::new(&mxid, &user.sub)) + .provision_user(&ProvisionRequest::new(&user.username, &user.sub)) .await .unwrap(); state .homeserver_connection - .delete_user(&mxid, true) + .delete_user(&user.username, true) .await .unwrap(); // The user should be deactivated on the homeserver - let mx_user = state.homeserver_connection.query_user(&mxid).await.unwrap(); + let mx_user = state + .homeserver_connection + .query_user(&user.username) + .await + .unwrap(); assert!(mx_user.deactivated); let request = Request::post(format!("/api/admin/v1/users/{}/reactivate", user.id)) @@ -176,10 +178,9 @@ mod tests { repo.save().await.unwrap(); // Provision the user on the homeserver - let mxid = state.homeserver_connection.mxid(&user.username); state .homeserver_connection - .provision_user(&ProvisionRequest::new(&mxid, &user.sub)) + .provision_user(&ProvisionRequest::new(&user.username, &user.sub)) .await .unwrap(); diff --git a/crates/handlers/src/admin/v1/users/unlock.rs b/crates/handlers/src/admin/v1/users/unlock.rs index 5584f4a69..944dd77f4 100644 --- a/crates/handlers/src/admin/v1/users/unlock.rs +++ b/crates/handlers/src/admin/v1/users/unlock.rs @@ -112,10 +112,9 @@ mod tests { // Also provision the user on the homeserver, because this endpoint will try to // reactivate it - let mxid = state.homeserver_connection.mxid(&user.username); state .homeserver_connection - .provision_user(&ProvisionRequest::new(&mxid, &user.sub)) + .provision_user(&ProvisionRequest::new(&user.username, &user.sub)) .await .unwrap(); @@ -149,21 +148,24 @@ mod tests { repo.save().await.unwrap(); // Provision the user on the homeserver - let mxid = state.homeserver_connection.mxid(&user.username); state .homeserver_connection - .provision_user(&ProvisionRequest::new(&mxid, &user.sub)) + .provision_user(&ProvisionRequest::new(&user.username, &user.sub)) .await .unwrap(); // but then deactivate it state .homeserver_connection - .delete_user(&mxid, true) + .delete_user(&user.username, true) .await .unwrap(); // The user should be deactivated on the homeserver - let mx_user = state.homeserver_connection.query_user(&mxid).await.unwrap(); + let mx_user = state + .homeserver_connection + .query_user(&user.username) + .await + .unwrap(); assert!(mx_user.deactivated); let request = Request::post(format!("/api/admin/v1/users/{}/unlock", user.id)) @@ -182,7 +184,11 @@ mod tests { body["data"]["attributes"]["deactivated_at"], serde_json::json!(state.clock.now()) ); - let mx_user = state.homeserver_connection.query_user(&mxid).await.unwrap(); + let mx_user = state + .homeserver_connection + .query_user(&user.username) + .await + .unwrap(); assert!(mx_user.deactivated); } diff --git a/crates/handlers/src/compat/login.rs b/crates/handlers/src/compat/login.rs index 75b96417e..c5e9cd432 100644 --- a/crates/handlers/src/compat/login.rs +++ b/crates/handlers/src/compat/login.rs @@ -411,7 +411,11 @@ pub(crate) async fn post( // Now we can create the device on the homeserver, without holding the // transaction if let Err(err) = homeserver - .create_device(&user_id, device.as_str(), session.human_name.as_deref()) + .create_device( + &user.username, + device.as_str(), + session.human_name.as_deref(), + ) .await { // Something went wrong, let's end this session and schedule a device sync @@ -829,10 +833,9 @@ mod tests { .add(&mut rng, &state.clock, &user, version, hash, None) .await .unwrap(); - let mxid = state.homeserver_connection.mxid(&user.username); state .homeserver_connection - .provision_user(&ProvisionRequest::new(mxid, &user.sub)) + .provision_user(&ProvisionRequest::new(&user.username, &user.sub)) .await .unwrap(); @@ -1133,10 +1136,9 @@ mod tests { .await .unwrap(); - let mxid = state.homeserver_connection.mxid(&user.username); state .homeserver_connection - .provision_user(&ProvisionRequest::new(mxid, &user.sub)) + .provision_user(&ProvisionRequest::new(&user.username, &user.sub)) .await .unwrap(); @@ -1239,10 +1241,9 @@ mod tests { let user = repo.user().lock(&state.clock, user).await.unwrap(); repo.save().await.unwrap(); - let mxid = state.homeserver_connection.mxid(&user.username); state .homeserver_connection - .provision_user(&ProvisionRequest::new(mxid, &user.sub)) + .provision_user(&ProvisionRequest::new(&user.username, &user.sub)) .await .unwrap(); diff --git a/crates/handlers/src/graphql/model/matrix.rs b/crates/handlers/src/graphql/model/matrix.rs index 08e583d74..7316c0d63 100644 --- a/crates/handlers/src/graphql/model/matrix.rs +++ b/crates/handlers/src/graphql/model/matrix.rs @@ -27,9 +27,9 @@ impl MatrixUser { conn: &C, user: &str, ) -> Result { - let mxid = conn.mxid(user); + let info = conn.query_user(user).await?; - let info = conn.query_user(&mxid).await?; + let mxid = conn.mxid(user); Ok(MatrixUser { mxid, diff --git a/crates/handlers/src/graphql/mutations/compat_session.rs b/crates/handlers/src/graphql/mutations/compat_session.rs index ec8993942..973d46f05 100644 --- a/crates/handlers/src/graphql/mutations/compat_session.rs +++ b/crates/handlers/src/graphql/mutations/compat_session.rs @@ -187,10 +187,9 @@ impl CompatSessionMutations { .await?; // Update the device on the homeserver side - let mxid = homeserver.mxid(&user.username); if let Some(device) = session.device.as_ref() { homeserver - .update_device_display_name(&mxid, device.as_str(), &input.human_name) + .update_device_display_name(&user.username, device.as_str(), &input.human_name) .await .context("Failed to provision device")?; } diff --git a/crates/handlers/src/graphql/mutations/matrix.rs b/crates/handlers/src/graphql/mutations/matrix.rs index 16c4916c3..f88668e2f 100644 --- a/crates/handlers/src/graphql/mutations/matrix.rs +++ b/crates/handlers/src/graphql/mutations/matrix.rs @@ -93,7 +93,6 @@ impl MatrixMutations { repo.cancel().await?; let conn = state.homeserver_connection(); - let mxid = conn.mxid(&user.username); if let Some(display_name) = &input.display_name { // Let's do some basic validation on the display name @@ -105,11 +104,11 @@ impl MatrixMutations { return Ok(SetDisplayNamePayload::Invalid); } - conn.set_displayname(&mxid, display_name) + conn.set_displayname(&user.username, display_name) .await .context("Failed to set display name")?; } else { - conn.unset_displayname(&mxid) + conn.unset_displayname(&user.username) .await .context("Failed to unset display name")?; } diff --git a/crates/handlers/src/graphql/mutations/oauth2_session.rs b/crates/handlers/src/graphql/mutations/oauth2_session.rs index 0de5b16a2..27f253394 100644 --- a/crates/handlers/src/graphql/mutations/oauth2_session.rs +++ b/crates/handlers/src/graphql/mutations/oauth2_session.rs @@ -212,11 +212,10 @@ impl OAuth2SessionMutations { repo.user().acquire_lock_for_sync(&user).await?; // Look for devices to provision - let mxid = homeserver.mxid(&user.username); for scope in &*session.scope { if let Some(device) = Device::from_scope_token(scope) { homeserver - .create_device(&mxid, device.as_str(), None) + .create_device(&user.username, device.as_str(), None) .await .context("Failed to provision device")?; } @@ -331,11 +330,10 @@ impl OAuth2SessionMutations { .await?; // Update the device on the homeserver side - let mxid = homeserver.mxid(&user.username); for scope in &*session.scope { if let Some(device) = Device::from_scope_token(scope) { homeserver - .update_device_display_name(&mxid, device.as_str(), &input.human_name) + .update_device_display_name(&user.username, device.as_str(), &input.human_name) .await .context("Failed to provision device")?; } diff --git a/crates/handlers/src/graphql/mutations/user.rs b/crates/handlers/src/graphql/mutations/user.rs index 26352db81..f9f5696e7 100644 --- a/crates/handlers/src/graphql/mutations/user.rs +++ b/crates/handlers/src/graphql/mutations/user.rs @@ -586,8 +586,7 @@ impl UserMutations { }; // Call the homeserver synchronously to reactivate the user - let mxid = matrix.mxid(&user.username); - matrix.reactivate_user(&mxid).await?; + matrix.reactivate_user(&user.username).await?; // Now reactivate & unlock the user in our database let user = repo.user().reactivate(user).await?; @@ -654,9 +653,7 @@ impl UserMutations { }; let conn = state.homeserver_connection(); - let mxid = conn.mxid(&user.username); - - conn.allow_cross_signing_reset(&mxid) + conn.allow_cross_signing_reset(&user.username) .await .context("Failed to allow cross-signing reset")?; diff --git a/crates/handlers/src/graphql/tests.rs b/crates/handlers/src/graphql/tests.rs index df4b5b80b..bc5079924 100644 --- a/crates/handlers/src/graphql/tests.rs +++ b/crates/handlers/src/graphql/tests.rs @@ -529,10 +529,9 @@ async fn test_oauth2_client_credentials(pool: PgPool) { // XXX: we don't run the task worker here, so even though the addUser mutation // should have scheduled a job to provision the user, it won't run in the test, // so we need to do it manually - let mxid = state.homeserver_connection.mxid("alice"); state .homeserver_connection - .provision_user(&ProvisionRequest::new(mxid, user_id)) + .provision_user(&ProvisionRequest::new("alice", user_id)) .await .unwrap(); diff --git a/crates/handlers/src/oauth2/introspection.rs b/crates/handlers/src/oauth2/introspection.rs index b1a7a99ea..50c043b04 100644 --- a/crates/handlers/src/oauth2/introspection.rs +++ b/crates/handlers/src/oauth2/introspection.rs @@ -634,10 +634,9 @@ mod tests { .await .unwrap(); - let mxid = state.homeserver_connection.mxid(&user.username); state .homeserver_connection - .provision_user(&ProvisionRequest::new(mxid, &user.sub)) + .provision_user(&ProvisionRequest::new(&user.username, &user.sub)) .await .unwrap(); @@ -835,10 +834,9 @@ mod tests { .await .unwrap(); - let mxid = state.homeserver_connection.mxid(&user.username); state .homeserver_connection - .provision_user(&ProvisionRequest::new(mxid, &user.sub)) + .provision_user(&ProvisionRequest::new(&user.username, &user.sub)) .await .unwrap(); diff --git a/crates/handlers/src/oauth2/token.rs b/crates/handlers/src/oauth2/token.rs index 1634e8f2e..a56cf763f 100644 --- a/crates/handlers/src/oauth2/token.rs +++ b/crates/handlers/src/oauth2/token.rs @@ -575,11 +575,14 @@ async fn authorization_code_grant( .await?; // Look for device to provision - let mxid = homeserver.mxid(&browser_session.user.username); for scope in &*session.scope { if let Some(device) = Device::from_scope_token(scope) { homeserver - .create_device(&mxid, device.as_str(), Some(&device_name)) + .create_device( + &browser_session.user.username, + device.as_str(), + Some(&device_name), + ) .await .map_err(RouteError::ProvisionDeviceFailed)?; } @@ -951,11 +954,10 @@ async fn device_code_grant( .await?; // Look for device to provision - let mxid = homeserver.mxid(&browser_session.user.username); for scope in &*session.scope { if let Some(device) = Device::from_scope_token(scope) { homeserver - .create_device(&mxid, device.as_str(), None) + .create_device(&browser_session.user.username, device.as_str(), None) .await .map_err(RouteError::ProvisionDeviceFailed)?; } diff --git a/crates/matrix-synapse/src/lib.rs b/crates/matrix-synapse/src/lib.rs index 28f27d76c..13008b23b 100644 --- a/crates/matrix-synapse/src/lib.rs +++ b/crates/matrix-synapse/src/lib.rs @@ -177,12 +177,13 @@ impl HomeserverConnection for SynapseConnection { skip_all, fields( matrix.homeserver = self.homeserver, - matrix.mxid = mxid, + matrix.localpart = localpart, ), err(Debug), )] - async fn query_user(&self, mxid: &str) -> Result { - let encoded_mxid = urlencoding::encode(mxid); + async fn query_user(&self, localpart: &str) -> Result { + let mxid = self.mxid(localpart); + let encoded_mxid = urlencoding::encode(&mxid); let response = self .get(&format!("_synapse/admin/v2/users/{encoded_mxid}")) @@ -263,7 +264,7 @@ impl HomeserverConnection for SynapseConnection { skip_all, fields( matrix.homeserver = self.homeserver, - matrix.mxid = request.mxid(), + matrix.localpart = request.localpart(), user.id = request.sub(), ), err(Debug), @@ -297,7 +298,8 @@ impl HomeserverConnection for SynapseConnection { ); }); - let encoded_mxid = urlencoding::encode(request.mxid()); + let mxid = self.mxid(request.localpart()); + let encoded_mxid = urlencoding::encode(&mxid); let response = self .put(&format!("_synapse/admin/v2/users/{encoded_mxid}")) .json(&body) @@ -322,18 +324,19 @@ impl HomeserverConnection for SynapseConnection { skip_all, fields( matrix.homeserver = self.homeserver, - matrix.mxid = mxid, + matrix.localpart = localpart, matrix.device_id = device_id, ), err(Debug), )] async fn create_device( &self, - mxid: &str, + localpart: &str, device_id: &str, initial_display_name: Option<&str>, ) -> Result<(), anyhow::Error> { - let encoded_mxid = urlencoding::encode(mxid); + let mxid = self.mxid(localpart); + let encoded_mxid = urlencoding::encode(&mxid); let response = self .post(&format!("_synapse/admin/v2/users/{encoded_mxid}/devices")) @@ -360,7 +363,7 @@ impl HomeserverConnection for SynapseConnection { // It's annoying, but the POST endpoint doesn't let us set the display name // of the device, so we have to do it manually. if let Some(display_name) = initial_display_name { - self.update_device_display_name(mxid, device_id, display_name) + self.update_device_display_name(localpart, device_id, display_name) .await?; } @@ -372,18 +375,19 @@ impl HomeserverConnection for SynapseConnection { skip_all, fields( matrix.homeserver = self.homeserver, - matrix.mxid = mxid, + matrix.localpart = localpart, matrix.device_id = device_id, ), err(Debug), )] async fn update_device_display_name( &self, - mxid: &str, + localpart: &str, device_id: &str, display_name: &str, ) -> Result<(), anyhow::Error> { - let encoded_mxid = urlencoding::encode(mxid); + let mxid = self.mxid(localpart); + let encoded_mxid = urlencoding::encode(&mxid); let device_id = urlencoding::encode(device_id); let response = self .put(&format!( @@ -416,13 +420,14 @@ impl HomeserverConnection for SynapseConnection { skip_all, fields( matrix.homeserver = self.homeserver, - matrix.mxid = mxid, + matrix.localpart = localpart, matrix.device_id = device_id, ), err(Debug), )] - async fn delete_device(&self, mxid: &str, device_id: &str) -> Result<(), anyhow::Error> { - let encoded_mxid = urlencoding::encode(mxid); + async fn delete_device(&self, localpart: &str, device_id: &str) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); + let encoded_mxid = urlencoding::encode(&mxid); let encoded_device_id = urlencoding::encode(device_id); let response = self @@ -453,17 +458,18 @@ impl HomeserverConnection for SynapseConnection { skip_all, fields( matrix.homeserver = self.homeserver, - matrix.mxid = mxid, + matrix.localpart = localpart, ), err(Debug), )] async fn sync_devices( &self, - mxid: &str, + localpart: &str, devices: HashSet, ) -> Result<(), anyhow::Error> { // Get the list of current devices - let encoded_mxid = urlencoding::encode(mxid); + let mxid = self.mxid(localpart); + let encoded_mxid = urlencoding::encode(&mxid); let response = self .get(&format!("_synapse/admin/v2/users/{encoded_mxid}/devices")) @@ -519,7 +525,7 @@ impl HomeserverConnection for SynapseConnection { // Then, create the devices that are missing. There is no batching API to do // this, so we do this sequentially, which is fine as the API is idempotent. for device_id in devices.difference(&existing_devices) { - self.create_device(mxid, device_id, None).await?; + self.create_device(localpart, device_id, None).await?; } Ok(()) @@ -530,13 +536,14 @@ impl HomeserverConnection for SynapseConnection { skip_all, fields( matrix.homeserver = self.homeserver, - matrix.mxid = mxid, + matrix.localpart = localpart, erase = erase, ), err(Debug), )] - async fn delete_user(&self, mxid: &str, erase: bool) -> Result<(), anyhow::Error> { - let encoded_mxid = urlencoding::encode(mxid); + async fn delete_user(&self, localpart: &str, erase: bool) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); + let encoded_mxid = urlencoding::encode(&mxid); let response = self .post(&format!("_synapse/admin/v1/deactivate/{encoded_mxid}")) @@ -567,12 +574,13 @@ impl HomeserverConnection for SynapseConnection { skip_all, fields( matrix.homeserver = self.homeserver, - matrix.mxid = mxid, + matrix.localpart = localpart, ), err(Debug), )] - async fn reactivate_user(&self, mxid: &str) -> Result<(), anyhow::Error> { - let encoded_mxid = urlencoding::encode(mxid); + async fn reactivate_user(&self, localpart: &str) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); + let encoded_mxid = urlencoding::encode(&mxid); let response = self .put(&format!("_synapse/admin/v2/users/{encoded_mxid}")) .json(&SynapseUser { @@ -599,13 +607,18 @@ impl HomeserverConnection for SynapseConnection { skip_all, fields( matrix.homeserver = self.homeserver, - matrix.mxid = mxid, + matrix.localpart = localpart, matrix.displayname = displayname, ), err(Debug), )] - async fn set_displayname(&self, mxid: &str, displayname: &str) -> Result<(), anyhow::Error> { - let encoded_mxid = urlencoding::encode(mxid); + async fn set_displayname( + &self, + localpart: &str, + displayname: &str, + ) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); + let encoded_mxid = urlencoding::encode(&mxid); let response = self .put(&format!( "_matrix/client/v3/profile/{encoded_mxid}/displayname" @@ -635,12 +648,12 @@ impl HomeserverConnection for SynapseConnection { skip_all, fields( matrix.homeserver = self.homeserver, - matrix.mxid = mxid, + matrix.localpart = localpart, ), err(Display), )] - async fn unset_displayname(&self, mxid: &str) -> Result<(), anyhow::Error> { - self.set_displayname(mxid, "").await + async fn unset_displayname(&self, localpart: &str) -> Result<(), anyhow::Error> { + self.set_displayname(localpart, "").await } #[tracing::instrument( @@ -648,12 +661,13 @@ impl HomeserverConnection for SynapseConnection { skip_all, fields( matrix.homeserver = self.homeserver, - matrix.mxid = mxid, + matrix.localpart = localpart, ), err(Debug), )] - async fn allow_cross_signing_reset(&self, mxid: &str) -> Result<(), anyhow::Error> { - let encoded_mxid = urlencoding::encode(mxid); + async fn allow_cross_signing_reset(&self, localpart: &str) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); + let encoded_mxid = urlencoding::encode(&mxid); let response = self .post(&format!( diff --git a/crates/matrix/src/lib.rs b/crates/matrix/src/lib.rs index 9c0f81bd3..012fba216 100644 --- a/crates/matrix/src/lib.rs +++ b/crates/matrix/src/lib.rs @@ -31,7 +31,7 @@ enum FieldAction { } pub struct ProvisionRequest { - mxid: String, + localpart: String, sub: String, displayname: FieldAction, avatar_url: FieldAction, @@ -43,12 +43,12 @@ impl ProvisionRequest { /// /// # Parameters /// - /// * `mxid` - The Matrix ID to provision. + /// * `localpart` - The localpart of the user to provision. /// * `sub` - The `sub` of the user, aka the internal ID. #[must_use] - pub fn new(mxid: impl Into, sub: impl Into) -> Self { + pub fn new(localpart: impl Into, sub: impl Into) -> Self { Self { - mxid: mxid.into(), + localpart: localpart.into(), sub: sub.into(), displayname: FieldAction::DoNothing, avatar_url: FieldAction::DoNothing, @@ -62,10 +62,10 @@ impl ProvisionRequest { &self.sub } - /// Get the Matrix ID to provision. + /// Get the localpart of the user to provision. #[must_use] - pub fn mxid(&self) -> &str { - &self.mxid + pub fn localpart(&self) -> &str { + &self.localpart } /// Ask to set the displayname of the user. @@ -211,13 +211,13 @@ pub trait HomeserverConnection: Send + Sync { /// /// # Parameters /// - /// * `mxid` - The Matrix ID of the user to query. + /// * `localpart` - The localpart of the user to query. /// /// # Errors /// /// Returns an error if the homeserver is unreachable or the user does not /// exist. - async fn query_user(&self, mxid: &str) -> Result; + async fn query_user(&self, localpart: &str) -> Result; /// Provision a user on the homeserver. /// @@ -247,7 +247,7 @@ pub trait HomeserverConnection: Send + Sync { /// /// # Parameters /// - /// * `mxid` - The Matrix ID of the user to create a device for. + /// * `localpart` - The localpart of the user to create a device for. /// * `device_id` - The device ID to create. /// /// # Errors @@ -256,7 +256,7 @@ pub trait HomeserverConnection: Send + Sync { /// not be created. async fn create_device( &self, - mxid: &str, + localpart: &str, device_id: &str, initial_display_name: Option<&str>, ) -> Result<(), anyhow::Error>; @@ -265,7 +265,7 @@ pub trait HomeserverConnection: Send + Sync { /// /// # Parameters /// - /// * `mxid` - The Matrix ID of the user to update a device for. + /// * `localpart` - The localpart of the user to update a device for. /// * `device_id` - The device ID to update. /// * `display_name` - The new display name to set /// @@ -275,7 +275,7 @@ pub trait HomeserverConnection: Send + Sync { /// not be updated. async fn update_device_display_name( &self, - mxid: &str, + localpart: &str, device_id: &str, display_name: &str, ) -> Result<(), anyhow::Error>; @@ -284,90 +284,98 @@ pub trait HomeserverConnection: Send + Sync { /// /// # Parameters /// - /// * `mxid` - The Matrix ID of the user to delete a device for. + /// * `localpart` - The localpart of the user to delete a device for. /// * `device_id` - The device ID to delete. /// /// # Errors /// /// Returns an error if the homeserver is unreachable or the device could /// not be deleted. - async fn delete_device(&self, mxid: &str, device_id: &str) -> Result<(), anyhow::Error>; + async fn delete_device(&self, localpart: &str, device_id: &str) -> Result<(), anyhow::Error>; /// Sync the list of devices of a user with the homeserver. /// /// # Parameters /// - /// * `mxid` - The Matrix ID of the user to sync the devices for. + /// * `localpart` - The localpart of the user to sync the devices for. /// * `devices` - The list of devices to sync. /// /// # Errors /// /// Returns an error if the homeserver is unreachable or the devices could /// not be synced. - async fn sync_devices(&self, mxid: &str, devices: HashSet) - -> Result<(), anyhow::Error>; + async fn sync_devices( + &self, + localpart: &str, + devices: HashSet, + ) -> Result<(), anyhow::Error>; /// Delete a user on the homeserver. /// /// # Parameters /// - /// * `mxid` - The Matrix ID of the user to delete. + /// * `localpart` - The localpart of the user to delete. /// * `erase` - Whether to ask the homeserver to erase the user's data. /// /// # Errors /// /// Returns an error if the homeserver is unreachable or the user could not /// be deleted. - async fn delete_user(&self, mxid: &str, erase: bool) -> Result<(), anyhow::Error>; + async fn delete_user(&self, localpart: &str, erase: bool) -> Result<(), anyhow::Error>; /// Reactivate a user on the homeserver. /// /// # Parameters /// - /// * `mxid` - The Matrix ID of the user to reactivate. + /// * `localpart` - The localpart of the user to reactivate. /// /// # Errors /// /// Returns an error if the homeserver is unreachable or the user could not /// be reactivated. - async fn reactivate_user(&self, mxid: &str) -> Result<(), anyhow::Error>; + async fn reactivate_user(&self, localpart: &str) -> Result<(), anyhow::Error>; /// Set the displayname of a user on the homeserver. /// /// # Parameters /// - /// * `mxid` - The Matrix ID of the user to set the displayname for. + /// * `localpart` - The localpart of the user to set the displayname for. /// * `displayname` - The displayname to set. /// /// # Errors /// /// Returns an error if the homeserver is unreachable or the displayname /// could not be set. - async fn set_displayname(&self, mxid: &str, displayname: &str) -> Result<(), anyhow::Error>; + async fn set_displayname( + &self, + localpart: &str, + displayname: &str, + ) -> Result<(), anyhow::Error>; /// Unset the displayname of a user on the homeserver. /// /// # Parameters /// - /// * `mxid` - The Matrix ID of the user to unset the displayname for. + /// * `localpart` - The localpart of the user to unset the displayname for. /// /// # Errors /// /// Returns an error if the homeserver is unreachable or the displayname /// could not be unset. - async fn unset_displayname(&self, mxid: &str) -> Result<(), anyhow::Error>; + async fn unset_displayname(&self, localpart: &str) -> Result<(), anyhow::Error>; /// Temporarily allow a user to reset their cross-signing keys. /// /// # Parameters /// - /// * `mxid` - The Matrix ID of the user to allow cross-signing key reset + /// * `localpart` - The localpart of the user to allow cross-signing key + /// reset /// /// # Errors /// /// Returns an error if the homeserver is unreachable or the cross-signing /// reset could not be allowed. - async fn allow_cross_signing_reset(&self, mxid: &str) -> Result<(), anyhow::Error>; + async fn allow_cross_signing_reset(&self, localpart: &str) -> Result<(), anyhow::Error>; } #[async_trait::async_trait] @@ -376,8 +384,8 @@ impl HomeserverConnection for &T (**self).homeserver() } - async fn query_user(&self, mxid: &str) -> Result { - (**self).query_user(mxid).await + async fn query_user(&self, localpart: &str) -> Result { + (**self).query_user(localpart).await } async fn provision_user(&self, request: &ProvisionRequest) -> Result { @@ -390,56 +398,60 @@ impl HomeserverConnection for &T async fn create_device( &self, - mxid: &str, + localpart: &str, device_id: &str, initial_display_name: Option<&str>, ) -> Result<(), anyhow::Error> { (**self) - .create_device(mxid, device_id, initial_display_name) + .create_device(localpart, device_id, initial_display_name) .await } async fn update_device_display_name( &self, - mxid: &str, + localpart: &str, device_id: &str, display_name: &str, ) -> Result<(), anyhow::Error> { (**self) - .update_device_display_name(mxid, device_id, display_name) + .update_device_display_name(localpart, device_id, display_name) .await } - async fn delete_device(&self, mxid: &str, device_id: &str) -> Result<(), anyhow::Error> { - (**self).delete_device(mxid, device_id).await + async fn delete_device(&self, localpart: &str, device_id: &str) -> Result<(), anyhow::Error> { + (**self).delete_device(localpart, device_id).await } async fn sync_devices( &self, - mxid: &str, + localpart: &str, devices: HashSet, ) -> Result<(), anyhow::Error> { - (**self).sync_devices(mxid, devices).await + (**self).sync_devices(localpart, devices).await } - async fn delete_user(&self, mxid: &str, erase: bool) -> Result<(), anyhow::Error> { - (**self).delete_user(mxid, erase).await + async fn delete_user(&self, localpart: &str, erase: bool) -> Result<(), anyhow::Error> { + (**self).delete_user(localpart, erase).await } - async fn reactivate_user(&self, mxid: &str) -> Result<(), anyhow::Error> { - (**self).reactivate_user(mxid).await + async fn reactivate_user(&self, localpart: &str) -> Result<(), anyhow::Error> { + (**self).reactivate_user(localpart).await } - async fn set_displayname(&self, mxid: &str, displayname: &str) -> Result<(), anyhow::Error> { - (**self).set_displayname(mxid, displayname).await + async fn set_displayname( + &self, + localpart: &str, + displayname: &str, + ) -> Result<(), anyhow::Error> { + (**self).set_displayname(localpart, displayname).await } - async fn unset_displayname(&self, mxid: &str) -> Result<(), anyhow::Error> { - (**self).unset_displayname(mxid).await + async fn unset_displayname(&self, localpart: &str) -> Result<(), anyhow::Error> { + (**self).unset_displayname(localpart).await } - async fn allow_cross_signing_reset(&self, mxid: &str) -> Result<(), anyhow::Error> { - (**self).allow_cross_signing_reset(mxid).await + async fn allow_cross_signing_reset(&self, localpart: &str) -> Result<(), anyhow::Error> { + (**self).allow_cross_signing_reset(localpart).await } } @@ -450,8 +462,8 @@ impl HomeserverConnection for Arc { (**self).homeserver() } - async fn query_user(&self, mxid: &str) -> Result { - (**self).query_user(mxid).await + async fn query_user(&self, localpart: &str) -> Result { + (**self).query_user(localpart).await } async fn provision_user(&self, request: &ProvisionRequest) -> Result { @@ -464,55 +476,59 @@ impl HomeserverConnection for Arc { async fn create_device( &self, - mxid: &str, + localpart: &str, device_id: &str, initial_display_name: Option<&str>, ) -> Result<(), anyhow::Error> { (**self) - .create_device(mxid, device_id, initial_display_name) + .create_device(localpart, device_id, initial_display_name) .await } async fn update_device_display_name( &self, - mxid: &str, + localpart: &str, device_id: &str, display_name: &str, ) -> Result<(), anyhow::Error> { (**self) - .update_device_display_name(mxid, device_id, display_name) + .update_device_display_name(localpart, device_id, display_name) .await } - async fn delete_device(&self, mxid: &str, device_id: &str) -> Result<(), anyhow::Error> { - (**self).delete_device(mxid, device_id).await + async fn delete_device(&self, localpart: &str, device_id: &str) -> Result<(), anyhow::Error> { + (**self).delete_device(localpart, device_id).await } async fn sync_devices( &self, - mxid: &str, + localpart: &str, devices: HashSet, ) -> Result<(), anyhow::Error> { - (**self).sync_devices(mxid, devices).await + (**self).sync_devices(localpart, devices).await } - async fn delete_user(&self, mxid: &str, erase: bool) -> Result<(), anyhow::Error> { - (**self).delete_user(mxid, erase).await + async fn delete_user(&self, localpart: &str, erase: bool) -> Result<(), anyhow::Error> { + (**self).delete_user(localpart, erase).await } - async fn reactivate_user(&self, mxid: &str) -> Result<(), anyhow::Error> { - (**self).reactivate_user(mxid).await + async fn reactivate_user(&self, localpart: &str) -> Result<(), anyhow::Error> { + (**self).reactivate_user(localpart).await } - async fn set_displayname(&self, mxid: &str, displayname: &str) -> Result<(), anyhow::Error> { - (**self).set_displayname(mxid, displayname).await + async fn set_displayname( + &self, + localpart: &str, + displayname: &str, + ) -> Result<(), anyhow::Error> { + (**self).set_displayname(localpart, displayname).await } - async fn unset_displayname(&self, mxid: &str) -> Result<(), anyhow::Error> { - (**self).unset_displayname(mxid).await + async fn unset_displayname(&self, localpart: &str) -> Result<(), anyhow::Error> { + (**self).unset_displayname(localpart).await } - async fn allow_cross_signing_reset(&self, mxid: &str) -> Result<(), anyhow::Error> { - (**self).allow_cross_signing_reset(mxid).await + async fn allow_cross_signing_reset(&self, localpart: &str) -> Result<(), anyhow::Error> { + (**self).allow_cross_signing_reset(localpart).await } } diff --git a/crates/matrix/src/mock.rs b/crates/matrix/src/mock.rs index 7969fee3c..ce2c61000 100644 --- a/crates/matrix/src/mock.rs +++ b/crates/matrix/src/mock.rs @@ -54,9 +54,10 @@ impl crate::HomeserverConnection for HomeserverConnection { &self.homeserver } - async fn query_user(&self, mxid: &str) -> Result { + async fn query_user(&self, localpart: &str) -> Result { + let mxid = self.mxid(localpart); let users = self.users.read().await; - let user = users.get(mxid).context("User not found")?; + let user = users.get(&mxid).context("User not found")?; Ok(MatrixUser { displayname: user.displayname.clone(), avatar_url: user.avatar_url.clone(), @@ -66,8 +67,9 @@ impl crate::HomeserverConnection for HomeserverConnection { async fn provision_user(&self, request: &ProvisionRequest) -> Result { let mut users = self.users.write().await; - let inserted = !users.contains_key(request.mxid()); - let user = users.entry(request.mxid().to_owned()).or_insert(MockUser { + let mxid = self.mxid(request.localpart()); + let inserted = !users.contains_key(&mxid); + let user = users.entry(mxid).or_insert(MockUser { sub: request.sub().to_owned(), avatar_url: None, displayname: None, @@ -109,49 +111,54 @@ impl crate::HomeserverConnection for HomeserverConnection { async fn create_device( &self, - mxid: &str, + localpart: &str, device_id: &str, _initial_display_name: Option<&str>, ) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); let mut users = self.users.write().await; - let user = users.get_mut(mxid).context("User not found")?; + let user = users.get_mut(&mxid).context("User not found")?; user.devices.insert(device_id.to_owned()); Ok(()) } async fn update_device_display_name( &self, - mxid: &str, + localpart: &str, device_id: &str, _display_name: &str, ) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); let mut users = self.users.write().await; - let user = users.get_mut(mxid).context("User not found")?; + let user = users.get_mut(&mxid).context("User not found")?; user.devices.get(device_id).context("Device not found")?; Ok(()) } - async fn delete_device(&self, mxid: &str, device_id: &str) -> Result<(), anyhow::Error> { + async fn delete_device(&self, localpart: &str, device_id: &str) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); let mut users = self.users.write().await; - let user = users.get_mut(mxid).context("User not found")?; + let user = users.get_mut(&mxid).context("User not found")?; user.devices.remove(device_id); Ok(()) } async fn sync_devices( &self, - mxid: &str, + localpart: &str, devices: HashSet, ) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); let mut users = self.users.write().await; - let user = users.get_mut(mxid).context("User not found")?; + let user = users.get_mut(&mxid).context("User not found")?; user.devices = devices; Ok(()) } - async fn delete_user(&self, mxid: &str, erase: bool) -> Result<(), anyhow::Error> { + async fn delete_user(&self, localpart: &str, erase: bool) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); let mut users = self.users.write().await; - let user = users.get_mut(mxid).context("User not found")?; + let user = users.get_mut(&mxid).context("User not found")?; user.devices.clear(); user.emails = None; user.deactivated = true; @@ -163,31 +170,39 @@ impl crate::HomeserverConnection for HomeserverConnection { Ok(()) } - async fn reactivate_user(&self, mxid: &str) -> Result<(), anyhow::Error> { + async fn reactivate_user(&self, localpart: &str) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); let mut users = self.users.write().await; - let user = users.get_mut(mxid).context("User not found")?; + let user = users.get_mut(&mxid).context("User not found")?; user.deactivated = false; Ok(()) } - async fn set_displayname(&self, mxid: &str, displayname: &str) -> Result<(), anyhow::Error> { + async fn set_displayname( + &self, + localpart: &str, + displayname: &str, + ) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); let mut users = self.users.write().await; - let user = users.get_mut(mxid).context("User not found")?; + let user = users.get_mut(&mxid).context("User not found")?; user.displayname = Some(displayname.to_owned()); Ok(()) } - async fn unset_displayname(&self, mxid: &str) -> Result<(), anyhow::Error> { + async fn unset_displayname(&self, localpart: &str) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); let mut users = self.users.write().await; - let user = users.get_mut(mxid).context("User not found")?; + let user = users.get_mut(&mxid).context("User not found")?; user.displayname = None; Ok(()) } - async fn allow_cross_signing_reset(&self, mxid: &str) -> Result<(), anyhow::Error> { + async fn allow_cross_signing_reset(&self, localpart: &str) -> Result<(), anyhow::Error> { + let mxid = self.mxid(localpart); let mut users = self.users.write().await; - let user = users.get_mut(mxid).context("User not found")?; + let user = users.get_mut(&mxid).context("User not found")?; user.cross_signing_reset_allowed = true; Ok(()) } @@ -207,11 +222,11 @@ mod tests { assert_eq!(conn.homeserver(), "example.org"); assert_eq!(conn.mxid("test"), mxid); - assert!(conn.query_user(mxid).await.is_err()); - assert!(conn.create_device(mxid, device, None).await.is_err()); - assert!(conn.delete_device(mxid, device).await.is_err()); + assert!(conn.query_user("test").await.is_err()); + assert!(conn.create_device("test", device, None).await.is_err()); + assert!(conn.delete_device("test", device).await.is_err()); - let request = ProvisionRequest::new("@test:example.org", "test") + let request = ProvisionRequest::new("test", "test") .set_displayname("Test User".into()) .set_avatar_url("mxc://example.org/1234567890".into()) .set_emails(vec!["test@example.org".to_owned()]); @@ -219,33 +234,33 @@ mod tests { let inserted = conn.provision_user(&request).await.unwrap(); assert!(inserted); - let user = conn.query_user(mxid).await.unwrap(); + let user = conn.query_user("test").await.unwrap(); assert_eq!(user.displayname, Some("Test User".into())); assert_eq!(user.avatar_url, Some("mxc://example.org/1234567890".into())); // Set the displayname again - assert!(conn.set_displayname(mxid, "John").await.is_ok()); + assert!(conn.set_displayname("test", "John").await.is_ok()); - let user = conn.query_user(mxid).await.unwrap(); + let user = conn.query_user("test").await.unwrap(); assert_eq!(user.displayname, Some("John".into())); // Unset the displayname - assert!(conn.unset_displayname(mxid).await.is_ok()); + assert!(conn.unset_displayname("test").await.is_ok()); - let user = conn.query_user(mxid).await.unwrap(); + let user = conn.query_user("test").await.unwrap(); assert_eq!(user.displayname, None); // Deleting a non-existent device should not fail - assert!(conn.delete_device(mxid, device).await.is_ok()); + assert!(conn.delete_device("test", device).await.is_ok()); // Create the device - assert!(conn.create_device(mxid, device, None).await.is_ok()); + assert!(conn.create_device("test", device, None).await.is_ok()); // Create the same device again - assert!(conn.create_device(mxid, device, None).await.is_ok()); + assert!(conn.create_device("test", device, None).await.is_ok()); // XXX: there is no API to query devices yet in the trait // Delete the device - assert!(conn.delete_device(mxid, device).await.is_ok()); + assert!(conn.delete_device("test", device).await.is_ok()); // The user we just created should be not available assert!(!conn.is_localpart_available("test").await.unwrap()); diff --git a/crates/matrix/src/readonly.rs b/crates/matrix/src/readonly.rs index 10a0642c2..39f36204f 100644 --- a/crates/matrix/src/readonly.rs +++ b/crates/matrix/src/readonly.rs @@ -28,8 +28,8 @@ impl HomeserverConnection for ReadOnlyHomeserverConnect self.inner.homeserver() } - async fn query_user(&self, mxid: &str) -> Result { - self.inner.query_user(mxid).await + async fn query_user(&self, localpart: &str) -> Result { + self.inner.query_user(localpart).await } async fn provision_user(&self, _request: &ProvisionRequest) -> Result { @@ -42,7 +42,7 @@ impl HomeserverConnection for ReadOnlyHomeserverConnect async fn create_device( &self, - _mxid: &str, + _localpart: &str, _device_id: &str, _initial_display_name: Option<&str>, ) -> Result<(), anyhow::Error> { @@ -51,42 +51,46 @@ impl HomeserverConnection for ReadOnlyHomeserverConnect async fn update_device_display_name( &self, - _mxid: &str, + _localpart: &str, _device_id: &str, _display_name: &str, ) -> Result<(), anyhow::Error> { anyhow::bail!("Device display name update is not supported in read-only mode"); } - async fn delete_device(&self, _mxid: &str, _device_id: &str) -> Result<(), anyhow::Error> { + async fn delete_device(&self, _localpart: &str, _device_id: &str) -> Result<(), anyhow::Error> { anyhow::bail!("Device deletion is not supported in read-only mode"); } async fn sync_devices( &self, - _mxid: &str, + _localpart: &str, _devices: HashSet, ) -> Result<(), anyhow::Error> { anyhow::bail!("Device synchronization is not supported in read-only mode"); } - async fn delete_user(&self, _mxid: &str, _erase: bool) -> Result<(), anyhow::Error> { + async fn delete_user(&self, _localpart: &str, _erase: bool) -> Result<(), anyhow::Error> { anyhow::bail!("User deletion is not supported in read-only mode"); } - async fn reactivate_user(&self, _mxid: &str) -> Result<(), anyhow::Error> { + async fn reactivate_user(&self, _localpart: &str) -> Result<(), anyhow::Error> { anyhow::bail!("User reactivation is not supported in read-only mode"); } - async fn set_displayname(&self, _mxid: &str, _displayname: &str) -> Result<(), anyhow::Error> { + async fn set_displayname( + &self, + _localpart: &str, + _displayname: &str, + ) -> Result<(), anyhow::Error> { anyhow::bail!("User displayname update is not supported in read-only mode"); } - async fn unset_displayname(&self, _mxid: &str) -> Result<(), anyhow::Error> { + async fn unset_displayname(&self, _localpart: &str) -> Result<(), anyhow::Error> { anyhow::bail!("User displayname update is not supported in read-only mode"); } - async fn allow_cross_signing_reset(&self, _mxid: &str) -> Result<(), anyhow::Error> { + async fn allow_cross_signing_reset(&self, _localpart: &str) -> Result<(), anyhow::Error> { anyhow::bail!("Allowing cross-signing reset is not supported in read-only mode"); } } diff --git a/crates/tasks/src/matrix.rs b/crates/tasks/src/matrix.rs index 92e15f448..4855a4bf1 100644 --- a/crates/tasks/src/matrix.rs +++ b/crates/tasks/src/matrix.rs @@ -51,7 +51,6 @@ impl RunnableJob for ProvisionUserJob { .context("User not found") .map_err(JobError::fail)?; - let mxid = matrix.mxid(&user.username); let emails = repo .user_email() .all(&user) @@ -60,7 +59,8 @@ impl RunnableJob for ProvisionUserJob { .into_iter() .map(|email| email.email) .collect(); - let mut request = ProvisionRequest::new(mxid.clone(), user.sub.clone()).set_emails(emails); + let mut request = + ProvisionRequest::new(user.username.clone(), user.sub.clone()).set_emails(emails); if let Some(display_name) = self.display_name_to_set() { request = request.set_displayname(display_name.to_owned()); @@ -71,6 +71,7 @@ impl RunnableJob for ProvisionUserJob { .await .map_err(JobError::retry)?; + let mxid = matrix.mxid(&user.username); if created { info!(%user.id, %mxid, "User created"); } else { @@ -241,9 +242,8 @@ impl RunnableJob for SyncDevicesJob { } } - let mxid = matrix.mxid(&user.username); matrix - .sync_devices(&mxid, devices) + .sync_devices(&user.username, devices) .await .map_err(JobError::retry)?;