fix: Resolve errors in recently added services

This commit is contained in:
Ginger
2026-04-28 09:16:51 -04:00
parent a4e64383b7
commit 3e1f97487f
10 changed files with 99 additions and 55 deletions
+7 -2
View File
@@ -455,11 +455,16 @@ impl Service {
} }
async fn handle_response(&self, content: RoomMessageEventContent) -> Result<()> { async fn handle_response(&self, content: RoomMessageEventContent) -> Result<()> {
let Some(Relation::Reply(reply )) = content.relates_to.as_ref() else { let Some(Relation::Reply(reply)) = content.relates_to.as_ref() else {
return Ok(()); return Ok(());
}; };
let Ok(pdu) = self.services.timeline.get_pdu(&reply.in_reply_to.event_id).await else { let Ok(pdu) = self
.services
.timeline
.get_pdu(&reply.in_reply_to.event_id)
.await
else {
error!( error!(
event_id = ?reply.in_reply_to.event_id, event_id = ?reply.in_reply_to.event_id,
"Missing admin command in_reply_to event" "Missing admin command in_reply_to event"
+1 -1
View File
@@ -68,7 +68,7 @@ impl Service {
pub fn expect_mailer(&self) -> Result<Mailer<'_>> { pub fn expect_mailer(&self) -> Result<Mailer<'_>> {
self.mailer().ok_or_else(|| { self.mailer().ok_or_else(|| {
err!(Request(FeatureDisabled("This homeserver is not configured to send email."))) err!(Request(Unrecognized("This homeserver is not configured to send email.")))
}) })
} }
} }
+2 -1
View File
@@ -16,6 +16,8 @@ use serde::Serialize;
use url::Url; use url::Url;
use super::Service; use super::Service;
#[cfg(feature = "url_preview")]
use crate::media::mxc::Mxc;
#[derive(Serialize, Default)] #[derive(Serialize, Default)]
pub struct UrlPreviewData { pub struct UrlPreviewData {
@@ -218,7 +220,6 @@ pub async fn download_audio(
pub async fn download_media(&self, url: &str) -> Result<(OwnedMxcUri, usize)> { pub async fn download_media(&self, url: &str) -> Result<(OwnedMxcUri, usize)> {
use conduwuit::utils::random_string; use conduwuit::utils::random_string;
use http::header::CONTENT_TYPE; use http::header::CONTENT_TYPE;
use ruma::Mxc;
let response = self.services.client.url_preview.get(url).send().await?; let response = self.services.client.url_preview.get(url).send().await?;
let content_type = response.headers().get(CONTENT_TYPE).cloned(); let content_type = response.headers().get(CONTENT_TYPE).cloned();
+8 -5
View File
@@ -30,7 +30,8 @@ use ruma::{
}, },
}, },
push::{ push::{
Action, HighlightTweakValue, PushConditionPowerLevelsCtx, PushConditionRoomCtx, PushFormat, Ruleset, Tweak Action, HighlightTweakValue, PushConditionPowerLevelsCtx, PushConditionRoomCtx,
PushFormat, Ruleset, Tweak,
}, },
room_version_rules::{AuthorizationRules, RoomPowerLevelsRules, RoomVersionRules}, room_version_rules::{AuthorizationRules, RoomPowerLevelsRules, RoomVersionRules},
serde::Raw, serde::Raw,
@@ -467,10 +468,12 @@ impl Service {
if !event_id_only { if !event_id_only {
if *event.kind() == TimelineEventType::RoomEncrypted if *event.kind() == TimelineEventType::RoomEncrypted
|| tweaks || tweaks.iter().any(|t| {
.iter() matches!(
.any(|t| matches!(t, Tweak::Highlight(HighlightTweakValue::Yes) | Tweak::Sound(_))) t,
{ Tweak::Highlight(HighlightTweakValue::Yes) | Tweak::Sound(_)
)
}) {
notify.prio = NotificationPriority::High; notify.prio = NotificationPriority::High;
} else { } else {
notify.prio = NotificationPriority::Low; notify.prio = NotificationPriority::Low;
+5 -3
View File
@@ -22,8 +22,10 @@ use futures::{FutureExt, Stream, StreamExt};
use ruma::{ use ruma::{
OwnedServerName, RoomId, ServerName, UserId, OwnedServerName, RoomId, ServerName, UserId,
api::{ api::{
OutgoingRequest, auth_scheme::{NoAuthentication, NoAccessToken, SendAccessToken}, OutgoingRequest,
federation::authentication::ServerSignatures, path_builder::PathBuilder, auth_scheme::{NoAccessToken, NoAuthentication, SendAccessToken},
federation::authentication::ServerSignatures,
path_builder::PathBuilder,
}, },
}; };
use tokio::{task, task::JoinSet}; use tokio::{task, task::JoinSet};
@@ -348,6 +350,7 @@ impl Service {
.execute_unauthenticated(dest, request) .execute_unauthenticated(dest, request)
.await .await
} }
/// Send an unauthenticated federation request with no X-Matrix header. /// Send an unauthenticated federation request with no X-Matrix header.
#[inline] #[inline]
pub async fn send_legacy_media_request<'i, T>( pub async fn send_legacy_media_request<'i, T>(
@@ -362,7 +365,6 @@ impl Service {
> + Debug > + Debug
+ Send, + Send,
{ {
self.services self.services
.federation .federation
.execute_on(&self.services.client.federation, dest, request, SendAccessToken::None) .execute_on(&self.services.client.federation, dest, request, SendAccessToken::None)
+16 -15
View File
@@ -1,7 +1,10 @@
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use ruma::{ use ruma::{
CanonicalJsonObject, CanonicalJsonValue, IdParseError, OwnedEventId, OwnedServerName, OwnedServerSigningKeyId, RoomVersionId, UserId, canonical_json::JsonType, signatures::{JsonError, VerificationError} CanonicalJsonObject, CanonicalJsonValue, IdParseError, OwnedEventId, OwnedServerName,
OwnedServerSigningKeyId, RoomVersionId, UserId,
canonical_json::JsonType,
signatures::{JsonError, VerificationError},
}; };
/// Whether the given event is an `m.room.member` invite that was created as the /// Whether the given event is an `m.room.member` invite that was created as the
@@ -9,7 +12,9 @@ use ruma::{
/// ///
/// Returns an error if the object has not the expected format of an /// Returns an error if the object has not the expected format of an
/// `m.room.member` event. /// `m.room.member` event.
pub(super) fn is_invite_via_third_party_id(object: &CanonicalJsonObject) -> Result<bool, JsonError> { pub(super) fn is_invite_via_third_party_id(
object: &CanonicalJsonObject,
) -> Result<bool, JsonError> {
let Some(CanonicalJsonValue::String(raw_type)) = object.get("type") else { let Some(CanonicalJsonValue::String(raw_type)) = object.get("type") else {
return Err(JsonError::NotOfType { return Err(JsonError::NotOfType {
target: "type".to_owned(), target: "type".to_owned(),
@@ -74,10 +79,8 @@ pub fn servers_to_check_signatures(
if !is_invite_via_third_party_id(object)? { if !is_invite_via_third_party_id(object)? {
match object.get("sender") { match object.get("sender") {
| Some(CanonicalJsonValue::String(raw_sender)) => { | Some(CanonicalJsonValue::String(raw_sender)) => {
let user_id = <&UserId>::try_from(raw_sender.as_str()).map_err(|source| {VerificationError::ParseIdentifier { let user_id = <&UserId>::try_from(raw_sender.as_str()).map_err(|source| {
identifier_type: "user ID", VerificationError::ParseIdentifier { identifier_type: "user ID", source }
source,
}
})?; })?;
servers_to_check.insert(user_id.server_name().to_owned()); servers_to_check.insert(user_id.server_name().to_owned());
@@ -95,18 +98,15 @@ pub fn servers_to_check_signatures(
| RoomVersionId::V1 | RoomVersionId::V2 => match object.get("event_id") { | RoomVersionId::V1 | RoomVersionId::V2 => match object.get("event_id") {
| Some(CanonicalJsonValue::String(raw_event_id)) => { | Some(CanonicalJsonValue::String(raw_event_id)) => {
let event_id: OwnedEventId = raw_event_id.parse().map_err(|source| { let event_id: OwnedEventId = raw_event_id.parse().map_err(|source| {
VerificationError::ParseIdentifier { VerificationError::ParseIdentifier { identifier_type: "event ID", source }
identifier_type: "event ID",
source,
}
})?; })?;
let server_name = event_id let server_name = event_id
.server_name() .server_name()
.ok_or_else(|| VerificationError::ParseIdentifier { .ok_or_else(|| VerificationError::ParseIdentifier {
identifier_type: "event ID", identifier_type: "event ID",
source: IdParseError::InvalidServerName, source: IdParseError::InvalidServerName,
})? })?
.to_owned(); .to_owned();
servers_to_check.insert(server_name); servers_to_check.insert(server_name);
@@ -138,8 +138,9 @@ pub fn servers_to_check_signatures(
} }
.into() .into()
})?; })?;
let authorized_user = <&UserId>::try_from(authorized_user) let authorized_user = <&UserId>::try_from(authorized_user).map_err(|source| {
.map_err(|source| VerificationError::ParseIdentifier { identifier_type: "user ID", source })?; VerificationError::ParseIdentifier { identifier_type: "user ID", source }
})?;
servers_to_check.insert(authorized_user.server_name().to_owned()); servers_to_check.insert(authorized_user.server_name().to_owned());
} }
+5 -2
View File
@@ -5,7 +5,10 @@ use database::{Deserialized, Map};
use governor::{DefaultKeyedRateLimiter, Quota, RateLimiter}; use governor::{DefaultKeyedRateLimiter, Quota, RateLimiter};
use lettre::{Address, message::Mailbox}; use lettre::{Address, message::Mailbox};
use nonzero_ext::nonzero; use nonzero_ext::nonzero;
use ruma::{ClientSecret, OwnedClientSecret, OwnedSessionId, SessionId, api::error::ErrorKind}; use ruma::{
ClientSecret, OwnedClientSecret, OwnedSessionId, SessionId,
api::error::{ErrorKind, LimitExceededErrorData},
};
mod session; mod session;
@@ -119,7 +122,7 @@ impl Service {
// Check ratelimiting for the target address. // Check ratelimiting for the target address.
if self.ratelimiter.check_key(&recipient.email).is_err() { if self.ratelimiter.check_key(&recipient.email).is_err() {
return Err(Error::BadRequest( return Err(Error::BadRequest(
ErrorKind::LimitExceeded { retry_after: None }, ErrorKind::LimitExceeded(LimitExceededErrorData::new()),
"You're sending emails too fast, try again in a few minutes.", "You're sending emails too fast, try again in a few minutes.",
)); ));
} }
+1 -1
View File
@@ -70,7 +70,7 @@ impl ValidationSessions {
#[must_use] #[must_use]
pub(super) fn generate_session_id() -> OwnedSessionId { pub(super) fn generate_session_id() -> OwnedSessionId {
OwnedSessionId::parse(utils::random_string(Self::RANDOM_SID_LENGTH)).unwrap() SessionId::parse(utils::random_string(Self::RANDOM_SID_LENGTH)).unwrap()
} }
pub(super) fn create_session( pub(super) fn create_session(
+6 -3
View File
@@ -13,7 +13,10 @@ use conduwuit::{Error, Result, SyncRwLock, debug_warn, warn};
use database::{Handle, Map}; use database::{Handle, Map};
use ruma::{ use ruma::{
DeviceId, OwnedServerName, OwnedTransactionId, TransactionId, UserId, DeviceId, OwnedServerName, OwnedTransactionId, TransactionId, UserId,
api::{error::ErrorKind::LimitExceeded, federation::transactions::send_transaction_message}, api::{
error::{ErrorKind::LimitExceeded, LimitExceededErrorData},
federation::transactions::send_transaction_message,
},
}; };
use tokio::sync::watch::{Receiver, Sender}; use tokio::sync::watch::{Receiver, Sender};
@@ -181,7 +184,7 @@ impl Service {
"Got concurrent transaction request from an origin with an active transaction" "Got concurrent transaction request from an origin with an active transaction"
); );
return Err(Error::BadRequest( return Err(Error::BadRequest(
LimitExceeded { retry_after: None }, LimitExceeded(LimitExceededErrorData::default()),
"Still processing another transaction from this origin", "Still processing another transaction from this origin",
)); ));
} }
@@ -201,7 +204,7 @@ impl Service {
"Server is overloaded, dropping incoming transaction" "Server is overloaded, dropping incoming transaction"
); );
return Err(Error::BadRequest( return Err(Error::BadRequest(
LimitExceeded { retry_after: None }, LimitExceeded(LimitExceededErrorData::default()),
"Server is overloaded, try again later", "Server is overloaded, try again later",
)); ));
} }
+48 -22
View File
@@ -10,8 +10,9 @@ use ruma::{
UserId, UserId,
api::{ api::{
client::uiaa::{ client::uiaa::{
AuthData, AuthFlow, AuthType, EmailIdentity, Password, ReCaptcha, RegistrationToken, AuthData, AuthFlow, AuthType, EmailIdentity, EmailUserIdentifier,
ThirdpartyIdCredentials, UiaaInfo, UserIdentifier, MatrixUserIdentifier MatrixUserIdentifier, Password, ReCaptcha, RegistrationToken,
ThirdpartyIdCredentials, UiaaInfo, UserIdentifier,
}, },
error::{ErrorKind, StandardErrorBody}, error::{ErrorKind, StandardErrorBody},
}, },
@@ -19,7 +20,7 @@ use ruma::{
use serde_json::value::RawValue; use serde_json::value::RawValue;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use crate::{Dep, config, globals, registration_tokens, rooms::user, threepid, users}; use crate::{Dep, config, globals, registration_tokens, threepid, users};
pub struct Service { pub struct Service {
services: Services, services: Services,
@@ -91,10 +92,7 @@ macro_rules! identity_update_fn {
} else if self.$field == Some($field) { } else if self.$field == Some($field) {
Ok(()) Ok(())
} else { } else {
Err(StandardErrorBody { Err(StandardErrorBody::new(ErrorKind::InvalidParam, $error.to_owned()))
kind: ErrorKind::InvalidParam,
message: $error.to_owned(),
})
} }
} }
}; };
@@ -330,19 +328,23 @@ impl Service {
Ok(AuthType::EmailIdentity) Ok(AuthType::EmailIdentity)
}, },
| Err(message) => Err(StandardErrorBody { | Err(message) => Err(StandardErrorBody::new(
kind: ErrorKind::ThreepidAuthFailed, ErrorKind::ThreepidAuthFailed,
message: message.into_owned(), message.into_owned(),
}), )),
} }
}, },
#[allow(clippy::useless_let_if_seq)] #[allow(clippy::useless_let_if_seq)]
| AuthData::Password(Password { identifier, password, .. }) => { | AuthData::Password(Password { identifier, password, .. }) => {
let user_id_or_localpart = match identifier { let user_id_or_localpart = match identifier {
| Some(UserIdentifier::Matrix(MatrixUserIdentifier{user})) => user.to_owned(), | UserIdentifier::Matrix(MatrixUserIdentifier { user, .. }) =>
| Some(UserIdentifier::Email(address)) => { user.to_owned(),
| UserIdentifier::Email(EmailUserIdentifier { address, .. }) => {
let Ok(email) = Address::try_from(address.to_owned()) else { let Ok(email) = Address::try_from(address.to_owned()) else {
return Err(StandardErrorBody::new(ErrorKind::InvalidParam, "Email is malformed".to_owned())); return Err(StandardErrorBody::new(
ErrorKind::InvalidParam,
"Email is malformed".to_owned(),
));
}; };
if let Some(localpart) = if let Some(localpart) =
@@ -352,18 +354,27 @@ impl Service {
localpart localpart
} else { } else {
return Err(StandardErrorBody::new(ErrorKind::Forbidden, "Invalid identifier or password".to_owned())); return Err(StandardErrorBody::new(
ErrorKind::Forbidden,
"Invalid identifier or password".to_owned(),
));
} }
}, },
| _ => | _ =>
return Err(StandardErrorBody::new(ErrorKind::Unrecognized, "Identifier type not recognized".to_owned())), return Err(StandardErrorBody::new(
ErrorKind::Unrecognized,
"Identifier type not recognized".to_owned(),
)),
}; };
let Ok(user_id) = UserId::parse_with_server_name( let Ok(user_id) = UserId::parse_with_server_name(
user_id_or_localpart, user_id_or_localpart,
self.services.globals.server_name(), self.services.globals.server_name(),
) else { ) else {
return Err(StandardErrorBody::new(ErrorKind::InvalidParam, "User ID is malformed".to_owned())); return Err(StandardErrorBody::new(
ErrorKind::InvalidParam,
"User ID is malformed".to_owned(),
));
}; };
// Check if password is correct // Check if password is correct
@@ -396,20 +407,29 @@ impl Service {
Ok(AuthType::Password) Ok(AuthType::Password)
} else { } else {
Err(StandardErrorBody::new(ErrorKind::Forbidden, "Invalid identifier or password".to_owned())) Err(StandardErrorBody::new(
ErrorKind::Forbidden,
"Invalid identifier or password".to_owned(),
))
} }
}, },
| AuthData::ReCaptcha(ReCaptcha { response, .. }) => { | AuthData::ReCaptcha(ReCaptcha { response, .. }) => {
let Some(ref private_site_key) = self.services.config.recaptcha_private_site_key let Some(ref private_site_key) = self.services.config.recaptcha_private_site_key
else { else {
return Err(StandardErrorBody::new(ErrorKind::Forbidden, "ReCaptcha is not configured".to_owned())); return Err(StandardErrorBody::new(
ErrorKind::Forbidden,
"ReCaptcha is not configured".to_owned(),
));
}; };
match recaptcha_verify::verify_v3(private_site_key, response, None).await { match recaptcha_verify::verify_v3(private_site_key, response, None).await {
| Ok(()) => Ok(AuthType::ReCaptcha), | Ok(()) => Ok(AuthType::ReCaptcha),
| Err(e) => { | Err(e) => {
error!("ReCaptcha verification failed: {e:?}"); error!("ReCaptcha verification failed: {e:?}");
Err(StandardErrorBody::new(ErrorKind::Forbidden, "ReCaptcha verification failed".to_owned())) Err(StandardErrorBody::new(
ErrorKind::Forbidden,
"ReCaptcha verification failed".to_owned(),
))
}, },
} }
}, },
@@ -428,11 +448,17 @@ impl Service {
Ok(AuthType::RegistrationToken) Ok(AuthType::RegistrationToken)
} else { } else {
Err(StandardErrorBody::new(ErrorKind::Forbidden, "Invalid registration token".to_owned())) Err(StandardErrorBody::new(
ErrorKind::Forbidden,
"Invalid registration token".to_owned(),
))
} }
}, },
| AuthData::Terms(_) => Ok(AuthType::Terms), | AuthData::Terms(_) => Ok(AuthType::Terms),
| _ => Err(StandardErrorBody::new(ErrorKind::Unrecognized, "Unsupported stage type".into())), | _ => Err(StandardErrorBody::new(
ErrorKind::Unrecognized,
"Unsupported stage type".into(),
)),
} }
.map(|auth_type| (auth_type, identity)) .map(|auth_type| (auth_type, identity))
} }