mirror of
https://github.com/girlbossceo/conduwuit.git
synced 2025-12-11 09:48:49 -05:00
Compare commits
5 commits
3cc92b32ec
...
99868b1661
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99868b1661 | ||
|
|
d5ad973464 | ||
|
|
ff276a42a3 | ||
|
|
5f8c68ab84 | ||
|
|
6578b83bce |
17 changed files with 162 additions and 157 deletions
|
|
@ -594,7 +594,7 @@
|
||||||
# Currently, conduwuit doesn't support inbound batched key requests, so
|
# Currently, conduwuit doesn't support inbound batched key requests, so
|
||||||
# this list should only contain other Synapse servers.
|
# this list should only contain other Synapse servers.
|
||||||
#
|
#
|
||||||
# example: ["matrix.org", "envs.net", "tchncs.de"]
|
# example: ["matrix.org", "tchncs.de"]
|
||||||
#
|
#
|
||||||
#trusted_servers = ["matrix.org"]
|
#trusted_servers = ["matrix.org"]
|
||||||
|
|
||||||
|
|
@ -1186,13 +1186,16 @@
|
||||||
#
|
#
|
||||||
#prune_missing_media = false
|
#prune_missing_media = false
|
||||||
|
|
||||||
# Vector list of servers that conduwuit will refuse to download remote
|
# Vector list of regex patterns of server names that conduwuit will refuse
|
||||||
# media from.
|
# to download remote media from.
|
||||||
|
#
|
||||||
|
# example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"]
|
||||||
#
|
#
|
||||||
#prevent_media_downloads_from = []
|
#prevent_media_downloads_from = []
|
||||||
|
|
||||||
# List of forbidden server names that we will block incoming AND outgoing
|
# List of forbidden server names via regex patterns that we will block
|
||||||
# federation with, and block client room joins / remote user invites.
|
# incoming AND outgoing federation with, and block client room joins /
|
||||||
|
# remote user invites.
|
||||||
#
|
#
|
||||||
# This check is applied on the room ID, room alias, sender server name,
|
# This check is applied on the room ID, room alias, sender server name,
|
||||||
# sender user's server name, inbound federation X-Matrix origin, and
|
# sender user's server name, inbound federation X-Matrix origin, and
|
||||||
|
|
@ -1200,11 +1203,15 @@
|
||||||
#
|
#
|
||||||
# Basically "global" ACLs.
|
# Basically "global" ACLs.
|
||||||
#
|
#
|
||||||
|
# example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"]
|
||||||
|
#
|
||||||
#forbidden_remote_server_names = []
|
#forbidden_remote_server_names = []
|
||||||
|
|
||||||
# List of forbidden server names that we will block all outgoing federated
|
# List of forbidden server names via regex patterns that we will block all
|
||||||
# room directory requests for. Useful for preventing our users from
|
# outgoing federated room directory requests for. Useful for preventing
|
||||||
# wandering into bad servers or spaces.
|
# our users from wandering into bad servers or spaces.
|
||||||
|
#
|
||||||
|
# example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"]
|
||||||
#
|
#
|
||||||
#forbidden_remote_room_directory_server_names = []
|
#forbidden_remote_room_directory_server_names = []
|
||||||
|
|
||||||
|
|
@ -1315,7 +1322,7 @@
|
||||||
# used, and startup as warnings if any room aliases in your database have
|
# used, and startup as warnings if any room aliases in your database have
|
||||||
# a forbidden room alias/ID.
|
# a forbidden room alias/ID.
|
||||||
#
|
#
|
||||||
# example: ["19dollarfortnitecards", "b[4a]droom"]
|
# example: ["19dollarfortnitecards", "b[4a]droom", "badphrase"]
|
||||||
#
|
#
|
||||||
#forbidden_alias_names = []
|
#forbidden_alias_names = []
|
||||||
|
|
||||||
|
|
@ -1328,7 +1335,7 @@
|
||||||
# startup as warnings if any local users in your database have a forbidden
|
# startup as warnings if any local users in your database have a forbidden
|
||||||
# username.
|
# username.
|
||||||
#
|
#
|
||||||
# example: ["administrator", "b[a4]dusernam[3e]"]
|
# example: ["administrator", "b[a4]dusernam[3e]", "badphrase"]
|
||||||
#
|
#
|
||||||
#forbidden_usernames = []
|
#forbidden_usernames = []
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,13 @@ pub(crate) async fn get_public_rooms_filtered_route(
|
||||||
) -> Result<get_public_rooms_filtered::v3::Response> {
|
) -> Result<get_public_rooms_filtered::v3::Response> {
|
||||||
if let Some(server) = &body.server {
|
if let Some(server) = &body.server {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_room_directory_server_names
|
.forbidden_remote_room_directory_server_names
|
||||||
.contains(server)
|
.is_match(server.host())
|
||||||
|
|| services
|
||||||
|
.config
|
||||||
|
.forbidden_remote_server_names
|
||||||
|
.is_match(server.host())
|
||||||
{
|
{
|
||||||
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
|
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
|
||||||
}
|
}
|
||||||
|
|
@ -90,10 +93,13 @@ pub(crate) async fn get_public_rooms_route(
|
||||||
) -> Result<get_public_rooms::v3::Response> {
|
) -> Result<get_public_rooms::v3::Response> {
|
||||||
if let Some(server) = &body.server {
|
if let Some(server) = &body.server {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_room_directory_server_names
|
.forbidden_remote_room_directory_server_names
|
||||||
.contains(server)
|
.is_match(server.host())
|
||||||
|
|| services
|
||||||
|
.config
|
||||||
|
.forbidden_remote_server_names
|
||||||
|
.is_match(server.host())
|
||||||
{
|
{
|
||||||
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
|
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||||
|
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{Err, Error, Result, debug, debug_warn, err, info, result::NotFound, utils};
|
use conduwuit::{Err, Error, Result, debug, debug_warn, err, result::NotFound, utils};
|
||||||
use conduwuit_service::{Services, users::parse_master_key};
|
use conduwuit_service::{Services, users::parse_master_key};
|
||||||
use futures::{StreamExt, stream::FuturesUnordered};
|
use futures::{StreamExt, stream::FuturesUnordered};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
|
|
@ -177,7 +177,7 @@ pub(crate) async fn upload_signing_keys_route(
|
||||||
body.master_key.as_ref(),
|
body.master_key.as_ref(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.inspect_err(|e| info!(?e))
|
.inspect_err(|e| debug!(?e))
|
||||||
{
|
{
|
||||||
| Ok(exists) => {
|
| Ok(exists) => {
|
||||||
if let Some(result) = exists {
|
if let Some(result) = exists {
|
||||||
|
|
|
||||||
|
|
@ -79,10 +79,9 @@ async fn banned_room_check(
|
||||||
if let Some(room_id) = room_id {
|
if let Some(room_id) = room_id {
|
||||||
if services.rooms.metadata.is_banned(room_id).await
|
if services.rooms.metadata.is_banned(room_id).await
|
||||||
|| services
|
|| services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(&room_id.server_name().unwrap().to_owned())
|
.is_match(room_id.server_name().unwrap().host())
|
||||||
{
|
{
|
||||||
warn!(
|
warn!(
|
||||||
"User {user_id} who is not an admin attempted to send an invite for or \
|
"User {user_id} who is not an admin attempted to send an invite for or \
|
||||||
|
|
@ -120,10 +119,9 @@ async fn banned_room_check(
|
||||||
}
|
}
|
||||||
} else if let Some(server_name) = server_name {
|
} else if let Some(server_name) = server_name {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(&server_name.to_owned())
|
.is_match(server_name.host())
|
||||||
{
|
{
|
||||||
warn!(
|
warn!(
|
||||||
"User {user_id} who is not an admin tried joining a room which has the server \
|
"User {user_id} who is not an admin tried joining a room which has the server \
|
||||||
|
|
|
||||||
|
|
@ -261,10 +261,9 @@ pub(crate) async fn is_ignored_pdu(
|
||||||
let ignored_type = IGNORED_MESSAGE_TYPES.binary_search(&pdu.kind).is_ok();
|
let ignored_type = IGNORED_MESSAGE_TYPES.binary_search(&pdu.kind).is_ok();
|
||||||
|
|
||||||
let ignored_server = services
|
let ignored_server = services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(pdu.sender().server_name());
|
.is_match(pdu.sender().server_name().host());
|
||||||
|
|
||||||
if ignored_type
|
if ignored_type
|
||||||
&& (ignored_server || services.users.user_is_ignored(&pdu.sender, user_id).await)
|
&& (ignored_server || services.users.user_is_ignored(&pdu.sender, user_id).await)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use axum_client_ip::InsecureClientIp;
|
use axum_client_ip::InsecureClientIp;
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Result, debug_warn,
|
Err, Result, debug_warn, trace,
|
||||||
utils::{IterStream, future::TryExtExt},
|
utils::{IterStream, future::TryExtExt},
|
||||||
};
|
};
|
||||||
use futures::{
|
use futures::{
|
||||||
|
|
@ -74,7 +74,12 @@ async fn room_summary_response(
|
||||||
servers: &[OwnedServerName],
|
servers: &[OwnedServerName],
|
||||||
sender_user: Option<&UserId>,
|
sender_user: Option<&UserId>,
|
||||||
) -> Result<get_summary::msc3266::Response> {
|
) -> Result<get_summary::msc3266::Response> {
|
||||||
if services.rooms.metadata.exists(room_id).await {
|
if services
|
||||||
|
.rooms
|
||||||
|
.state_cache
|
||||||
|
.server_in_room(services.globals.server_name(), room_id)
|
||||||
|
.await
|
||||||
|
{
|
||||||
return local_room_summary_response(services, room_id, sender_user)
|
return local_room_summary_response(services, room_id, sender_user)
|
||||||
.boxed()
|
.boxed()
|
||||||
.await;
|
.await;
|
||||||
|
|
@ -106,14 +111,14 @@ async fn local_room_summary_response(
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
sender_user: Option<&UserId>,
|
sender_user: Option<&UserId>,
|
||||||
) -> Result<get_summary::msc3266::Response> {
|
) -> Result<get_summary::msc3266::Response> {
|
||||||
|
trace!(?sender_user, "Sending local room summary response for {room_id:?}");
|
||||||
let join_rule = services.rooms.state_accessor.get_join_rules(room_id);
|
let join_rule = services.rooms.state_accessor.get_join_rules(room_id);
|
||||||
|
|
||||||
let world_readable = services.rooms.state_accessor.is_world_readable(room_id);
|
let world_readable = services.rooms.state_accessor.is_world_readable(room_id);
|
||||||
|
|
||||||
let guest_can_join = services.rooms.state_accessor.guest_can_join(room_id);
|
let guest_can_join = services.rooms.state_accessor.guest_can_join(room_id);
|
||||||
|
|
||||||
let (join_rule, world_readable, guest_can_join) =
|
let (join_rule, world_readable, guest_can_join) =
|
||||||
join3(join_rule, world_readable, guest_can_join).await;
|
join3(join_rule, world_readable, guest_can_join).await;
|
||||||
|
trace!("{join_rule:?}, {world_readable:?}, {guest_can_join:?}");
|
||||||
|
|
||||||
user_can_see_summary(
|
user_can_see_summary(
|
||||||
services,
|
services,
|
||||||
|
|
@ -215,6 +220,7 @@ async fn remote_room_summary_hierarchy_response(
|
||||||
servers: &[OwnedServerName],
|
servers: &[OwnedServerName],
|
||||||
sender_user: Option<&UserId>,
|
sender_user: Option<&UserId>,
|
||||||
) -> Result<SpaceHierarchyParentSummary> {
|
) -> Result<SpaceHierarchyParentSummary> {
|
||||||
|
trace!(?sender_user, ?servers, "Sending remote room summary response for {room_id:?}");
|
||||||
if !services.config.allow_federation {
|
if !services.config.allow_federation {
|
||||||
return Err!(Request(Forbidden("Federation is disabled.")));
|
return Err!(Request(Forbidden("Federation is disabled.")));
|
||||||
}
|
}
|
||||||
|
|
@ -237,6 +243,7 @@ async fn remote_room_summary_hierarchy_response(
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
while let Some(Ok(response)) = requests.next().await {
|
while let Some(Ok(response)) = requests.next().await {
|
||||||
|
trace!("{response:?}");
|
||||||
let room = response.room.clone();
|
let room = response.room.clone();
|
||||||
if room.room_id != room_id {
|
if room.room_id != room_id {
|
||||||
debug_warn!(
|
debug_warn!(
|
||||||
|
|
@ -278,6 +285,7 @@ async fn user_can_see_summary<'a, I>(
|
||||||
where
|
where
|
||||||
I: Iterator<Item = &'a RoomId> + Send,
|
I: Iterator<Item = &'a RoomId> + Send,
|
||||||
{
|
{
|
||||||
|
let is_public_room = matches!(join_rule, Public | Knock | KnockRestricted);
|
||||||
match sender_user {
|
match sender_user {
|
||||||
| Some(sender_user) => {
|
| Some(sender_user) => {
|
||||||
let user_can_see_state_events = services
|
let user_can_see_state_events = services
|
||||||
|
|
@ -296,7 +304,7 @@ where
|
||||||
|
|
||||||
if user_can_see_state_events
|
if user_can_see_state_events
|
||||||
|| (is_guest && guest_can_join)
|
|| (is_guest && guest_can_join)
|
||||||
|| matches!(&join_rule, &Public | &Knock | &KnockRestricted)
|
|| is_public_room
|
||||||
|| user_in_allowed_restricted_room
|
|| user_in_allowed_restricted_room
|
||||||
{
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -309,7 +317,7 @@ where
|
||||||
)))
|
)))
|
||||||
},
|
},
|
||||||
| None => {
|
| None => {
|
||||||
if matches!(join_rule, Public | Knock | KnockRestricted) || world_readable {
|
if is_public_room || world_readable {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,20 @@
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{Result, utils::TryFutureExtExt};
|
use conduwuit::{
|
||||||
use futures::{StreamExt, pin_mut};
|
Result,
|
||||||
|
utils::{future::BoolExt, stream::BroadbandExt},
|
||||||
|
};
|
||||||
|
use futures::{FutureExt, StreamExt, pin_mut};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
api::client::user_directory::search_users,
|
api::client::user_directory::search_users::{self},
|
||||||
events::{
|
events::room::join_rules::JoinRule,
|
||||||
StateEventType,
|
|
||||||
room::join_rules::{JoinRule, RoomJoinRulesEventContent},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Ruma;
|
use crate::Ruma;
|
||||||
|
|
||||||
|
// conduwuit can handle a lot more results than synapse
|
||||||
|
const LIMIT_MAX: usize = 500;
|
||||||
|
const LIMIT_DEFAULT: usize = 10;
|
||||||
|
|
||||||
/// # `POST /_matrix/client/r0/user_directory/search`
|
/// # `POST /_matrix/client/r0/user_directory/search`
|
||||||
///
|
///
|
||||||
/// Searches all known users for a match.
|
/// Searches all known users for a match.
|
||||||
|
|
@ -21,78 +25,63 @@ pub(crate) async fn search_users_route(
|
||||||
State(services): State<crate::State>,
|
State(services): State<crate::State>,
|
||||||
body: Ruma<search_users::v3::Request>,
|
body: Ruma<search_users::v3::Request>,
|
||||||
) -> Result<search_users::v3::Response> {
|
) -> Result<search_users::v3::Response> {
|
||||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
let sender_user = body.sender_user();
|
||||||
let limit = usize::try_from(body.limit).map_or(10, usize::from).min(100); // default limit is 10
|
let limit = usize::try_from(body.limit)
|
||||||
|
.map_or(LIMIT_DEFAULT, usize::from)
|
||||||
|
.min(LIMIT_MAX);
|
||||||
|
|
||||||
let users = services.users.stream().filter_map(|user_id| async {
|
let mut users = services
|
||||||
// Filter out buggy users (they should not exist, but you never know...)
|
.users
|
||||||
let user = search_users::v3::User {
|
.stream()
|
||||||
user_id: user_id.to_owned(),
|
.map(ToOwned::to_owned)
|
||||||
display_name: services.users.displayname(user_id).await.ok(),
|
.broad_filter_map(async |user_id| {
|
||||||
avatar_url: services.users.avatar_url(user_id).await.ok(),
|
let user = search_users::v3::User {
|
||||||
};
|
user_id: user_id.clone(),
|
||||||
|
display_name: services.users.displayname(&user_id).await.ok(),
|
||||||
|
avatar_url: services.users.avatar_url(&user_id).await.ok(),
|
||||||
|
};
|
||||||
|
|
||||||
let user_id_matches = user
|
let user_id_matches = user
|
||||||
.user_id
|
.user_id
|
||||||
.to_string()
|
.as_str()
|
||||||
.to_lowercase()
|
.to_lowercase()
|
||||||
.contains(&body.search_term.to_lowercase());
|
.contains(&body.search_term.to_lowercase());
|
||||||
|
|
||||||
let user_displayname_matches = user
|
let user_displayname_matches = user.display_name.as_ref().is_some_and(|name| {
|
||||||
.display_name
|
|
||||||
.as_ref()
|
|
||||||
.filter(|name| {
|
|
||||||
name.to_lowercase()
|
name.to_lowercase()
|
||||||
.contains(&body.search_term.to_lowercase())
|
.contains(&body.search_term.to_lowercase())
|
||||||
})
|
});
|
||||||
.is_some();
|
|
||||||
|
|
||||||
if !user_id_matches && !user_displayname_matches {
|
if !user_id_matches && !user_displayname_matches {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's a matching user, but is the sender allowed to see them?
|
let user_in_public_room = services
|
||||||
let mut user_visible = false;
|
|
||||||
|
|
||||||
let user_is_in_public_rooms = services
|
|
||||||
.rooms
|
|
||||||
.state_cache
|
|
||||||
.rooms_joined(&user.user_id)
|
|
||||||
.any(|room| {
|
|
||||||
services
|
|
||||||
.rooms
|
|
||||||
.state_accessor
|
|
||||||
.room_state_get_content::<RoomJoinRulesEventContent>(
|
|
||||||
room,
|
|
||||||
&StateEventType::RoomJoinRules,
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
.map_ok_or(false, |content| content.join_rule == JoinRule::Public)
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if user_is_in_public_rooms {
|
|
||||||
user_visible = true;
|
|
||||||
} else {
|
|
||||||
let user_is_in_shared_rooms = services
|
|
||||||
.rooms
|
.rooms
|
||||||
.state_cache
|
.state_cache
|
||||||
.user_sees_user(sender_user, &user.user_id)
|
.rooms_joined(&user_id)
|
||||||
.await;
|
.map(ToOwned::to_owned)
|
||||||
|
.any(|room| async move {
|
||||||
|
services
|
||||||
|
.rooms
|
||||||
|
.state_accessor
|
||||||
|
.get_join_rules(&room)
|
||||||
|
.map(|rule| matches!(rule, JoinRule::Public))
|
||||||
|
.await
|
||||||
|
});
|
||||||
|
|
||||||
if user_is_in_shared_rooms {
|
let user_sees_user = services
|
||||||
user_visible = true;
|
.rooms
|
||||||
}
|
.state_cache
|
||||||
}
|
.user_sees_user(sender_user, &user_id);
|
||||||
|
|
||||||
user_visible.then_some(user)
|
pin_mut!(user_in_public_room, user_sees_user);
|
||||||
});
|
|
||||||
|
|
||||||
pin_mut!(users);
|
user_in_public_room.or(user_sees_user).await.then_some(user)
|
||||||
|
});
|
||||||
|
|
||||||
let limited = users.by_ref().next().await.is_some();
|
let results = users.by_ref().take(limit).collect().await;
|
||||||
|
let limited = users.next().await.is_some();
|
||||||
let results = users.take(limit).collect().await;
|
|
||||||
|
|
||||||
Ok(search_users::v3::Response { results, limited })
|
Ok(search_users::v3::Response { results, limited })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -317,10 +317,9 @@ fn auth_server_checks(services: &Services, x_matrix: &XMatrix) -> Result<()> {
|
||||||
|
|
||||||
let origin = &x_matrix.origin;
|
let origin = &x_matrix.origin;
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(origin)
|
.is_match(origin.host())
|
||||||
{
|
{
|
||||||
return Err!(Request(Forbidden(debug_warn!(
|
return Err!(Request(Forbidden(debug_warn!(
|
||||||
"Federation requests from {origin} denied."
|
"Federation requests from {origin} denied."
|
||||||
|
|
|
||||||
|
|
@ -38,20 +38,18 @@ pub(crate) async fn create_invite_route(
|
||||||
|
|
||||||
if let Some(server) = body.room_id.server_name() {
|
if let Some(server) = body.room_id.server_name() {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(&server.to_owned())
|
.is_match(server.host())
|
||||||
{
|
{
|
||||||
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
|
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(body.origin())
|
.is_match(body.origin().host())
|
||||||
{
|
{
|
||||||
warn!(
|
warn!(
|
||||||
"Received federated/remote invite from banned server {} for room ID {}. Rejecting.",
|
"Received federated/remote invite from banned server {} for room ID {}. Rejecting.",
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,9 @@ pub(crate) async fn create_join_event_template_route(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(body.origin())
|
.is_match(body.origin().host())
|
||||||
{
|
{
|
||||||
warn!(
|
warn!(
|
||||||
"Server {} for remote user {} tried joining room ID {} which has a server name that \
|
"Server {} for remote user {} tried joining room ID {} which has a server name that \
|
||||||
|
|
@ -59,10 +58,9 @@ pub(crate) async fn create_join_event_template_route(
|
||||||
|
|
||||||
if let Some(server) = body.room_id.server_name() {
|
if let Some(server) = body.room_id.server_name() {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(&server.to_owned())
|
.is_match(server.host())
|
||||||
{
|
{
|
||||||
return Err!(Request(Forbidden(warn!(
|
return Err!(Request(Forbidden(warn!(
|
||||||
"Room ID server name {server} is banned on this homeserver."
|
"Room ID server name {server} is banned on this homeserver."
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,9 @@ pub(crate) async fn create_knock_event_template_route(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(body.origin())
|
.is_match(body.origin().host())
|
||||||
{
|
{
|
||||||
warn!(
|
warn!(
|
||||||
"Server {} for remote user {} tried knocking room ID {} which has a server name \
|
"Server {} for remote user {} tried knocking room ID {} which has a server name \
|
||||||
|
|
@ -50,10 +49,9 @@ pub(crate) async fn create_knock_event_template_route(
|
||||||
|
|
||||||
if let Some(server) = body.room_id.server_name() {
|
if let Some(server) = body.room_id.server_name() {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(&server.to_owned())
|
.is_match(server.host())
|
||||||
{
|
{
|
||||||
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
|
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -268,10 +268,9 @@ pub(crate) async fn create_join_event_v1_route(
|
||||||
body: Ruma<create_join_event::v1::Request>,
|
body: Ruma<create_join_event::v1::Request>,
|
||||||
) -> Result<create_join_event::v1::Response> {
|
) -> Result<create_join_event::v1::Response> {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(body.origin())
|
.is_match(body.origin().host())
|
||||||
{
|
{
|
||||||
warn!(
|
warn!(
|
||||||
"Server {} tried joining room ID {} through us who has a server name that is \
|
"Server {} tried joining room ID {} through us who has a server name that is \
|
||||||
|
|
@ -284,10 +283,9 @@ pub(crate) async fn create_join_event_v1_route(
|
||||||
|
|
||||||
if let Some(server) = body.room_id.server_name() {
|
if let Some(server) = body.room_id.server_name() {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(&server.to_owned())
|
.is_match(server.host())
|
||||||
{
|
{
|
||||||
warn!(
|
warn!(
|
||||||
"Server {} tried joining room ID {} through us which has a server name that is \
|
"Server {} tried joining room ID {} through us which has a server name that is \
|
||||||
|
|
@ -316,20 +314,18 @@ pub(crate) async fn create_join_event_v2_route(
|
||||||
body: Ruma<create_join_event::v2::Request>,
|
body: Ruma<create_join_event::v2::Request>,
|
||||||
) -> Result<create_join_event::v2::Response> {
|
) -> Result<create_join_event::v2::Response> {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(body.origin())
|
.is_match(body.origin().host())
|
||||||
{
|
{
|
||||||
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
|
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(server) = body.room_id.server_name() {
|
if let Some(server) = body.room_id.server_name() {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(&server.to_owned())
|
.is_match(server.host())
|
||||||
{
|
{
|
||||||
warn!(
|
warn!(
|
||||||
"Server {} tried joining room ID {} through us which has a server name that is \
|
"Server {} tried joining room ID {} through us which has a server name that is \
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,9 @@ pub(crate) async fn create_knock_event_v1_route(
|
||||||
body: Ruma<send_knock::v1::Request>,
|
body: Ruma<send_knock::v1::Request>,
|
||||||
) -> Result<send_knock::v1::Response> {
|
) -> Result<send_knock::v1::Response> {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(body.origin())
|
.is_match(body.origin().host())
|
||||||
{
|
{
|
||||||
warn!(
|
warn!(
|
||||||
"Server {} tried knocking room ID {} who has a server name that is globally \
|
"Server {} tried knocking room ID {} who has a server name that is globally \
|
||||||
|
|
@ -42,10 +41,9 @@ pub(crate) async fn create_knock_event_v1_route(
|
||||||
|
|
||||||
if let Some(server) = body.room_id.server_name() {
|
if let Some(server) = body.room_id.server_name() {
|
||||||
if services
|
if services
|
||||||
.server
|
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(&server.to_owned())
|
.is_match(server.host())
|
||||||
{
|
{
|
||||||
warn!(
|
warn!(
|
||||||
"Server {} tried knocking room ID {} which has a server name that is globally \
|
"Server {} tried knocking room ID {} which has a server name that is globally \
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ pub mod manager;
|
||||||
pub mod proxy;
|
pub mod proxy;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, BTreeSet, HashSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
@ -715,7 +715,7 @@ pub struct Config {
|
||||||
/// Currently, conduwuit doesn't support inbound batched key requests, so
|
/// Currently, conduwuit doesn't support inbound batched key requests, so
|
||||||
/// this list should only contain other Synapse servers.
|
/// this list should only contain other Synapse servers.
|
||||||
///
|
///
|
||||||
/// example: ["matrix.org", "envs.net", "tchncs.de"]
|
/// example: ["matrix.org", "tchncs.de"]
|
||||||
///
|
///
|
||||||
/// default: ["matrix.org"]
|
/// default: ["matrix.org"]
|
||||||
#[serde(default = "default_trusted_servers")]
|
#[serde(default = "default_trusted_servers")]
|
||||||
|
|
@ -1361,15 +1361,18 @@ pub struct Config {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub prune_missing_media: bool,
|
pub prune_missing_media: bool,
|
||||||
|
|
||||||
/// Vector list of servers that conduwuit will refuse to download remote
|
/// Vector list of regex patterns of server names that conduwuit will refuse
|
||||||
/// media from.
|
/// to download remote media from.
|
||||||
|
///
|
||||||
|
/// example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"]
|
||||||
///
|
///
|
||||||
/// default: []
|
/// default: []
|
||||||
#[serde(default)]
|
#[serde(default, with = "serde_regex")]
|
||||||
pub prevent_media_downloads_from: HashSet<OwnedServerName>,
|
pub prevent_media_downloads_from: RegexSet,
|
||||||
|
|
||||||
/// List of forbidden server names that we will block incoming AND outgoing
|
/// List of forbidden server names via regex patterns that we will block
|
||||||
/// federation with, and block client room joins / remote user invites.
|
/// incoming AND outgoing federation with, and block client room joins /
|
||||||
|
/// remote user invites.
|
||||||
///
|
///
|
||||||
/// This check is applied on the room ID, room alias, sender server name,
|
/// This check is applied on the room ID, room alias, sender server name,
|
||||||
/// sender user's server name, inbound federation X-Matrix origin, and
|
/// sender user's server name, inbound federation X-Matrix origin, and
|
||||||
|
|
@ -1377,17 +1380,21 @@ pub struct Config {
|
||||||
///
|
///
|
||||||
/// Basically "global" ACLs.
|
/// Basically "global" ACLs.
|
||||||
///
|
///
|
||||||
/// default: []
|
/// example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"]
|
||||||
#[serde(default)]
|
|
||||||
pub forbidden_remote_server_names: HashSet<OwnedServerName>,
|
|
||||||
|
|
||||||
/// List of forbidden server names that we will block all outgoing federated
|
|
||||||
/// room directory requests for. Useful for preventing our users from
|
|
||||||
/// wandering into bad servers or spaces.
|
|
||||||
///
|
///
|
||||||
/// default: []
|
/// default: []
|
||||||
#[serde(default = "HashSet::new")]
|
#[serde(default, with = "serde_regex")]
|
||||||
pub forbidden_remote_room_directory_server_names: HashSet<OwnedServerName>,
|
pub forbidden_remote_server_names: RegexSet,
|
||||||
|
|
||||||
|
/// List of forbidden server names via regex patterns that we will block all
|
||||||
|
/// outgoing federated room directory requests for. Useful for preventing
|
||||||
|
/// our users from wandering into bad servers or spaces.
|
||||||
|
///
|
||||||
|
/// example: ["badserver\.tld$", "badphrase", "19dollarfortnitecards"]
|
||||||
|
///
|
||||||
|
/// default: []
|
||||||
|
#[serde(default, with = "serde_regex")]
|
||||||
|
pub forbidden_remote_room_directory_server_names: RegexSet,
|
||||||
|
|
||||||
/// Vector list of IPv4 and IPv6 CIDR ranges / subnets *in quotes* that you
|
/// Vector list of IPv4 and IPv6 CIDR ranges / subnets *in quotes* that you
|
||||||
/// do not want conduwuit to send outbound requests to. Defaults to
|
/// do not want conduwuit to send outbound requests to. Defaults to
|
||||||
|
|
@ -1508,11 +1515,10 @@ pub struct Config {
|
||||||
/// used, and startup as warnings if any room aliases in your database have
|
/// used, and startup as warnings if any room aliases in your database have
|
||||||
/// a forbidden room alias/ID.
|
/// a forbidden room alias/ID.
|
||||||
///
|
///
|
||||||
/// example: ["19dollarfortnitecards", "b[4a]droom"]
|
/// example: ["19dollarfortnitecards", "b[4a]droom", "badphrase"]
|
||||||
///
|
///
|
||||||
/// default: []
|
/// default: []
|
||||||
#[serde(default)]
|
#[serde(default, with = "serde_regex")]
|
||||||
#[serde(with = "serde_regex")]
|
|
||||||
pub forbidden_alias_names: RegexSet,
|
pub forbidden_alias_names: RegexSet,
|
||||||
|
|
||||||
/// List of forbidden username patterns/strings.
|
/// List of forbidden username patterns/strings.
|
||||||
|
|
@ -1524,11 +1530,10 @@ pub struct Config {
|
||||||
/// startup as warnings if any local users in your database have a forbidden
|
/// startup as warnings if any local users in your database have a forbidden
|
||||||
/// username.
|
/// username.
|
||||||
///
|
///
|
||||||
/// example: ["administrator", "b[a4]dusernam[3e]"]
|
/// example: ["administrator", "b[a4]dusernam[3e]", "badphrase"]
|
||||||
///
|
///
|
||||||
/// default: []
|
/// default: []
|
||||||
#[serde(default)]
|
#[serde(default, with = "serde_regex")]
|
||||||
#[serde(with = "serde_regex")]
|
|
||||||
pub forbidden_usernames: RegexSet,
|
pub forbidden_usernames: RegexSet,
|
||||||
|
|
||||||
/// Retry failed and incomplete messages to remote servers immediately upon
|
/// Retry failed and incomplete messages to remote servers immediately upon
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ where
|
||||||
.server
|
.server
|
||||||
.config
|
.config
|
||||||
.forbidden_remote_server_names
|
.forbidden_remote_server_names
|
||||||
.contains(dest)
|
.is_match(dest.host())
|
||||||
{
|
{
|
||||||
return Err!(Request(Forbidden(debug_warn!("Federation with {dest} is not allowed."))));
|
return Err!(Request(Forbidden(debug_warn!("Federation with {dest} is not allowed."))));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -426,7 +426,13 @@ fn check_fetch_authorized(&self, mxc: &Mxc<'_>) -> Result<()> {
|
||||||
.server
|
.server
|
||||||
.config
|
.config
|
||||||
.prevent_media_downloads_from
|
.prevent_media_downloads_from
|
||||||
.contains(mxc.server_name)
|
.is_match(mxc.server_name.host())
|
||||||
|
|| self
|
||||||
|
.services
|
||||||
|
.server
|
||||||
|
.config
|
||||||
|
.forbidden_remote_server_names
|
||||||
|
.is_match(mxc.server_name.host())
|
||||||
{
|
{
|
||||||
// we'll lie to the client and say the blocked server's media was not found and
|
// we'll lie to the client and say the blocked server's media was not found and
|
||||||
// log. the client has no way of telling anyways so this is a security bonus.
|
// log. the client has no way of telling anyways so this is a security bonus.
|
||||||
|
|
|
||||||
|
|
@ -491,7 +491,7 @@
|
||||||
{"Action":"fail","Test":"TestRoomCreationReportsEventsToMyself"}
|
{"Action":"fail","Test":"TestRoomCreationReportsEventsToMyself"}
|
||||||
{"Action":"fail","Test":"TestRoomCreationReportsEventsToMyself/parallel"}
|
{"Action":"fail","Test":"TestRoomCreationReportsEventsToMyself/parallel"}
|
||||||
{"Action":"pass","Test":"TestRoomCreationReportsEventsToMyself/parallel/Joining_room_twice_is_idempotent"}
|
{"Action":"pass","Test":"TestRoomCreationReportsEventsToMyself/parallel/Joining_room_twice_is_idempotent"}
|
||||||
{"Action":"pass","Test":"TestRoomCreationReportsEventsToMyself/parallel/Room_creation_reports_m.room.create_to_myself"}
|
{"Action":"fail","Test":"TestRoomCreationReportsEventsToMyself/parallel/Room_creation_reports_m.room.create_to_myself"}
|
||||||
{"Action":"pass","Test":"TestRoomCreationReportsEventsToMyself/parallel/Room_creation_reports_m.room.member_to_myself"}
|
{"Action":"pass","Test":"TestRoomCreationReportsEventsToMyself/parallel/Room_creation_reports_m.room.member_to_myself"}
|
||||||
{"Action":"pass","Test":"TestRoomCreationReportsEventsToMyself/parallel/Setting_room_topic_reports_m.room.topic_to_myself"}
|
{"Action":"pass","Test":"TestRoomCreationReportsEventsToMyself/parallel/Setting_room_topic_reports_m.room.topic_to_myself"}
|
||||||
{"Action":"fail","Test":"TestRoomCreationReportsEventsToMyself/parallel/Setting_state_twice_is_idempotent"}
|
{"Action":"fail","Test":"TestRoomCreationReportsEventsToMyself/parallel/Setting_state_twice_is_idempotent"}
|
||||||
|
|
@ -527,17 +527,17 @@
|
||||||
{"Action":"pass","Test":"TestRoomMessagesLazyLoadingLocalUser"}
|
{"Action":"pass","Test":"TestRoomMessagesLazyLoadingLocalUser"}
|
||||||
{"Action":"pass","Test":"TestRoomReadMarkers"}
|
{"Action":"pass","Test":"TestRoomReadMarkers"}
|
||||||
{"Action":"pass","Test":"TestRoomReceipts"}
|
{"Action":"pass","Test":"TestRoomReceipts"}
|
||||||
{"Action":"fail","Test":"TestRoomSpecificUsernameAtJoin"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin"}
|
||||||
{"Action":"fail","Test":"TestRoomSpecificUsernameAtJoin/Bob_can_find_Alice_by_mxid"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Bob_can_find_Alice_by_mxid"}
|
||||||
{"Action":"fail","Test":"TestRoomSpecificUsernameAtJoin/Bob_can_find_Alice_by_profile_display_name"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Bob_can_find_Alice_by_profile_display_name"}
|
||||||
{"Action":"fail","Test":"TestRoomSpecificUsernameAtJoin/Eve_can_find_Alice_by_mxid"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Eve_can_find_Alice_by_mxid"}
|
||||||
{"Action":"fail","Test":"TestRoomSpecificUsernameAtJoin/Eve_can_find_Alice_by_profile_display_name"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Eve_can_find_Alice_by_profile_display_name"}
|
||||||
{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Eve_cannot_find_Alice_by_room-specific_name_that_Eve_is_not_privy_to"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Eve_cannot_find_Alice_by_room-specific_name_that_Eve_is_not_privy_to"}
|
||||||
{"Action":"fail","Test":"TestRoomSpecificUsernameChange"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameChange"}
|
||||||
{"Action":"fail","Test":"TestRoomSpecificUsernameChange/Bob_can_find_Alice_by_mxid"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameChange/Bob_can_find_Alice_by_mxid"}
|
||||||
{"Action":"fail","Test":"TestRoomSpecificUsernameChange/Bob_can_find_Alice_by_profile_display_name"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameChange/Bob_can_find_Alice_by_profile_display_name"}
|
||||||
{"Action":"fail","Test":"TestRoomSpecificUsernameChange/Eve_can_find_Alice_by_mxid"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameChange/Eve_can_find_Alice_by_mxid"}
|
||||||
{"Action":"fail","Test":"TestRoomSpecificUsernameChange/Eve_can_find_Alice_by_profile_display_name"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameChange/Eve_can_find_Alice_by_profile_display_name"}
|
||||||
{"Action":"pass","Test":"TestRoomSpecificUsernameChange/Eve_cannot_find_Alice_by_room-specific_name_that_Eve_is_not_privy_to"}
|
{"Action":"pass","Test":"TestRoomSpecificUsernameChange/Eve_cannot_find_Alice_by_room-specific_name_that_Eve_is_not_privy_to"}
|
||||||
{"Action":"fail","Test":"TestRoomState"}
|
{"Action":"fail","Test":"TestRoomState"}
|
||||||
{"Action":"fail","Test":"TestRoomState/Parallel"}
|
{"Action":"fail","Test":"TestRoomState/Parallel"}
|
||||||
|
|
@ -589,7 +589,7 @@
|
||||||
{"Action":"fail","Test":"TestSync/parallel/Newly_joined_room_has_correct_timeline_in_incremental_sync"}
|
{"Action":"fail","Test":"TestSync/parallel/Newly_joined_room_has_correct_timeline_in_incremental_sync"}
|
||||||
{"Action":"fail","Test":"TestSync/parallel/Newly_joined_room_includes_presence_in_incremental_sync"}
|
{"Action":"fail","Test":"TestSync/parallel/Newly_joined_room_includes_presence_in_incremental_sync"}
|
||||||
{"Action":"pass","Test":"TestSync/parallel/Newly_joined_room_is_included_in_an_incremental_sync"}
|
{"Action":"pass","Test":"TestSync/parallel/Newly_joined_room_is_included_in_an_incremental_sync"}
|
||||||
{"Action":"fail","Test":"TestSync/parallel/sync_should_succeed_even_if_the_sync_token_points_to_a_redaction_of_an_unknown_event"}
|
{"Action":"pass","Test":"TestSync/parallel/sync_should_succeed_even_if_the_sync_token_points_to_a_redaction_of_an_unknown_event"}
|
||||||
{"Action":"pass","Test":"TestSyncFilter"}
|
{"Action":"pass","Test":"TestSyncFilter"}
|
||||||
{"Action":"pass","Test":"TestSyncFilter/Can_create_filter"}
|
{"Action":"pass","Test":"TestSyncFilter/Can_create_filter"}
|
||||||
{"Action":"pass","Test":"TestSyncFilter/Can_download_filter"}
|
{"Action":"pass","Test":"TestSyncFilter/Can_download_filter"}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue