refactor some additional errors

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-08-01 10:58:27 +00:00
parent f51d4237c7
commit 2e3e14b045
13 changed files with 127 additions and 148 deletions

View file

@ -1,10 +1,9 @@
use std::{io::Cursor, time::SystemTime};
use conduit::{debug, utils, warn, Error, Result};
use conduit::{debug, utils, warn, Err, Result};
use conduit_core::implement;
use image::ImageReader as ImgReader;
use ipaddress::IPAddress;
use ruma::api::client::error::ErrorKind;
use serde::Serialize;
use url::Url;
use webpage::HTML;
@ -89,7 +88,7 @@ pub async fn get_url_preview(&self, url: &str) -> Result<UrlPreviewData> {
async fn request_url_preview(&self, url: &str) -> Result<UrlPreviewData> {
if let Ok(ip) = IPAddress::parse(url) {
if !self.services.globals.valid_cidr_range(&ip) {
return Err(Error::BadServerResponse("Requesting from this address is forbidden"));
return Err!(BadServerResponse("Requesting from this address is forbidden"));
}
}
@ -99,7 +98,7 @@ async fn request_url_preview(&self, url: &str) -> Result<UrlPreviewData> {
if let Some(remote_addr) = response.remote_addr() {
if let Ok(ip) = IPAddress::parse(remote_addr.ip().to_string()) {
if !self.services.globals.valid_cidr_range(&ip) {
return Err(Error::BadServerResponse("Requesting from this address is forbidden"));
return Err!(BadServerResponse("Requesting from this address is forbidden"));
}
}
}
@ -109,12 +108,12 @@ async fn request_url_preview(&self, url: &str) -> Result<UrlPreviewData> {
.get(reqwest::header::CONTENT_TYPE)
.and_then(|x| x.to_str().ok())
else {
return Err(Error::BadRequest(ErrorKind::Unknown, "Unknown Content-Type"));
return Err!(Request(Unknown("Unknown Content-Type")));
};
let data = match content_type {
html if html.starts_with("text/html") => self.download_html(url).await?,
img if img.starts_with("image/") => self.download_image(url).await?,
_ => return Err(Error::BadRequest(ErrorKind::Unknown, "Unsupported Content-Type")),
_ => return Err!(Request(Unknown("Unsupported Content-Type"))),
};
self.set_url_preview(url, &data).await?;
@ -142,7 +141,7 @@ async fn download_html(&self, url: &str) -> Result<UrlPreviewData> {
}
let body = String::from_utf8_lossy(&bytes);
let Ok(html) = HTML::from_string(body.to_string(), Some(url.to_owned())) else {
return Err(Error::BadRequest(ErrorKind::Unknown, "Failed to parse HTML"));
return Err!(Request(Unknown("Failed to parse HTML")));
};
let mut data = match html.opengraph.images.first() {

View file

@ -3,7 +3,7 @@ mod data;
use std::{fmt::Debug, mem, sync::Arc};
use bytes::BytesMut;
use conduit::{debug_info, info, trace, utils::string_from_bytes, warn, Error, PduEvent, Result};
use conduit::{debug_error, err, trace, utils::string_from_bytes, warn, Err, PduEvent, Result};
use ipaddress::IPAddress;
use ruma::{
api::{
@ -84,8 +84,9 @@ impl Service {
let http_request = request
.try_into_http_request::<BytesMut>(&dest, SendAccessToken::IfRequired(""), &VERSIONS)
.map_err(|e| {
warn!("Failed to find destination {dest} for push gateway: {e}");
Error::BadServerResponse("Invalid push gateway destination")
err!(BadServerResponse(warn!(
"Failed to find destination {dest} for push gateway: {e}"
)))
})?
.map(BytesMut::freeze);
@ -95,7 +96,7 @@ impl Service {
trace!("Checking request URL for IP");
if let Ok(ip) = IPAddress::parse(url_host) {
if !self.services.globals.valid_cidr_range(&ip) {
return Err(Error::BadServerResponse("Not allowed to send requests to this IP"));
return Err!(BadServerResponse("Not allowed to send requests to this IP"));
}
}
}
@ -110,7 +111,7 @@ impl Service {
if let Some(remote_addr) = response.remote_addr() {
if let Ok(ip) = IPAddress::parse(remote_addr.ip().to_string()) {
if !self.services.globals.valid_cidr_range(&ip) {
return Err(Error::BadServerResponse("Not allowed to send requests to this IP"));
return Err!(BadServerResponse("Not allowed to send requests to this IP"));
}
}
}
@ -129,10 +130,10 @@ impl Service {
let body = response.bytes().await?; // TODO: handle timeout
if !status.is_success() {
info!("Push gateway {dest} returned unsuccessful HTTP response ({status})");
debug_info!("Push gateway response body: {:?}", string_from_bytes(&body));
return Err(Error::BadServerResponse("Push gateway returned unsuccessful response"));
debug_error!("Push gateway response body: {:?}", string_from_bytes(&body));
return Err!(BadServerResponse(error!(
"Push gateway {dest} returned unsuccessful HTTP response: {status}"
)));
}
let response = T::IncomingResponse::try_from_http_response(
@ -140,13 +141,11 @@ impl Service {
.body(body)
.expect("reqwest body is valid http body"),
);
response.map_err(|e| {
warn!("Push gateway {dest} returned invalid response bytes: {e}");
Error::BadServerResponse("Push gateway returned bad/invalid response")
})
response
.map_err(|e| err!(BadServerResponse(error!("Push gateway {dest} returned invalid response: {e}"))))
},
Err(e) => {
warn!("Could not send request to pusher {dest}: {e}");
debug_error!("Could not send request to pusher {dest}: {e}");
Err(e.into())
},
}
@ -165,7 +164,7 @@ impl Service {
.room_state_get(&pdu.room_id, &StateEventType::RoomPowerLevels, "")?
.map(|ev| {
serde_json::from_str(ev.content.get())
.map_err(|_| Error::bad_database("invalid m.room.power_levels event"))
.map_err(|e| err!(Database("invalid m.room.power_levels event: {e:?}")))
})
.transpose()?
.unwrap_or_default();
@ -181,8 +180,8 @@ impl Service {
};
if notify.is_some() {
return Err(Error::bad_database(
r#"Malformed pushrule contains more than one of these actions: ["dont_notify", "notify", "coalesce"]"#,
return Err!(Database(
r#"Malformed pushrule contains more than one of these actions: ["dont_notify", "notify", "coalesce"]"#
));
}

View file

@ -4,7 +4,7 @@ use std::{
sync::Arc,
};
use conduit::{debug, debug_error, debug_info, debug_warn, trace, Err, Error, Result};
use conduit::{debug, debug_error, debug_info, debug_warn, err, trace, Err, Result};
use hickory_resolver::{error::ResolveError, lookup::SrvLookup};
use ipaddress::IPAddress;
use ruma::ServerName;
@ -329,10 +329,8 @@ impl super::Service {
dest.is_ip_literal() || !IPAddress::is_valid(dest.host()),
"Destination is not an IP literal."
);
let ip = IPAddress::parse(dest.host()).map_err(|e| {
debug_error!("Failed to parse IP literal from string: {}", e);
Error::BadServerResponse("Invalid IP address")
})?;
let ip = IPAddress::parse(dest.host())
.map_err(|e| err!(BadServerResponse(debug_error!("Failed to parse IP literal from string: {e}"))))?;
self.validate_ip(&ip)?;
@ -341,7 +339,7 @@ impl super::Service {
pub(crate) fn validate_ip(&self, ip: &IPAddress) -> Result<()> {
if !self.services.globals.valid_cidr_range(ip) {
return Err(Error::BadServerResponse("Not allowed to send requests to this IP"));
return Err!(BadServerResponse("Not allowed to send requests to this IP"));
}
Ok(())

View file

@ -1,18 +1,18 @@
use conduit::{pdu::gen_event_id_canonical_json, warn, Err, Error, Result};
use ruma::{api::client::error::ErrorKind, CanonicalJsonObject, OwnedEventId, OwnedRoomId, RoomId};
use conduit::{debug_warn, err, pdu::gen_event_id_canonical_json, Err, Result};
use ruma::{CanonicalJsonObject, OwnedEventId, OwnedRoomId, RoomId};
use serde_json::value::RawValue as RawJsonValue;
impl super::Service {
pub fn parse_incoming_pdu(&self, pdu: &RawJsonValue) -> Result<(OwnedEventId, CanonicalJsonObject, OwnedRoomId)> {
let value: CanonicalJsonObject = serde_json::from_str(pdu.get()).map_err(|e| {
warn!("Error parsing incoming event {pdu:?}: {e:?}");
Error::BadServerResponse("Invalid PDU in server response")
debug_warn!("Error parsing incoming event {pdu:#?}");
err!(BadServerResponse("Error parsing incoming event {e:?}"))
})?;
let room_id: OwnedRoomId = value
.get("room_id")
.and_then(|id| RoomId::parse(id.as_str()?).ok())
.ok_or(Error::BadRequest(ErrorKind::InvalidParam, "Invalid room id in pdu"))?;
.ok_or(err!(Request(InvalidParam("Invalid room id in pdu"))))?;
let Ok(room_version_id) = self.services.state.get_room_version(&room_id) else {
return Err!("Server is not in room {room_id}");

View file

@ -1,7 +1,7 @@
use std::{fmt::Debug, mem};
use bytes::BytesMut;
use conduit::{debug_error, trace, utils, warn, Error, Result};
use conduit::{debug_error, err, trace, utils, warn, Err, Result};
use reqwest::Client;
use ruma::api::{appservice::Registration, IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken};
@ -26,10 +26,7 @@ where
let hs_token = registration.hs_token.as_str();
let mut http_request = request
.try_into_http_request::<BytesMut>(&dest, SendAccessToken::IfRequired(hs_token), &VERSIONS)
.map_err(|e| {
warn!("Failed to find destination {dest}: {e}");
Error::BadServerResponse("Invalid appservice destination")
})?
.map_err(|e| err!(BadServerResponse(warn!("Failed to find destination {dest}: {e}"))))?
.map(BytesMut::freeze);
let mut parts = http_request.uri().clone().into_parts();
@ -69,13 +66,11 @@ where
let body = response.bytes().await?; // TODO: handle timeout
if !status.is_success() {
warn!(
debug_error!("Appservice response bytes: {:?}", utils::string_from_bytes(&body));
return Err!(BadServerResponse(error!(
"Appservice \"{}\" returned unsuccessful HTTP response {status} at {dest}",
registration.id
);
debug_error!("Appservice response bytes: {:?}", utils::string_from_bytes(&body));
return Err(Error::BadServerResponse("Appservice returned unsuccessful HTTP response"));
)));
}
let response = T::IncomingResponse::try_from_http_response(
@ -85,7 +80,9 @@ where
);
response.map(Some).map_err(|e| {
warn!("Appservice \"{}\" returned invalid response bytes {dest}: {e}", registration.id);
Error::BadServerResponse("Appservice returned bad/invalid response")
err!(BadServerResponse(error!(
"Appservice \"{}\" returned invalid response bytes {dest}: {e}",
registration.id
)))
})
}

View file

@ -1,7 +1,7 @@
use std::{fmt::Debug, mem};
use conduit::{
debug, debug_error, debug_warn, error::inspect_debug_log, trace, utils::string::EMPTY, Err, Error, Result,
debug, debug_error, debug_warn, err, error::inspect_debug_log, trace, utils::string::EMPTY, Err, Error, Result,
};
use http::{header::AUTHORIZATION, HeaderValue};
use ipaddress::IPAddress;
@ -62,7 +62,7 @@ impl super::Service {
trace!("Preparing request");
let mut http_request = req
.try_into_http_request::<Vec<u8>>(&actual.string, SATIR, &VERSIONS)
.map_err(|_| Error::BadServerResponse("Invalid destination"))?;
.map_err(|e| err!(BadServerResponse("Invalid destination: {e:?}")))?;
sign_request::<T>(&self.services.globals, dest, &mut http_request);
@ -139,10 +139,7 @@ where
);
}
match response {
Err(_) => Err(Error::BadServerResponse("Server returned bad 200 response.")),
Ok(response) => Ok(response),
}
response.map_err(|e| err!(BadServerResponse("Server returned bad 200 response: {e:?}")))
}
fn handle_error<T>(

View file

@ -4,7 +4,7 @@ use std::{
time::{Duration, SystemTime},
};
use conduit::{debug, error, info, trace, warn, Error, Result};
use conduit::{debug, debug_error, debug_warn, err, error, info, trace, warn, Err, Result};
use futures_util::{stream::FuturesUnordered, StreamExt};
use ruma::{
api::federation::{
@ -57,13 +57,13 @@ impl Service {
for event in events {
for (signature_server, signature) in event
.get("signatures")
.ok_or(Error::BadServerResponse("No signatures in server response pdu."))?
.ok_or(err!(BadServerResponse("No signatures in server response pdu.")))?
.as_object()
.ok_or(Error::BadServerResponse("Invalid signatures object in server response pdu."))?
.ok_or(err!(BadServerResponse("Invalid signatures object in server response pdu.")))?
{
let signature_object = signature.as_object().ok_or(Error::BadServerResponse(
let signature_object = signature.as_object().ok_or(err!(BadServerResponse(
"Invalid signatures content object in server response pdu.",
))?;
)))?;
for signature_id in signature_object.keys() {
server_key_ids
@ -94,10 +94,12 @@ impl Service {
.map(|(signature_server, signature_ids)| async {
let fetch_res = self
.fetch_signing_keys_for_server(
signature_server.as_str().try_into().map_err(|_| {
signature_server.as_str().try_into().map_err(|e| {
(
signature_server.clone(),
Error::BadServerResponse("Invalid servername in signatures of server response pdu."),
err!(BadServerResponse(
"Invalid servername in signatures of server response pdu: {e:?}"
)),
)
})?,
signature_ids.into_iter().collect(), // HashSet to Vec
@ -107,7 +109,9 @@ impl Service {
match fetch_res {
Ok(keys) => Ok((signature_server, keys)),
Err(e) => {
warn!("Signature verification failed: Could not fetch signing key for {signature_server}: {e}",);
debug_error!(
"Signature verification failed: Could not fetch signing key for {signature_server}: {e}",
);
Err((signature_server, e))
},
}
@ -123,7 +127,7 @@ impl Service {
.insert(signature_server.clone(), keys);
},
Err((signature_server, e)) => {
warn!("Failed to fetch keys for {}: {:?}", signature_server, e);
debug_warn!("Failed to fetch keys for {signature_server}: {e:?}");
},
}
}
@ -141,35 +145,37 @@ impl Service {
pub_key_map: &mut RwLockWriteGuard<'_, BTreeMap<String, BTreeMap<String, Base64>>>,
) -> Result<()> {
let value: CanonicalJsonObject = serde_json::from_str(pdu.get()).map_err(|e| {
error!("Invalid PDU in server response: {:?}: {:?}", pdu, e);
Error::BadServerResponse("Invalid PDU in server response")
debug_error!("Invalid PDU in server response: {pdu:#?}");
err!(BadServerResponse(error!("Invalid PDU in server response: {e:?}")))
})?;
let signatures = value
.get("signatures")
.ok_or(Error::BadServerResponse("No signatures in server response pdu."))?
.ok_or(err!(BadServerResponse("No signatures in server response pdu.")))?
.as_object()
.ok_or(Error::BadServerResponse("Invalid signatures object in server response pdu."))?;
.ok_or(err!(BadServerResponse("Invalid signatures object in server response pdu.")))?;
for (signature_server, signature) in signatures {
let signature_object = signature.as_object().ok_or(Error::BadServerResponse(
let signature_object = signature.as_object().ok_or(err!(BadServerResponse(
"Invalid signatures content object in server response pdu.",
))?;
)))?;
let signature_ids = signature_object.keys().cloned().collect::<Vec<_>>();
let contains_all_ids =
|keys: &BTreeMap<String, Base64>| signature_ids.iter().all(|id| keys.contains_key(id));
let origin = <&ServerName>::try_from(signature_server.as_str())
.map_err(|_| Error::BadServerResponse("Invalid servername in signatures of server response pdu."))?;
let origin = <&ServerName>::try_from(signature_server.as_str()).map_err(|e| {
err!(BadServerResponse(
"Invalid servername in signatures of server response pdu: {e:?}"
))
})?;
if servers.contains_key(origin) || pub_key_map.contains_key(origin.as_str()) {
continue;
}
debug!("Loading signing keys for {}", origin);
debug!("Loading signing keys for {origin}");
let result: BTreeMap<_, _> = self
.services
.globals
@ -179,7 +185,7 @@ impl Service {
.collect();
if !contains_all_ids(&result) {
debug!("Signing key not loaded for {}", origin);
debug_warn!("Signing key not loaded for {origin}");
servers.insert(origin.to_owned(), BTreeMap::new());
}
@ -196,7 +202,7 @@ impl Service {
pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, Base64>>>,
) -> Result<()> {
for server in self.services.globals.trusted_servers() {
debug!("Asking batch signing keys from trusted server {}", server);
debug!("Asking batch signing keys from trusted server {server}");
match self
.services
.sending
@ -209,14 +215,16 @@ impl Service {
.await
{
Ok(keys) => {
debug!("Got signing keys: {:?}", keys);
debug!("Got signing keys: {keys:?}");
let mut pkm = pub_key_map.write().await;
for k in keys.server_keys {
let k = match k.deserialize() {
Ok(key) => key,
Err(e) => {
warn!("Received error {e} while fetching keys from trusted server {server}");
warn!("{}", k.into_json());
warn!(
"Received error {e} while fetching keys from trusted server {server}: {:#?}",
k.into_json()
);
continue;
},
};
@ -236,13 +244,10 @@ impl Service {
pkm.insert(k.server_name.to_string(), result);
}
},
Err(e) => {
warn!(
"Failed sending batched key request to trusted key server {server} for the remote servers \
{:?}: {e}",
servers
);
},
Err(e) => error!(
"Failed sending batched key request to trusted key server {server} for the remote servers \
{servers:?}: {e}"
),
}
}
@ -478,7 +483,6 @@ impl Service {
}
} else {
info!("query_trusted_key_servers_first is set to false, querying {origin} first");
debug!("Asking {origin} for their signing keys over federation");
if let Some(server_key) = self
.services
@ -536,7 +540,7 @@ impl Service {
.filter_map(|e| e.deserialize().ok())
.collect::<Vec<_>>()
}) {
debug!("Got signing keys: {:?}", server_keys);
debug!("Got signing keys: {server_keys:?}");
for k in server_keys {
self.services
.globals
@ -561,7 +565,6 @@ impl Service {
}
}
warn!("Failed to find public key for server: {origin}");
Err(Error::BadServerResponse("Failed to find public key for server"))
Err!(BadServerResponse(warn!("Failed to find public key for server {origin:?}")))
}
}