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
Add API to check localpart availability
This commit is contained in:
@@ -175,6 +175,37 @@ impl HomeserverConnection for SynapseConnection {
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(
|
||||
name = "homeserver.is_localpart_available",
|
||||
skip_all,
|
||||
fields(
|
||||
matrix.homeserver = self.homeserver,
|
||||
matrix.localpart = localpart,
|
||||
),
|
||||
err(Display),
|
||||
)]
|
||||
async fn is_localpart_available(&self, localpart: &str) -> Result<bool, Self::Error> {
|
||||
let mut client = self
|
||||
.http_client_factory
|
||||
.client("homeserver.is_localpart_available");
|
||||
|
||||
let request = self
|
||||
.get(&format!(
|
||||
"_synapse/admin/v1/username_available?username={localpart}"
|
||||
))
|
||||
.body(EmptyBody::new())?;
|
||||
|
||||
let response = client.ready().await?.call(request).await?;
|
||||
|
||||
match response.status() {
|
||||
StatusCode::OK => Ok(true),
|
||||
StatusCode::BAD_REQUEST => Ok(false),
|
||||
_ => Err(anyhow::anyhow!(
|
||||
"Failed to query localpart availability from Synapse"
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(
|
||||
name = "homeserver.provision_user",
|
||||
skip_all,
|
||||
|
@@ -219,6 +219,17 @@ pub trait HomeserverConnection: Send + Sync {
|
||||
/// be provisioned.
|
||||
async fn provision_user(&self, request: &ProvisionRequest) -> Result<bool, Self::Error>;
|
||||
|
||||
/// Check whether a given username is available on the homeserver.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `localpart` - The localpart to check.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the homeserver is unreachable.
|
||||
async fn is_localpart_available(&self, localpart: &str) -> Result<bool, Self::Error>;
|
||||
|
||||
/// Create a device for a user on the homeserver.
|
||||
///
|
||||
/// # Parameters
|
||||
@@ -312,6 +323,10 @@ impl<T: HomeserverConnection + Send + Sync + ?Sized> HomeserverConnection for &T
|
||||
(**self).provision_user(request).await
|
||||
}
|
||||
|
||||
async fn is_localpart_available(&self, localpart: &str) -> Result<bool, Self::Error> {
|
||||
(**self).is_localpart_available(localpart).await
|
||||
}
|
||||
|
||||
async fn create_device(&self, mxid: &str, device_id: &str) -> Result<(), Self::Error> {
|
||||
(**self).create_device(mxid, device_id).await
|
||||
}
|
||||
|
@@ -34,6 +34,7 @@ struct MockUser {
|
||||
pub struct HomeserverConnection {
|
||||
homeserver: String,
|
||||
users: RwLock<HashMap<String, MockUser>>,
|
||||
reserved_localparts: RwLock<HashSet<&'static str>>,
|
||||
}
|
||||
|
||||
impl HomeserverConnection {
|
||||
@@ -45,8 +46,13 @@ impl HomeserverConnection {
|
||||
Self {
|
||||
homeserver: homeserver.into(),
|
||||
users: RwLock::new(HashMap::new()),
|
||||
reserved_localparts: RwLock::new(HashSet::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reserve_localpart(&self, localpart: &'static str) {
|
||||
self.reserved_localparts.write().await.insert(localpart);
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -98,6 +104,16 @@ impl crate::HomeserverConnection for HomeserverConnection {
|
||||
Ok(inserted)
|
||||
}
|
||||
|
||||
async fn is_localpart_available(&self, localpart: &str) -> Result<bool, Self::Error> {
|
||||
if self.reserved_localparts.read().await.contains(localpart) {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let mxid = self.mxid(localpart);
|
||||
let users = self.users.read().await;
|
||||
Ok(!users.contains_key(&mxid))
|
||||
}
|
||||
|
||||
async fn create_device(&self, mxid: &str, device_id: &str) -> Result<(), Self::Error> {
|
||||
let mut users = self.users.write().await;
|
||||
let user = users.get_mut(mxid).context("User not found")?;
|
||||
@@ -200,5 +216,14 @@ mod tests {
|
||||
// XXX: there is no API to query devices yet in the trait
|
||||
// Delete the device
|
||||
assert!(conn.delete_device(mxid, device).await.is_ok());
|
||||
|
||||
// The user we just created should be not available
|
||||
assert!(!conn.is_localpart_available("test").await.unwrap());
|
||||
// But another user should be
|
||||
assert!(conn.is_localpart_available("alice").await.unwrap());
|
||||
|
||||
// Reserve the localpart, it should not be available anymore
|
||||
conn.reserve_localpart("alice").await;
|
||||
assert!(!conn.is_localpart_available("alice").await.unwrap());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user