You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-08-09 04:22:45 +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(
|
#[tracing::instrument(
|
||||||
name = "homeserver.provision_user",
|
name = "homeserver.provision_user",
|
||||||
skip_all,
|
skip_all,
|
||||||
|
@@ -219,6 +219,17 @@ pub trait HomeserverConnection: Send + Sync {
|
|||||||
/// be provisioned.
|
/// be provisioned.
|
||||||
async fn provision_user(&self, request: &ProvisionRequest) -> Result<bool, Self::Error>;
|
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.
|
/// Create a device for a user on the homeserver.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
@@ -312,6 +323,10 @@ impl<T: HomeserverConnection + Send + Sync + ?Sized> HomeserverConnection for &T
|
|||||||
(**self).provision_user(request).await
|
(**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> {
|
async fn create_device(&self, mxid: &str, device_id: &str) -> Result<(), Self::Error> {
|
||||||
(**self).create_device(mxid, device_id).await
|
(**self).create_device(mxid, device_id).await
|
||||||
}
|
}
|
||||||
|
@@ -34,6 +34,7 @@ struct MockUser {
|
|||||||
pub struct HomeserverConnection {
|
pub struct HomeserverConnection {
|
||||||
homeserver: String,
|
homeserver: String,
|
||||||
users: RwLock<HashMap<String, MockUser>>,
|
users: RwLock<HashMap<String, MockUser>>,
|
||||||
|
reserved_localparts: RwLock<HashSet<&'static str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HomeserverConnection {
|
impl HomeserverConnection {
|
||||||
@@ -45,8 +46,13 @@ impl HomeserverConnection {
|
|||||||
Self {
|
Self {
|
||||||
homeserver: homeserver.into(),
|
homeserver: homeserver.into(),
|
||||||
users: RwLock::new(HashMap::new()),
|
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]
|
#[async_trait]
|
||||||
@@ -98,6 +104,16 @@ impl crate::HomeserverConnection for HomeserverConnection {
|
|||||||
Ok(inserted)
|
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> {
|
async fn create_device(&self, mxid: &str, device_id: &str) -> Result<(), Self::Error> {
|
||||||
let mut users = self.users.write().await;
|
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")?;
|
||||||
@@ -200,5 +216,14 @@ mod tests {
|
|||||||
// XXX: there is no API to query devices yet in the trait
|
// XXX: there is no API to query devices yet in the trait
|
||||||
// Delete the device
|
// Delete the device
|
||||||
assert!(conn.delete_device(mxid, device).await.is_ok());
|
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