mirror of
https://gitlab.com/famedly/conduit.git
synced 2024-12-27 13:03:47 +03:00
Merge branch 'exclusive-namespace-error' into 'next'
feat(appservice): ensure users/aliases outside of namespaces are not accessed See merge request famedly/conduit!634
This commit is contained in:
commit
7c83372336
7 changed files with 202 additions and 39 deletions
|
@ -75,20 +75,13 @@ pub async fn get_register_available_route(
|
||||||
/// - Creates a new account and populates it with default account data
|
/// - Creates a new account and populates it with default account data
|
||||||
/// - If `inhibit_login` is false: Creates a device and returns device id and access_token
|
/// - If `inhibit_login` is false: Creates a device and returns device id and access_token
|
||||||
pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<register::v3::Response> {
|
pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<register::v3::Response> {
|
||||||
if !services().globals.allow_registration() && !body.from_appservice {
|
if !services().globals.allow_registration() && body.appservice_info.is_none() {
|
||||||
return Err(Error::BadRequest(
|
return Err(Error::BadRequest(
|
||||||
ErrorKind::Forbidden,
|
ErrorKind::Forbidden,
|
||||||
"Registration has been disabled.",
|
"Registration has been disabled.",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if body.body.login_type == Some(LoginType::ApplicationService) && !body.from_appservice {
|
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::MissingToken,
|
|
||||||
"Missing appservice token.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_guest = body.kind == RegistrationKind::Guest;
|
let is_guest = body.kind == RegistrationKind::Guest;
|
||||||
|
|
||||||
let user_id = match (&body.username, is_guest) {
|
let user_id = match (&body.username, is_guest) {
|
||||||
|
@ -126,10 +119,30 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if body.body.login_type == Some(LoginType::ApplicationService) {
|
||||||
|
if let Some(ref info) = body.appservice_info {
|
||||||
|
if !info.is_user_match(&user_id) {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"User is not in namespace.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::MissingToken,
|
||||||
|
"Missing appservice token.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if services().appservice.is_exclusive_user_id(&user_id).await {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"User id reserved by appservice.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// UIAA
|
// UIAA
|
||||||
let mut uiaainfo;
|
let mut uiaainfo;
|
||||||
let skip_auth;
|
let skip_auth = if services().globals.config.registration_token.is_some() {
|
||||||
if services().globals.config.registration_token.is_some() {
|
|
||||||
// Registration token required
|
// Registration token required
|
||||||
uiaainfo = UiaaInfo {
|
uiaainfo = UiaaInfo {
|
||||||
flows: vec![AuthFlow {
|
flows: vec![AuthFlow {
|
||||||
|
@ -140,7 +153,7 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
||||||
session: None,
|
session: None,
|
||||||
auth_error: None,
|
auth_error: None,
|
||||||
};
|
};
|
||||||
skip_auth = body.from_appservice;
|
body.appservice_info.is_some()
|
||||||
} else {
|
} else {
|
||||||
// No registration token necessary, but clients must still go through the flow
|
// No registration token necessary, but clients must still go through the flow
|
||||||
uiaainfo = UiaaInfo {
|
uiaainfo = UiaaInfo {
|
||||||
|
@ -152,8 +165,8 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
||||||
session: None,
|
session: None,
|
||||||
auth_error: None,
|
auth_error: None,
|
||||||
};
|
};
|
||||||
skip_auth = body.from_appservice || is_guest;
|
body.appservice_info.is_some() || is_guest
|
||||||
}
|
};
|
||||||
|
|
||||||
if !skip_auth {
|
if !skip_auth {
|
||||||
if let Some(auth) = &body.auth {
|
if let Some(auth) = &body.auth {
|
||||||
|
@ -248,7 +261,7 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
info!("New user {} registered on this server.", user_id);
|
info!("New user {} registered on this server.", user_id);
|
||||||
if !body.from_appservice && !is_guest {
|
if body.appservice_info.is_none() && !is_guest {
|
||||||
services()
|
services()
|
||||||
.admin
|
.admin
|
||||||
.send_message(RoomMessageEventContent::notice_plain(format!(
|
.send_message(RoomMessageEventContent::notice_plain(format!(
|
||||||
|
@ -372,7 +385,7 @@ pub async fn whoami_route(body: Ruma<whoami::v3::Request>) -> Result<whoami::v3:
|
||||||
Ok(whoami::v3::Response {
|
Ok(whoami::v3::Response {
|
||||||
user_id: sender_user.clone(),
|
user_id: sender_user.clone(),
|
||||||
device_id,
|
device_id,
|
||||||
is_guest: services().users.is_deactivated(sender_user)? && !body.from_appservice,
|
is_guest: services().users.is_deactivated(sender_user)? && body.appservice_info.is_none(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,24 @@ pub async fn create_alias_route(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref info) = body.appservice_info {
|
||||||
|
if !info.aliases.is_match(body.room_alias.as_str()) {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"Room alias is not in namespace.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if services()
|
||||||
|
.appservice
|
||||||
|
.is_exclusive_alias(&body.room_alias)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"Room alias reserved by appservice.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if services()
|
if services()
|
||||||
.rooms
|
.rooms
|
||||||
.alias
|
.alias
|
||||||
|
@ -58,6 +76,24 @@ pub async fn delete_alias_route(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref info) = body.appservice_info {
|
||||||
|
if !info.aliases.is_match(body.room_alias.as_str()) {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"Room alias is not in namespace.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if services()
|
||||||
|
.appservice
|
||||||
|
.is_exclusive_alias(&body.room_alias)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"Room alias reserved by appservice.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
services().rooms.alias.remove_alias(&body.room_alias)?;
|
services().rooms.alias.remove_alias(&body.room_alias)?;
|
||||||
|
|
||||||
// TODO: update alt_aliases?
|
// TODO: update alt_aliases?
|
||||||
|
|
|
@ -68,7 +68,7 @@ pub async fn create_room_route(
|
||||||
let state_lock = mutex_state.lock().await;
|
let state_lock = mutex_state.lock().await;
|
||||||
|
|
||||||
if !services().globals.allow_room_creation()
|
if !services().globals.allow_room_creation()
|
||||||
&& !body.from_appservice
|
&& body.appservice_info.is_none()
|
||||||
&& !services().users.is_admin(sender_user)?
|
&& !services().users.is_admin(sender_user)?
|
||||||
{
|
{
|
||||||
return Err(Error::BadRequest(
|
return Err(Error::BadRequest(
|
||||||
|
@ -104,6 +104,22 @@ pub async fn create_room_route(
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
if let Some(ref alias) = alias {
|
||||||
|
if let Some(ref info) = body.appservice_info {
|
||||||
|
if !info.aliases.is_match(alias.as_str()) {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"Room alias is not in namespace.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if services().appservice.is_exclusive_alias(alias).await {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"Room alias reserved by appservice.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let room_version = match body.room_version.clone() {
|
let room_version = match body.room_version.clone() {
|
||||||
Some(room_version) => {
|
Some(room_version) => {
|
||||||
if services()
|
if services()
|
||||||
|
|
|
@ -67,6 +67,13 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
|
||||||
}
|
}
|
||||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?;
|
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?;
|
||||||
|
|
||||||
|
if services().appservice.is_exclusive_user_id(&user_id).await {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"User id reserved by appservice.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let hash = services()
|
let hash = services()
|
||||||
.users
|
.users
|
||||||
.password_hash(&user_id)?
|
.password_hash(&user_id)?
|
||||||
|
@ -102,9 +109,20 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
|
||||||
)
|
)
|
||||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Token is invalid."))?;
|
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Token is invalid."))?;
|
||||||
let username = token.claims.sub.to_lowercase();
|
let username = token.claims.sub.to_lowercase();
|
||||||
UserId::parse_with_server_name(username, services().globals.server_name()).map_err(
|
let user_id =
|
||||||
|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."),
|
UserId::parse_with_server_name(username, services().globals.server_name())
|
||||||
)?
|
.map_err(|_| {
|
||||||
|
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if services().appservice.is_exclusive_user_id(&user_id).await {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"User id reserved by appservice.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
user_id
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::BadRequest(
|
return Err(Error::BadRequest(
|
||||||
ErrorKind::Unknown,
|
ErrorKind::Unknown,
|
||||||
|
@ -116,13 +134,7 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
|
||||||
identifier,
|
identifier,
|
||||||
user,
|
user,
|
||||||
}) => {
|
}) => {
|
||||||
if !body.from_appservice {
|
let user_id = if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) = identifier {
|
||||||
return Err(Error::BadRequest(
|
|
||||||
ErrorKind::MissingToken,
|
|
||||||
"Missing appservice token.",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) = identifier {
|
|
||||||
UserId::parse_with_server_name(
|
UserId::parse_with_server_name(
|
||||||
user_id.to_lowercase(),
|
user_id.to_lowercase(),
|
||||||
services().globals.server_name(),
|
services().globals.server_name(),
|
||||||
|
@ -133,7 +145,23 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
|
||||||
warn!("Bad login type: {:?}", &body.login_info);
|
warn!("Bad login type: {:?}", &body.login_info);
|
||||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Bad login type."));
|
return Err(Error::BadRequest(ErrorKind::Forbidden, "Bad login type."));
|
||||||
}
|
}
|
||||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?
|
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."))?;
|
||||||
|
|
||||||
|
if let Some(ref info) = body.appservice_info {
|
||||||
|
if !info.is_user_match(&user_id) {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"User is not in namespace.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::MissingToken,
|
||||||
|
"Missing appservice token.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
user_id
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
warn!("Unsupported or unknown login type: {:?}", &body.login_info);
|
warn!("Unsupported or unknown login type: {:?}", &body.login_info);
|
||||||
|
@ -199,6 +227,15 @@ pub async fn logout_route(body: Ruma<logout::v3::Request>) -> Result<logout::v3:
|
||||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||||
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
|
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
|
||||||
|
|
||||||
|
if let Some(ref info) = body.appservice_info {
|
||||||
|
if !info.is_user_match(sender_user) {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"User is not in namespace.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
services().users.remove_device(sender_user, sender_device)?;
|
services().users.remove_device(sender_user, sender_device)?;
|
||||||
|
|
||||||
Ok(logout::v3::Response::new())
|
Ok(logout::v3::Response::new())
|
||||||
|
@ -220,6 +257,20 @@ pub async fn logout_all_route(
|
||||||
) -> Result<logout_all::v3::Response> {
|
) -> Result<logout_all::v3::Response> {
|
||||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||||
|
|
||||||
|
if let Some(ref info) = body.appservice_info {
|
||||||
|
if !info.is_user_match(sender_user) {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"User is not in namespace.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::MissingToken,
|
||||||
|
"Missing appservice token.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
for device_id in services().users.all_device_ids(sender_user).flatten() {
|
for device_id in services().users.all_device_ids(sender_user).flatten() {
|
||||||
services().users.remove_device(sender_user, &device_id)?;
|
services().users.remove_device(sender_user, &device_id)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ where
|
||||||
|
|
||||||
let mut json_body = serde_json::from_slice::<CanonicalJsonValue>(&body).ok();
|
let mut json_body = serde_json::from_slice::<CanonicalJsonValue>(&body).ok();
|
||||||
|
|
||||||
let (sender_user, sender_device, sender_servername, from_appservice) =
|
let (sender_user, sender_device, sender_servername, appservice_info) =
|
||||||
match (metadata.authentication, token) {
|
match (metadata.authentication, token) {
|
||||||
(_, Token::Invalid) => {
|
(_, Token::Invalid) => {
|
||||||
return Err(Error::BadRequest(
|
return Err(Error::BadRequest(
|
||||||
|
@ -122,6 +122,14 @@ where
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
|
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
if !info.is_user_match(&user_id) {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Exclusive,
|
||||||
|
"User is not in namespace.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if !services().users.exists(&user_id)? {
|
if !services().users.exists(&user_id)? {
|
||||||
return Err(Error::BadRequest(
|
return Err(Error::BadRequest(
|
||||||
ErrorKind::Forbidden,
|
ErrorKind::Forbidden,
|
||||||
|
@ -129,15 +137,14 @@ where
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check if appservice is allowed to be that user
|
(Some(user_id), None, None, Some(*info))
|
||||||
(Some(user_id), None, None, true)
|
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
AuthScheme::None
|
AuthScheme::None
|
||||||
| AuthScheme::AppserviceToken
|
| AuthScheme::AppserviceToken
|
||||||
| AuthScheme::AccessTokenOptional,
|
| AuthScheme::AccessTokenOptional,
|
||||||
Token::Appservice(_),
|
Token::Appservice(info),
|
||||||
) => (None, None, None, true),
|
) => (None, None, None, Some(*info)),
|
||||||
(AuthScheme::AccessToken, Token::None) => {
|
(AuthScheme::AccessToken, Token::None) => {
|
||||||
return Err(Error::BadRequest(
|
return Err(Error::BadRequest(
|
||||||
ErrorKind::MissingToken,
|
ErrorKind::MissingToken,
|
||||||
|
@ -147,7 +154,7 @@ where
|
||||||
(
|
(
|
||||||
AuthScheme::AccessToken | AuthScheme::AccessTokenOptional | AuthScheme::None,
|
AuthScheme::AccessToken | AuthScheme::AccessTokenOptional | AuthScheme::None,
|
||||||
Token::User((user_id, device_id)),
|
Token::User((user_id, device_id)),
|
||||||
) => (Some(user_id), Some(device_id), None, false),
|
) => (Some(user_id), Some(device_id), None, None),
|
||||||
(AuthScheme::ServerSignatures, Token::None) => {
|
(AuthScheme::ServerSignatures, Token::None) => {
|
||||||
let TypedHeader(Authorization(x_matrix)) = parts
|
let TypedHeader(Authorization(x_matrix)) = parts
|
||||||
.extract::<TypedHeader<Authorization<XMatrix>>>()
|
.extract::<TypedHeader<Authorization<XMatrix>>>()
|
||||||
|
@ -228,7 +235,7 @@ where
|
||||||
BTreeMap::from_iter([(x_matrix.origin.as_str().to_owned(), keys)]);
|
BTreeMap::from_iter([(x_matrix.origin.as_str().to_owned(), keys)]);
|
||||||
|
|
||||||
match ruma::signatures::verify_json(&pub_key_map, &request_map) {
|
match ruma::signatures::verify_json(&pub_key_map, &request_map) {
|
||||||
Ok(()) => (None, None, Some(x_matrix.origin), false),
|
Ok(()) => (None, None, Some(x_matrix.origin), None),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!(
|
warn!(
|
||||||
"Failed to verify json request from {}: {}\n{:?}",
|
"Failed to verify json request from {}: {}\n{:?}",
|
||||||
|
@ -255,7 +262,7 @@ where
|
||||||
| AuthScheme::AppserviceToken
|
| AuthScheme::AppserviceToken
|
||||||
| AuthScheme::AccessTokenOptional,
|
| AuthScheme::AccessTokenOptional,
|
||||||
Token::None,
|
Token::None,
|
||||||
) => (None, None, None, false),
|
) => (None, None, None, None),
|
||||||
(AuthScheme::ServerSignatures, Token::Appservice(_) | Token::User(_)) => {
|
(AuthScheme::ServerSignatures, Token::Appservice(_) | Token::User(_)) => {
|
||||||
return Err(Error::BadRequest(
|
return Err(Error::BadRequest(
|
||||||
ErrorKind::Unauthorized,
|
ErrorKind::Unauthorized,
|
||||||
|
@ -318,7 +325,7 @@ where
|
||||||
sender_user,
|
sender_user,
|
||||||
sender_device,
|
sender_device,
|
||||||
sender_servername,
|
sender_servername,
|
||||||
from_appservice,
|
appservice_info,
|
||||||
json_body,
|
json_body,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::Error;
|
use crate::{service::appservice::RegistrationInfo, Error};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
api::client::uiaa::UiaaResponse, CanonicalJsonValue, OwnedDeviceId, OwnedServerName,
|
api::client::uiaa::UiaaResponse, CanonicalJsonValue, OwnedDeviceId, OwnedServerName,
|
||||||
OwnedUserId,
|
OwnedUserId,
|
||||||
|
@ -16,7 +16,7 @@ pub struct Ruma<T> {
|
||||||
pub sender_servername: Option<OwnedServerName>,
|
pub sender_servername: Option<OwnedServerName>,
|
||||||
// This is None when body is not a valid string
|
// This is None when body is not a valid string
|
||||||
pub json_body: Option<CanonicalJsonValue>,
|
pub json_body: Option<CanonicalJsonValue>,
|
||||||
pub from_appservice: bool,
|
pub appservice_info: Option<RegistrationInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Deref for Ruma<T> {
|
impl<T> Deref for Ruma<T> {
|
||||||
|
|
|
@ -6,7 +6,10 @@ pub use data::Data;
|
||||||
|
|
||||||
use futures_util::Future;
|
use futures_util::Future;
|
||||||
use regex::RegexSet;
|
use regex::RegexSet;
|
||||||
use ruma::api::appservice::{Namespace, Registration};
|
use ruma::{
|
||||||
|
api::appservice::{Namespace, Registration},
|
||||||
|
RoomAliasId, RoomId, UserId,
|
||||||
|
};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::{services, Result};
|
use crate::{services, Result};
|
||||||
|
@ -83,6 +86,18 @@ pub struct RegistrationInfo {
|
||||||
pub rooms: NamespaceRegex,
|
pub rooms: NamespaceRegex,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RegistrationInfo {
|
||||||
|
pub fn is_user_match(&self, user_id: &UserId) -> bool {
|
||||||
|
self.users.is_match(user_id.as_str())
|
||||||
|
|| self.registration.sender_localpart == user_id.localpart()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_exclusive_user_match(&self, user_id: &UserId) -> bool {
|
||||||
|
self.users.is_exclusive_match(user_id.as_str())
|
||||||
|
|| self.registration.sender_localpart == user_id.localpart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<Registration> for RegistrationInfo {
|
impl TryFrom<Registration> for RegistrationInfo {
|
||||||
fn try_from(value: Registration) -> Result<RegistrationInfo, regex::Error> {
|
fn try_from(value: Registration) -> Result<RegistrationInfo, regex::Error> {
|
||||||
Ok(RegistrationInfo {
|
Ok(RegistrationInfo {
|
||||||
|
@ -122,6 +137,7 @@ impl Service {
|
||||||
}
|
}
|
||||||
/// Registers an appservice and returns the ID to the caller.
|
/// Registers an appservice and returns the ID to the caller.
|
||||||
pub async fn register_appservice(&self, yaml: Registration) -> Result<String> {
|
pub async fn register_appservice(&self, yaml: Registration) -> Result<String> {
|
||||||
|
//TODO: Check for collisions between exclusive appservice namespaces
|
||||||
services()
|
services()
|
||||||
.appservice
|
.appservice
|
||||||
.registration_info
|
.registration_info
|
||||||
|
@ -175,6 +191,30 @@ impl Service {
|
||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks if a given user id matches any exclusive appservice regex
|
||||||
|
pub async fn is_exclusive_user_id(&self, user_id: &UserId) -> bool {
|
||||||
|
self.read()
|
||||||
|
.await
|
||||||
|
.values()
|
||||||
|
.any(|info| info.is_exclusive_user_match(user_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if a given room alias matches any exclusive appservice regex
|
||||||
|
pub async fn is_exclusive_alias(&self, alias: &RoomAliasId) -> bool {
|
||||||
|
self.read()
|
||||||
|
.await
|
||||||
|
.values()
|
||||||
|
.any(|info| info.aliases.is_exclusive_match(alias.as_str()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if a given room id matches any exclusive appservice regex
|
||||||
|
pub async fn is_exclusive_room_id(&self, room_id: &RoomId) -> bool {
|
||||||
|
self.read()
|
||||||
|
.await
|
||||||
|
.values()
|
||||||
|
.any(|info| info.rooms.is_exclusive_match(room_id.as_str()))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read(
|
pub fn read(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Future<Output = tokio::sync::RwLockReadGuard<'_, BTreeMap<String, RegistrationInfo>>>
|
) -> impl Future<Output = tokio::sync::RwLockReadGuard<'_, BTreeMap<String, RegistrationInfo>>>
|
||||||
|
|
Loading…
Reference in a new issue