diff --git a/config/config.hjson b/config/config.hjson index 461efa0d3..236751f4e 100644 --- a/config/config.hjson +++ b/config/config.hjson @@ -39,6 +39,8 @@ pictrs_url: "http://pictrs:8080" # address where iframely is available iframely_url: "http://iframely" + # maximum length of local community and user names + actor_name_max_length: 20 # rate limits for various user actions, by user ip rate_limit: { # maximum number of messages created in interval diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs index 5c55e149e..ecaa9058d 100644 --- a/crates/api_crud/src/community/create.rs +++ b/crates/api_crud/src/community/create.rs @@ -28,7 +28,7 @@ use lemmy_db_schema::source::{ use lemmy_db_views_actor::community_view::CommunityView; use lemmy_utils::{ apub::generate_actor_keypair, - utils::{check_slurs, check_slurs_opt, is_valid_community_name}, + utils::{check_slurs, check_slurs_opt, is_valid_actor_name}, ApiError, ConnectionId, LemmyError, @@ -56,7 +56,7 @@ impl PerformCrud for CreateCommunity { check_slurs(&data.title)?; check_slurs_opt(&data.description)?; - if !is_valid_community_name(&data.name) { + if !is_valid_actor_name(&data.name) { return Err(ApiError::err("invalid_community_name").into()); } diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs index 82788b6da..8047369fa 100644 --- a/crates/api_crud/src/user/create.rs +++ b/crates/api_crud/src/user/create.rs @@ -30,7 +30,7 @@ use lemmy_utils::{ apub::generate_actor_keypair, claims::Claims, settings::structs::Settings, - utils::{check_slurs, is_valid_username}, + utils::{check_slurs, is_valid_actor_name}, ApiError, ConnectionId, LemmyError, @@ -91,7 +91,7 @@ impl PerformCrud for Register { check_slurs(&data.username)?; let actor_keypair = generate_actor_keypair()?; - if !is_valid_username(&data.username) { + if !is_valid_actor_name(&data.username) { return Err(ApiError::err("invalid_username").into()); } let actor_id = generate_apub_endpoint(EndpointType::Person, &data.username)?; diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index f917d9389..ca544bd49 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -89,12 +89,12 @@ impl actix_web::error::ResponseError for LemmyError { lazy_static! { pub static ref WEBFINGER_COMMUNITY_REGEX: Regex = Regex::new(&format!( - "^group:([a-z0-9_]{{3, 20}})@{}$", + "^group:([a-z0-9_]{{3,}})@{}$", Settings::get().hostname() )) .expect("compile webfinger regex"); pub static ref WEBFINGER_USERNAME_REGEX: Regex = Regex::new(&format!( - "^acct:([a-z0-9_]{{3, 20}})@{}$", + "^acct:([a-z0-9_]{{3,}})@{}$", Settings::get().hostname() )) .expect("compile webfinger regex"); diff --git a/crates/utils/src/settings/defaults.rs b/crates/utils/src/settings/defaults.rs index 2dddd3f3b..1333ebe3d 100644 --- a/crates/utils/src/settings/defaults.rs +++ b/crates/utils/src/settings/defaults.rs @@ -18,6 +18,7 @@ impl Default for Settings { pictrs_url: Some("http://pictrs:8080".into()), iframely_url: Some("http://iframely".into()), additional_slurs: None, + actor_name_max_length: Some(20), } } } diff --git a/crates/utils/src/settings/mod.rs b/crates/utils/src/settings/mod.rs index 8c9f82ccf..b247bae93 100644 --- a/crates/utils/src/settings/mod.rs +++ b/crates/utils/src/settings/mod.rs @@ -132,29 +132,52 @@ impl Settings { Ok(Self::read_config_file()?) } - pub fn database(&self) -> DatabaseConfig { - self.database.to_owned().unwrap_or_default() - } pub fn hostname(&self) -> String { - self.hostname.to_owned().unwrap_or_default() + self.hostname.to_owned().expect("No hostname given") } pub fn bind(&self) -> IpAddr { self.bind.expect("return bind address") } pub fn port(&self) -> u16 { - self.port.unwrap_or_default() + self + .port + .unwrap_or_else(|| Settings::default().port.expect("missing port")) } pub fn tls_enabled(&self) -> bool { - self.tls_enabled.unwrap_or_default() + self.tls_enabled.unwrap_or_else(|| { + Settings::default() + .tls_enabled + .expect("missing tls_enabled") + }) } pub fn jwt_secret(&self) -> String { - self.jwt_secret.to_owned().unwrap_or_default() + self + .jwt_secret + .to_owned() + .unwrap_or_else(|| Settings::default().jwt_secret.expect("missing jwt_secret")) } pub fn pictrs_url(&self) -> String { - self.pictrs_url.to_owned().unwrap_or_default() + self + .pictrs_url + .to_owned() + .unwrap_or_else(|| Settings::default().pictrs_url.expect("missing pictrs_url")) } pub fn iframely_url(&self) -> String { - self.iframely_url.to_owned().unwrap_or_default() + self.iframely_url.to_owned().unwrap_or_else(|| { + Settings::default() + .iframely_url + .expect("missing iframely_url") + }) + } + pub fn actor_name_max_length(&self) -> usize { + self.actor_name_max_length.unwrap_or_else(|| { + Settings::default() + .actor_name_max_length + .expect("missing actor name length") + }) + } + pub fn database(&self) -> DatabaseConfig { + self.database.to_owned().unwrap_or_default() } pub fn rate_limit(&self) -> RateLimitConfig { self.rate_limit.to_owned().unwrap_or_default() diff --git a/crates/utils/src/settings/structs.rs b/crates/utils/src/settings/structs.rs index 1a7a74343..1046bd147 100644 --- a/crates/utils/src/settings/structs.rs +++ b/crates/utils/src/settings/structs.rs @@ -18,6 +18,7 @@ pub struct Settings { pub(crate) email: Option, pub(crate) setup: Option, pub(crate) additional_slurs: Option, + pub(crate) actor_name_max_length: Option, } #[derive(Debug, Deserialize, Clone)] diff --git a/crates/utils/src/test.rs b/crates/utils/src/test.rs index 2d9d417f3..33bf38700 100644 --- a/crates/utils/src/test.rs +++ b/crates/utils/src/test.rs @@ -1,9 +1,8 @@ use crate::utils::{ - is_valid_community_name, + is_valid_actor_name, is_valid_display_name, is_valid_matrix_id, is_valid_post_title, - is_valid_username, remove_slurs, scrape_text_for_mentions, slur_check, @@ -21,12 +20,12 @@ fn test_mentions_regex() { } #[test] -fn test_valid_register_username() { - assert!(is_valid_username("Hello_98")); - assert!(is_valid_username("ten")); - assert!(!is_valid_username("Hello-98")); - assert!(!is_valid_username("a")); - assert!(!is_valid_username("")); +fn test_valid_actor_name() { + assert!(is_valid_actor_name("Hello_98")); + assert!(is_valid_actor_name("ten")); + assert!(!is_valid_actor_name("Hello-98")); + assert!(!is_valid_actor_name("a")); + assert!(!is_valid_actor_name("")); } #[test] @@ -41,15 +40,6 @@ fn test_valid_display_name() { ))); } -#[test] -fn test_valid_community_name() { - assert!(is_valid_community_name("example")); - assert!(is_valid_community_name("example_community")); - assert!(!is_valid_community_name("Example")); - assert!(!is_valid_community_name("Ex")); - assert!(!is_valid_community_name("")); -} - #[test] fn test_valid_post_title() { assert!(is_valid_post_title("Post Title")); diff --git a/crates/utils/src/utils.rs b/crates/utils/src/utils.rs index ee0289143..d6e1f25d4 100644 --- a/crates/utils/src/utils.rs +++ b/crates/utils/src/utils.rs @@ -22,8 +22,7 @@ lazy_static! { // TODO keep this old one, it didn't work with port well tho // static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P[\w.]+)@(?P[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)").expect("compile regex"); static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P[\w.]+)@(?P[a-zA-Z0-9._:-]+)").expect("compile regex"); - static ref VALID_USERNAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]{3,20}$").expect("compile regex"); - static ref VALID_COMMUNITY_NAME_REGEX: Regex = Regex::new(r"^[a-z0-9_]{3,20}$").expect("compile regex"); + static ref VALID_ACTOR_NAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]{3,}$").expect("compile regex"); static ref VALID_POST_TITLE_REGEX: Regex = Regex::new(r".*\S.*").expect("compile regex"); static ref VALID_MATRIX_ID_REGEX: Regex = Regex::new(r"^@[A-Za-z0-9._=-]+:[A-Za-z0-9.-]+\.[A-Za-z]{2,}$").expect("compile regex"); // taken from https://en.wikipedia.org/wiki/UTM_parameters @@ -116,8 +115,9 @@ pub fn scrape_text_for_mentions(text: &str) -> Vec { out.into_iter().unique().collect() } -pub fn is_valid_username(name: &str) -> bool { - VALID_USERNAME_REGEX.is_match(name) +pub fn is_valid_actor_name(name: &str) -> bool { + name.chars().count() <= Settings::get().actor_name_max_length() + && VALID_ACTOR_NAME_REGEX.is_match(name) } // Can't do a regex here, reverse lookarounds not supported @@ -125,17 +125,13 @@ pub fn is_valid_display_name(name: &str) -> bool { !name.starts_with('@') && !name.starts_with('\u{200b}') && name.chars().count() >= 3 - && name.chars().count() <= 20 + && name.chars().count() <= Settings::get().actor_name_max_length() } pub fn is_valid_matrix_id(matrix_id: &str) -> bool { VALID_MATRIX_ID_REGEX.is_match(matrix_id) } -pub fn is_valid_community_name(name: &str) -> bool { - VALID_COMMUNITY_NAME_REGEX.is_match(name) -} - pub fn is_valid_post_title(title: &str) -> bool { VALID_POST_TITLE_REGEX.is_match(title) } diff --git a/migrations/2021-07-20-102033_actor_name_length/down.sql b/migrations/2021-07-20-102033_actor_name_length/down.sql new file mode 100644 index 000000000..76cec4c91 --- /dev/null +++ b/migrations/2021-07-20-102033_actor_name_length/down.sql @@ -0,0 +1,10 @@ +DROP VIEW person_alias_1; +DROP VIEW person_alias_2; + +ALTER TABLE community ALTER COLUMN name TYPE varchar(20); +ALTER TABLE community ALTER COLUMN title TYPE varchar(100); +ALTER TABLE person ALTER COLUMN name TYPE varchar(20); +ALTER TABLE person ALTER COLUMN display_name TYPE varchar(20); + +create view person_alias_1 as select * from person; +create view person_alias_2 as select * from person; diff --git a/migrations/2021-07-20-102033_actor_name_length/up.sql b/migrations/2021-07-20-102033_actor_name_length/up.sql new file mode 100644 index 000000000..2e7bc9dfb --- /dev/null +++ b/migrations/2021-07-20-102033_actor_name_length/up.sql @@ -0,0 +1,10 @@ +DROP VIEW person_alias_1; +DROP VIEW person_alias_2; + +ALTER TABLE community ALTER COLUMN name TYPE varchar(255); +ALTER TABLE community ALTER COLUMN title TYPE varchar(255); +ALTER TABLE person ALTER COLUMN name TYPE varchar(255); +ALTER TABLE person ALTER COLUMN display_name TYPE varchar(255); + +create view person_alias_1 as select * from person; +create view person_alias_2 as select * from person;