add appservice MSC4190 support
Signed-off-by: June Clementine Strawberry <june@3.dog>
This commit is contained in:
parent
0e0b8cc403
commit
24be579477
7 changed files with 125 additions and 50 deletions
22
Cargo.lock
generated
22
Cargo.lock
generated
|
@ -3531,7 +3531,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma"
|
||||
version = "0.10.1"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=ea1278657125e9414caada074e8c172bc252fb1c#ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=0701341a2fd5a6ea74beada18d5974cc401a4fc1#0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
dependencies = [
|
||||
"assign",
|
||||
"js_int",
|
||||
|
@ -3551,7 +3551,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-appservice-api"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=ea1278657125e9414caada074e8c172bc252fb1c#ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=0701341a2fd5a6ea74beada18d5974cc401a4fc1#0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-common",
|
||||
|
@ -3563,7 +3563,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-client-api"
|
||||
version = "0.18.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=ea1278657125e9414caada074e8c172bc252fb1c#ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=0701341a2fd5a6ea74beada18d5974cc401a4fc1#0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
dependencies = [
|
||||
"as_variant",
|
||||
"assign",
|
||||
|
@ -3586,7 +3586,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-common"
|
||||
version = "0.13.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=ea1278657125e9414caada074e8c172bc252fb1c#ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=0701341a2fd5a6ea74beada18d5974cc401a4fc1#0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
dependencies = [
|
||||
"as_variant",
|
||||
"base64 0.22.1",
|
||||
|
@ -3618,7 +3618,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-events"
|
||||
version = "0.28.1"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=ea1278657125e9414caada074e8c172bc252fb1c#ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=0701341a2fd5a6ea74beada18d5974cc401a4fc1#0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
dependencies = [
|
||||
"as_variant",
|
||||
"indexmap 2.8.0",
|
||||
|
@ -3643,7 +3643,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-federation-api"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=ea1278657125e9414caada074e8c172bc252fb1c#ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=0701341a2fd5a6ea74beada18d5974cc401a4fc1#0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"headers",
|
||||
|
@ -3665,7 +3665,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-identifiers-validation"
|
||||
version = "0.9.5"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=ea1278657125e9414caada074e8c172bc252fb1c#ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=0701341a2fd5a6ea74beada18d5974cc401a4fc1#0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"thiserror 2.0.12",
|
||||
|
@ -3674,7 +3674,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-identity-service-api"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=ea1278657125e9414caada074e8c172bc252fb1c#ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=0701341a2fd5a6ea74beada18d5974cc401a4fc1#0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-common",
|
||||
|
@ -3684,7 +3684,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-macros"
|
||||
version = "0.13.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=ea1278657125e9414caada074e8c172bc252fb1c#ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=0701341a2fd5a6ea74beada18d5974cc401a4fc1#0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro-crate",
|
||||
|
@ -3699,7 +3699,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-push-gateway-api"
|
||||
version = "0.9.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=ea1278657125e9414caada074e8c172bc252fb1c#ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=0701341a2fd5a6ea74beada18d5974cc401a4fc1#0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-common",
|
||||
|
@ -3711,7 +3711,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-signatures"
|
||||
version = "0.15.0"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=ea1278657125e9414caada074e8c172bc252fb1c#ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
source = "git+https://github.com/girlbossceo/ruwuma?rev=0701341a2fd5a6ea74beada18d5974cc401a4fc1#0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"ed25519-dalek",
|
||||
|
|
|
@ -346,7 +346,7 @@ version = "0.1.2"
|
|||
[workspace.dependencies.ruma]
|
||||
git = "https://github.com/girlbossceo/ruwuma"
|
||||
#branch = "conduwuit-changes"
|
||||
rev = "ea1278657125e9414caada074e8c172bc252fb1c"
|
||||
rev = "0701341a2fd5a6ea74beada18d5974cc401a4fc1"
|
||||
features = [
|
||||
"compat",
|
||||
"rand",
|
||||
|
|
|
@ -318,14 +318,14 @@ pub(crate) async fn register_route(
|
|||
// Success!
|
||||
},
|
||||
| _ => match body.json_body {
|
||||
| Some(json) => {
|
||||
| Some(ref json) => {
|
||||
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
|
||||
services.uiaa.create(
|
||||
&UserId::parse_with_server_name("", services.globals.server_name())
|
||||
.unwrap(),
|
||||
"".into(),
|
||||
&uiaainfo,
|
||||
&json,
|
||||
json,
|
||||
);
|
||||
return Err(Error::Uiaa(uiaainfo));
|
||||
},
|
||||
|
@ -373,8 +373,12 @@ pub(crate) async fn register_route(
|
|||
)
|
||||
.await?;
|
||||
|
||||
// Inhibit login does not work for guests
|
||||
if !is_guest && body.inhibit_login {
|
||||
if (!is_guest && body.inhibit_login)
|
||||
|| body
|
||||
.appservice_info
|
||||
.as_ref()
|
||||
.is_some_and(|appservice| appservice.registration.device_management)
|
||||
{
|
||||
return Ok(register::v3::Response {
|
||||
access_token: None,
|
||||
user_id,
|
||||
|
|
|
@ -22,7 +22,13 @@ pub(crate) async fn appservice_ping(
|
|||
)));
|
||||
}
|
||||
|
||||
if appservice_info.registration.url.is_none() {
|
||||
if appservice_info.registration.url.is_none()
|
||||
|| appservice_info
|
||||
.registration
|
||||
.url
|
||||
.as_ref()
|
||||
.is_some_and(|url| url.is_empty() || url == "null")
|
||||
{
|
||||
return Err!(Request(UrlNotSet(
|
||||
"Appservice does not have a URL set, there is nothing to ping."
|
||||
)));
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use axum::extract::State;
|
||||
use axum_client_ip::InsecureClientIp;
|
||||
use conduwuit::{Err, err};
|
||||
use conduwuit::{Err, debug, err};
|
||||
use futures::StreamExt;
|
||||
use ruma::{
|
||||
MilliSecondsSinceUnixEpoch,
|
||||
MilliSecondsSinceUnixEpoch, OwnedDeviceId,
|
||||
api::client::{
|
||||
device::{self, delete_device, delete_devices, get_device, get_devices, update_device},
|
||||
error::ErrorKind,
|
||||
|
@ -12,7 +12,7 @@ use ruma::{
|
|||
};
|
||||
|
||||
use super::SESSION_ID_LENGTH;
|
||||
use crate::{Error, Result, Ruma, utils};
|
||||
use crate::{Error, Result, Ruma, client::DEVICE_ID_LENGTH, utils};
|
||||
|
||||
/// # `GET /_matrix/client/r0/devices`
|
||||
///
|
||||
|
@ -59,14 +59,15 @@ pub(crate) async fn update_device_route(
|
|||
InsecureClientIp(client): InsecureClientIp,
|
||||
body: Ruma<update_device::v3::Request>,
|
||||
) -> Result<update_device::v3::Response> {
|
||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||
let sender_user = body.sender_user();
|
||||
let appservice = body.appservice_info.as_ref();
|
||||
|
||||
let mut device = services
|
||||
match services
|
||||
.users
|
||||
.get_device_metadata(sender_user, &body.device_id)
|
||||
.await
|
||||
.map_err(|_| err!(Request(NotFound("Device not found."))))?;
|
||||
|
||||
{
|
||||
| Ok(mut device) => {
|
||||
device.display_name.clone_from(&body.display_name);
|
||||
device.last_seen_ip.clone_from(&Some(client.to_string()));
|
||||
device
|
||||
|
@ -79,6 +80,37 @@ pub(crate) async fn update_device_route(
|
|||
.await?;
|
||||
|
||||
Ok(update_device::v3::Response {})
|
||||
},
|
||||
| Err(_) => {
|
||||
let Some(appservice) = appservice else {
|
||||
return Err!(Request(NotFound("Device not found.")));
|
||||
};
|
||||
if !appservice.registration.device_management {
|
||||
return Err!(Request(NotFound("Device not found.")));
|
||||
}
|
||||
|
||||
debug!(
|
||||
"Creating new device for {sender_user} from appservice {} as MSC4190 is enabled \
|
||||
and device ID does not exist",
|
||||
appservice.registration.id
|
||||
);
|
||||
|
||||
let device_id = OwnedDeviceId::from(utils::random_string(DEVICE_ID_LENGTH));
|
||||
|
||||
services
|
||||
.users
|
||||
.create_device(
|
||||
sender_user,
|
||||
&device_id,
|
||||
&appservice.registration.as_token,
|
||||
None,
|
||||
Some(client.to_string()),
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(update_device::v3::Response {});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// # `DELETE /_matrix/client/r0/devices/{deviceId}`
|
||||
|
@ -95,8 +127,21 @@ pub(crate) async fn delete_device_route(
|
|||
State(services): State<crate::State>,
|
||||
body: Ruma<delete_device::v3::Request>,
|
||||
) -> Result<delete_device::v3::Response> {
|
||||
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_user, sender_device) = body.sender();
|
||||
let appservice = body.appservice_info.as_ref();
|
||||
|
||||
if appservice.is_some_and(|appservice| appservice.registration.device_management) {
|
||||
debug!(
|
||||
"Skipping UIAA for {sender_user} as this is from an appservice and MSC4190 is \
|
||||
enabled"
|
||||
);
|
||||
services
|
||||
.users
|
||||
.remove_device(sender_user, &body.device_id)
|
||||
.await;
|
||||
|
||||
return Ok(delete_device::v3::Response {});
|
||||
}
|
||||
|
||||
// UIAA
|
||||
let mut uiaainfo = UiaaInfo {
|
||||
|
@ -120,11 +165,11 @@ pub(crate) async fn delete_device_route(
|
|||
// Success!
|
||||
},
|
||||
| _ => match body.json_body {
|
||||
| Some(json) => {
|
||||
| Some(ref json) => {
|
||||
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
|
||||
services
|
||||
.uiaa
|
||||
.create(sender_user, sender_device, &uiaainfo, &json);
|
||||
.create(sender_user, sender_device, &uiaainfo, json);
|
||||
|
||||
return Err!(Uiaa(uiaainfo));
|
||||
},
|
||||
|
@ -142,11 +187,12 @@ pub(crate) async fn delete_device_route(
|
|||
Ok(delete_device::v3::Response {})
|
||||
}
|
||||
|
||||
/// # `PUT /_matrix/client/r0/devices/{deviceId}`
|
||||
/// # `POST /_matrix/client/v3/delete_devices`
|
||||
///
|
||||
/// Deletes the given device.
|
||||
/// Deletes the given list of devices.
|
||||
///
|
||||
/// - Requires UIAA to verify user password
|
||||
/// - Requires UIAA to verify user password unless from an appservice with
|
||||
/// MSC4190 enabled.
|
||||
///
|
||||
/// For each device:
|
||||
/// - Invalidates access token
|
||||
|
@ -158,8 +204,20 @@ pub(crate) async fn delete_devices_route(
|
|||
State(services): State<crate::State>,
|
||||
body: Ruma<delete_devices::v3::Request>,
|
||||
) -> Result<delete_devices::v3::Response> {
|
||||
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_user, sender_device) = body.sender();
|
||||
let appservice = body.appservice_info.as_ref();
|
||||
|
||||
if appservice.is_some_and(|appservice| appservice.registration.device_management) {
|
||||
debug!(
|
||||
"Skipping UIAA for {sender_user} as this is from an appservice and MSC4190 is \
|
||||
enabled"
|
||||
);
|
||||
for device_id in &body.devices {
|
||||
services.users.remove_device(sender_user, device_id).await;
|
||||
}
|
||||
|
||||
return Ok(delete_devices::v3::Response {});
|
||||
}
|
||||
|
||||
// UIAA
|
||||
let mut uiaainfo = UiaaInfo {
|
||||
|
@ -183,11 +241,11 @@ pub(crate) async fn delete_devices_route(
|
|||
// Success!
|
||||
},
|
||||
| _ => match body.json_body {
|
||||
| Some(json) => {
|
||||
| Some(ref json) => {
|
||||
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
|
||||
services
|
||||
.uiaa
|
||||
.create(sender_user, sender_device, &uiaainfo, &json);
|
||||
.create(sender_user, sender_device, &uiaainfo, json);
|
||||
|
||||
return Err(Error::Uiaa(uiaainfo));
|
||||
},
|
||||
|
|
|
@ -25,6 +25,10 @@ where
|
|||
return Ok(None);
|
||||
};
|
||||
|
||||
if dest == *"null" || dest.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
trace!("Appservice URL \"{dest}\", Appservice ID: {}", registration.id);
|
||||
|
||||
let hs_token = registration.hs_token.as_str();
|
||||
|
@ -34,7 +38,11 @@ where
|
|||
SendAccessToken::IfRequired(hs_token),
|
||||
&VERSIONS,
|
||||
)
|
||||
.map_err(|e| err!(BadServerResponse(warn!("Failed to find destination {dest}: {e}"))))?
|
||||
.map_err(|e| {
|
||||
err!(BadServerResponse(
|
||||
warn!(appservice = %registration.id, "Failed to find destination {dest}: {e:?}")
|
||||
))
|
||||
})?
|
||||
.map(BytesMut::freeze);
|
||||
|
||||
let mut parts = http_request.uri().clone().into_parts();
|
||||
|
@ -51,7 +59,7 @@ where
|
|||
let reqwest_request = reqwest::Request::try_from(http_request)?;
|
||||
|
||||
let mut response = client.execute(reqwest_request).await.map_err(|e| {
|
||||
warn!("Could not send request to appservice \"{}\" at {dest}: {e}", registration.id);
|
||||
warn!("Could not send request to appservice \"{}\" at {dest}: {e:?}", registration.id);
|
||||
e
|
||||
})?;
|
||||
|
||||
|
@ -71,7 +79,7 @@ where
|
|||
|
||||
if !status.is_success() {
|
||||
debug_error!("Appservice response bytes: {:?}", utils::string_from_bytes(&body));
|
||||
return Err!(BadServerResponse(error!(
|
||||
return Err!(BadServerResponse(warn!(
|
||||
"Appservice \"{}\" returned unsuccessful HTTP response {status} at {dest}",
|
||||
registration.id
|
||||
)));
|
||||
|
@ -84,8 +92,8 @@ where
|
|||
);
|
||||
|
||||
response.map(Some).map_err(|e| {
|
||||
err!(BadServerResponse(error!(
|
||||
"Appservice \"{}\" returned invalid response bytes {dest}: {e}",
|
||||
err!(BadServerResponse(warn!(
|
||||
"Appservice \"{}\" returned invalid/malformed response bytes {dest}: {e}",
|
||||
registration.id
|
||||
)))
|
||||
})
|
||||
|
|
|
@ -350,7 +350,6 @@ impl Service {
|
|||
token: &str,
|
||||
) -> Result<()> {
|
||||
let key = (user_id, device_id);
|
||||
// should not be None, but we shouldn't assert either lol...
|
||||
if self.db.userdeviceid_metadata.qry(&key).await.is_err() {
|
||||
return Err!(Database(error!(
|
||||
?user_id,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue