mirror of
https://gitlab.com/famedly/conduit.git
synced 2025-06-27 16:35:59 +00:00
feat: forbid usernames & room aliases via regex
This commit is contained in:
parent
b11855e7a1
commit
d625d265bb
8 changed files with 134 additions and 0 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -386,6 +386,7 @@ dependencies = [
|
|||
"http",
|
||||
"hyper",
|
||||
"image",
|
||||
"itertools 0.12.1",
|
||||
"jsonwebtoken",
|
||||
"lazy_static",
|
||||
"lru-cache",
|
||||
|
@ -407,6 +408,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_html_form",
|
||||
"serde_json",
|
||||
"serde_regex",
|
||||
"serde_yaml",
|
||||
"sha-1",
|
||||
"thiserror",
|
||||
|
@ -2420,6 +2422,16 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_regex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.5"
|
||||
|
|
|
@ -78,6 +78,9 @@ ring = "0.17.7"
|
|||
trust-dns-resolver = "0.22.0"
|
||||
# Used to find matching events for appservices
|
||||
regex = "1.8.1"
|
||||
# Used to load forbidden room/user regex from config
|
||||
serde_regex = "1.1.0"
|
||||
itertools = "0.12.0"
|
||||
# jwt jsonwebtokens
|
||||
jsonwebtoken = "9.2.0"
|
||||
# Performance measurements
|
||||
|
|
|
@ -54,6 +54,17 @@ pub async fn get_register_available_route(
|
|||
));
|
||||
}
|
||||
|
||||
if services()
|
||||
.globals
|
||||
.forbidden_usernames()
|
||||
.is_match(user_id.localpart())
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Unknown,
|
||||
"Username is forbidden.",
|
||||
));
|
||||
}
|
||||
|
||||
// TODO add check for appservice namespaces
|
||||
|
||||
// If no if check is true we have an username that's available to be used.
|
||||
|
@ -107,6 +118,16 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
|
|||
"Desired user ID is already taken.",
|
||||
));
|
||||
}
|
||||
if services()
|
||||
.globals
|
||||
.forbidden_usernames()
|
||||
.is_match(proposed_user_id.localpart())
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Unknown,
|
||||
"Username is forbidden.",
|
||||
));
|
||||
}
|
||||
proposed_user_id
|
||||
}
|
||||
_ => loop {
|
||||
|
|
|
@ -26,6 +26,17 @@ pub async fn create_alias_route(
|
|||
));
|
||||
}
|
||||
|
||||
if services()
|
||||
.globals
|
||||
.forbidden_alias_names()
|
||||
.is_match(body.room_alias.alias())
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Unknown,
|
||||
"Room alias is forbidden.",
|
||||
));
|
||||
}
|
||||
|
||||
if services()
|
||||
.rooms
|
||||
.alias
|
||||
|
|
|
@ -81,6 +81,16 @@ pub async fn create_room_route(
|
|||
body.room_alias_name
|
||||
.as_ref()
|
||||
.map_or(Ok(None), |localpart| {
|
||||
if services()
|
||||
.globals
|
||||
.forbidden_alias_names()
|
||||
.is_match(localpart)
|
||||
{
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Unknown,
|
||||
"Room alias is forbidden.",
|
||||
));
|
||||
}
|
||||
// TODO: Check for invalid characters and maximum length
|
||||
let alias = RoomAliasId::parse(format!(
|
||||
"#{}:{}",
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
use itertools::Itertools;
|
||||
use regex::RegexSet;
|
||||
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fmt,
|
||||
|
@ -84,6 +87,14 @@ pub struct Config {
|
|||
|
||||
#[serde(flatten)]
|
||||
pub catchall: BTreeMap<String, IgnoredAny>,
|
||||
|
||||
#[serde(default = "RegexSet::empty")]
|
||||
#[serde(with = "serde_regex")]
|
||||
pub forbidden_alias_names: RegexSet,
|
||||
|
||||
#[serde(default = "RegexSet::empty")]
|
||||
#[serde(with = "serde_regex")]
|
||||
pub forbidden_usernames: RegexSet,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
|
@ -195,6 +206,12 @@ impl fmt::Display for Config {
|
|||
}
|
||||
&lst.join(", ")
|
||||
}),
|
||||
("Forbidden usernames", {
|
||||
&self.forbidden_usernames.patterns().iter().join(", ")
|
||||
}),
|
||||
("Forbidden room names", {
|
||||
&self.forbidden_alias_names.patterns().iter().join(", ")
|
||||
}),
|
||||
];
|
||||
|
||||
let mut msg: String = "Active config values:\n\n".to_owned();
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::{
|
|||
};
|
||||
use abstraction::{KeyValueDatabaseEngine, KvTree};
|
||||
use directories::ProjectDirs;
|
||||
use itertools::Itertools;
|
||||
use lru_cache::LruCache;
|
||||
use ruma::{
|
||||
events::{
|
||||
|
@ -943,6 +944,56 @@ impl KeyValueDatabase {
|
|||
latest_database_version
|
||||
);
|
||||
|
||||
{
|
||||
let patterns = &services().globals.config.forbidden_usernames;
|
||||
if !patterns.is_empty() {
|
||||
for user_id in services()
|
||||
.users
|
||||
.iter()
|
||||
.filter_map(std::result::Result::ok)
|
||||
.filter(|user| !services().users.is_deactivated(user).unwrap_or(true))
|
||||
.filter(|user| user.server_name() == services().globals.server_name())
|
||||
{
|
||||
let matches = patterns.matches(user_id.localpart());
|
||||
if matches.matched_any() {
|
||||
warn!(
|
||||
"User {} matches the following forbidden username patterns: {}",
|
||||
user_id.to_string(),
|
||||
matches
|
||||
.into_iter()
|
||||
.map(|x| &patterns.patterns()[x])
|
||||
.join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let patterns = &services().globals.config.forbidden_alias_names;
|
||||
if !patterns.is_empty() {
|
||||
for address in services().rooms.metadata.iter_ids() {
|
||||
let room_id = address?;
|
||||
let room_aliases = services().rooms.alias.local_aliases_for_room(&room_id);
|
||||
for room_alias_result in room_aliases {
|
||||
let room_alias = room_alias_result?;
|
||||
let matches = patterns.matches(room_alias.alias());
|
||||
if matches.matched_any() {
|
||||
warn!(
|
||||
"Room with alias {} ({}) matches the following forbidden room name patterns: {}",
|
||||
room_alias,
|
||||
&room_id,
|
||||
matches
|
||||
.into_iter()
|
||||
.map(|x| &patterns.patterns()[x])
|
||||
.join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!(
|
||||
"Loaded {} database with version {}",
|
||||
services().globals.config.database_backend,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use regex::RegexSet;
|
||||
use ruma::{
|
||||
serde::Base64, OwnedDeviceId, OwnedEventId, OwnedRoomId, OwnedServerName,
|
||||
OwnedServerSigningKeyId, OwnedUserId,
|
||||
|
@ -352,6 +353,14 @@ impl Service {
|
|||
&self.config.emergency_password
|
||||
}
|
||||
|
||||
pub fn forbidden_alias_names(&self) -> &RegexSet {
|
||||
&self.config.forbidden_alias_names
|
||||
}
|
||||
|
||||
pub fn forbidden_usernames(&self) -> &RegexSet {
|
||||
&self.config.forbidden_usernames
|
||||
}
|
||||
|
||||
pub fn supported_room_versions(&self) -> Vec<RoomVersionId> {
|
||||
let mut room_versions: Vec<RoomVersionId> = vec![];
|
||||
room_versions.extend(self.stable_room_versions.clone());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue