revamp appservice registration to ruma's Registration type

squashed from https://gitlab.com/famedly/conduit/-/merge_requests/583

Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
Matthias Ahouansou 2024-02-07 17:48:01 -05:00 committed by June
parent 0e9eb22ee7
commit 784d307425
13 changed files with 203 additions and 208 deletions

View file

@ -10,7 +10,7 @@ use std::fmt::Write;
use clap::{Parser, Subcommand};
use regex::Regex;
use ruma::{
api::client::error::ErrorKind,
api::{appservice::Registration, client::error::ErrorKind},
events::{
relation::InReplyTo,
room::{
@ -472,7 +472,7 @@ impl Service {
{
let appservice_config = body[1..body.len() - 1].join("\n");
let parsed_config =
serde_yaml::from_str::<serde_yaml::Value>(&appservice_config);
serde_yaml::from_str::<Registration>(&appservice_config);
match parsed_config {
Ok(yaml) => match services().appservice.register_appservice(yaml) {
Ok(id) => RoomMessageEventContent::text_plain(format!(

View file

@ -1,8 +1,10 @@
use ruma::api::appservice::Registration;
use crate::Result;
pub trait Data: Send + Sync {
/// Registers an appservice and returns the ID to the caller
fn register_appservice(&self, yaml: serde_yaml::Value) -> Result<String>;
fn register_appservice(&self, yaml: Registration) -> Result<String>;
/// Remove an appservice registration
///
@ -11,9 +13,9 @@ pub trait Data: Send + Sync {
/// * `service_name` - the name you send to register the service previously
fn unregister_appservice(&self, service_name: &str) -> Result<()>;
fn get_registration(&self, id: &str) -> Result<Option<serde_yaml::Value>>;
fn get_registration(&self, id: &str) -> Result<Option<Registration>>;
fn iter_ids<'a>(&'a self) -> Result<Box<dyn Iterator<Item = Result<String>> + 'a>>;
fn all(&self) -> Result<Vec<(String, serde_yaml::Value)>>;
fn all(&self) -> Result<Vec<(String, Registration)>>;
}

View file

@ -1,6 +1,7 @@
mod data;
pub(crate) use data::Data;
use ruma::api::appservice::Registration;
use crate::Result;
@ -10,7 +11,7 @@ pub struct Service {
impl Service {
/// Registers an appservice and returns the ID to the caller
pub fn register_appservice(&self, yaml: serde_yaml::Value) -> Result<String> {
pub fn register_appservice(&self, yaml: Registration) -> Result<String> {
self.db.register_appservice(yaml)
}
@ -23,7 +24,7 @@ impl Service {
self.db.unregister_appservice(service_name)
}
pub fn get_registration(&self, id: &str) -> Result<Option<serde_yaml::Value>> {
pub fn get_registration(&self, id: &str) -> Result<Option<Registration>> {
self.db.get_registration(id)
}
@ -31,7 +32,7 @@ impl Service {
self.db.iter_ids()
}
pub fn all(&self) -> Result<Vec<(String, serde_yaml::Value)>> {
pub fn all(&self) -> Result<Vec<(String, Registration)>> {
self.db.all()
}
}

View file

@ -2,6 +2,7 @@ use std::{collections::HashSet, sync::Arc};
use crate::Result;
use ruma::{
api::appservice::Registration,
events::{AnyStrippedStateEvent, AnySyncStateEvent},
serde::Raw,
OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, ServerName, UserId,
@ -31,7 +32,7 @@ pub trait Data: Send + Sync {
fn appservice_in_room(
&self,
room_id: &RoomId,
appservice: &(String, serde_yaml::Value),
appservice: &(String, Registration),
) -> Result<bool>;
/// Makes a user forget a room.

View file

@ -4,6 +4,7 @@ use std::{collections::HashSet, sync::Arc};
pub use data::Data;
use ruma::{
api::appservice::Registration,
events::{
direct::DirectEvent,
ignored_user_list::IgnoredUserListEvent,
@ -240,7 +241,7 @@ impl Service {
pub fn appservice_in_room(
&self,
room_id: &RoomId,
appservice: &(String, serde_yaml::Value),
appservice: &(String, Registration),
) -> Result<bool> {
self.db.appservice_in_room(room_id, appservice)
}

View file

@ -621,73 +621,61 @@ impl Service {
.as_ref()
.and_then(|state_key| UserId::parse(state_key.as_str()).ok())
{
if let Some(appservice_uid) = appservice
.1
.get("sender_localpart")
.and_then(|string| string.as_str())
.and_then(|string| {
UserId::parse_with_server_name(string, services().globals.server_name())
.ok()
})
{
if state_key_uid == &appservice_uid {
services()
.sending
.send_pdu_appservice(appservice.0, pdu_id.clone())?;
continue;
}
let appservice_uid = appservice.1.sender_localpart.as_str();
if state_key_uid == appservice_uid {
services()
.sending
.send_pdu_appservice(appservice.0, pdu_id.clone())?;
continue;
}
}
}
if let Some(namespaces) = appservice.1.get("namespaces") {
let users = namespaces
.get("users")
.and_then(|users| users.as_sequence())
.map_or_else(Vec::new, |users| {
users
.iter()
.filter_map(|users| Regex::new(users.get("regex")?.as_str()?).ok())
.collect::<Vec<_>>()
});
let aliases = namespaces
.get("aliases")
.and_then(|aliases| aliases.as_sequence())
.map_or_else(Vec::new, |aliases| {
aliases
.iter()
.filter_map(|aliases| Regex::new(aliases.get("regex")?.as_str()?).ok())
.collect::<Vec<_>>()
});
let rooms = namespaces
.get("rooms")
.and_then(|rooms| rooms.as_sequence());
let namespaces = appservice.1.namespaces;
let matching_users = |users: &Regex| {
users.is_match(pdu.sender.as_str())
|| pdu.kind == TimelineEventType::RoomMember
&& pdu
.state_key
.as_ref()
.map_or(false, |state_key| users.is_match(state_key))
};
let matching_aliases = |aliases: &Regex| {
services()
.rooms
.alias
.local_aliases_for_room(&pdu.room_id)
.filter_map(|r| r.ok())
.any(|room_alias| aliases.is_match(room_alias.as_str()))
};
// TODO: create some helper function to change from Strings to Regexes
let users = namespaces
.users
.iter()
.filter_map(|user| Regex::new(user.regex.as_str()).ok())
.collect::<Vec<_>>();
let aliases = namespaces
.aliases
.iter()
.filter_map(|alias| Regex::new(alias.regex.as_str()).ok())
.collect::<Vec<_>>();
let rooms = namespaces
.rooms
.iter()
.filter_map(|room| Regex::new(room.regex.as_str()).ok())
.collect::<Vec<_>>();
if aliases.iter().any(matching_aliases)
|| rooms.map_or(false, |rooms| rooms.contains(&pdu.room_id.as_str().into()))
|| users.iter().any(matching_users)
{
services()
.sending
.send_pdu_appservice(appservice.0, pdu_id.clone())?;
}
let matching_users = |users: &Regex| {
users.is_match(pdu.sender.as_str())
|| pdu.kind == TimelineEventType::RoomMember
&& pdu
.state_key
.as_ref()
.map_or(false, |state_key| users.is_match(state_key))
};
let matching_aliases = |aliases: &Regex| {
services()
.rooms
.alias
.local_aliases_for_room(&pdu.room_id)
.filter_map(|r| r.ok())
.any(|room_alias| aliases.is_match(room_alias.as_str()))
};
if aliases.iter().any(matching_aliases)
|| rooms
.iter()
.any(|namespace| namespace.is_match(pdu.room_id.as_str()))
|| users.iter().any(matching_users)
{
services()
.sending
.send_pdu_appservice(appservice.0, pdu_id.clone())?;
}
}

View file

@ -23,7 +23,7 @@ use base64::{engine::general_purpose, Engine as _};
use ruma::{
api::{
appservice,
appservice::{self, Registration},
federation::{
self,
transactions::edu::{
@ -520,7 +520,7 @@ impl Service {
let permit = services().sending.maximum_requests.acquire().await;
let response = appservice_server::send_request(
let response = match appservice_server::send_request(
services()
.appservice
.get_registration(id)
@ -547,8 +547,12 @@ impl Service {
},
)
.await
.map(|_response| kind.clone())
.map_err(|e| (kind, e));
{
None => Ok(kind.clone()),
Some(op_resp) => op_resp
.map(|_response| kind.clone())
.map_err(|e| (kind.clone(), e)),
};
drop(permit);
@ -764,12 +768,14 @@ impl Service {
response
}
#[tracing::instrument(skip(self, registration, request))]
/// Sends a request to an appservice
///
/// Only returns None if there is no url specified in the appservice registration file
pub async fn send_appservice_request<T: OutgoingRequest>(
&self,
registration: serde_yaml::Value,
registration: Registration,
request: T,
) -> Result<T::IncomingResponse>
) -> Option<Result<T::IncomingResponse>>
where
T: Debug,
{