diff --git a/config/defaults.hjson b/config/defaults.hjson index 96dc30b79..c12f879c7 100644 --- a/config/defaults.hjson +++ b/config/defaults.hjson @@ -122,5 +122,5 @@ } # Sets a response Access-Control-Allow-Origin CORS header # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin - cors_origin: "*" + cors_origin: "lemmy.tld" } diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index 65aa1f612..edcf7db30 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -16,9 +16,8 @@ use lemmy_api_common::{ }, }; use lemmy_db_schema::{ - impls::actor_language::default_post_language, + impls::actor_language::validate_post_language, source::{ - actor_language::CommunityLanguage, comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm}, comment_reply::{CommentReply, CommentReplyUpdateForm}, local_site::LocalSite, @@ -93,21 +92,13 @@ pub async fn create_comment( check_comment_depth(parent)?; } - // attempt to set default language if none was provided - let language_id = match data.language_id { - Some(lid) => lid, - None => { - default_post_language( - &mut context.pool(), - community_id, - local_user_view.local_user.id, - ) - .await? - } - }; - - CommunityLanguage::is_allowed_community_language(&mut context.pool(), language_id, community_id) - .await?; + let language_id = validate_post_language( + &mut context.pool(), + data.language_id, + community_id, + local_user_view.local_user.id, + ) + .await?; let comment_form = CommentInsertForm { language_id: Some(language_id), diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index 95cc85fe4..85ee9bff0 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -13,8 +13,8 @@ use lemmy_api_common::{ }, }; use lemmy_db_schema::{ + impls::actor_language::validate_post_language, source::{ - actor_language::CommunityLanguage, comment::{Comment, CommentUpdateForm}, local_site::LocalSite, }, @@ -55,14 +55,13 @@ pub async fn update_comment( Err(LemmyErrorType::NoCommentEditAllowed)? } - if let Some(language_id) = data.language_id { - CommunityLanguage::is_allowed_community_language( - &mut context.pool(), - language_id, - orig_comment.community.id, - ) - .await?; - } + let language_id = validate_post_language( + &mut context.pool(), + data.language_id, + orig_comment.community.id, + local_user_view.local_user.id, + ) + .await?; let slur_regex = local_site_to_slur_regex(&local_site); let url_blocklist = get_url_blocklist(&context).await?; @@ -74,7 +73,7 @@ pub async fn update_comment( let comment_id = data.comment_id; let form = CommentUpdateForm { content, - language_id: data.language_id, + language_id: Some(language_id), updated: Some(Some(naive_now())), ..Default::default() }; diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index d2a3d0fb7..8ff3f68cc 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -16,9 +16,8 @@ use lemmy_api_common::{ }, }; use lemmy_db_schema::{ - impls::actor_language::default_post_language, + impls::actor_language::validate_post_language, source::{ - actor_language::CommunityLanguage, community::Community, local_site::LocalSite, post::{Post, PostInsertForm, PostLike, PostLikeForm, PostRead}, @@ -97,23 +96,13 @@ pub async fn create_post( .await?; } - // attempt to set default language if none was provided - let language_id = match data.language_id { - Some(lid) => lid, - None => { - default_post_language( - &mut context.pool(), - community.id, - local_user_view.local_user.id, - ) - .await? - } - }; - - // Only need to check if language is allowed in case user set it explicitly. When using default - // language, it already only returns allowed languages. - CommunityLanguage::is_allowed_community_language(&mut context.pool(), language_id, community.id) - .await?; + let language_id = validate_post_language( + &mut context.pool(), + data.language_id, + data.community_id, + local_user_view.local_user.id, + ) + .await?; let scheduled_publish_time = convert_published_time(data.scheduled_publish_time, &local_user_view, &context).await?; diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index fc23e7d9e..217a6cc24 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -15,8 +15,8 @@ use lemmy_api_common::{ }, }; use lemmy_db_schema::{ + impls::actor_language::validate_post_language, source::{ - actor_language::CommunityLanguage, community::Community, local_site::LocalSite, post::{Post, PostUpdateForm}, @@ -101,14 +101,13 @@ pub async fn update_post( Err(LemmyErrorType::NoPostEditAllowed)? } - if let Some(language_id) = data.language_id { - CommunityLanguage::is_allowed_community_language( - &mut context.pool(), - language_id, - orig_post.community.id, - ) - .await?; - } + let language_id = validate_post_language( + &mut context.pool(), + data.language_id, + orig_post.post.community_id, + local_user_view.local_user.id, + ) + .await?; // handle changes to scheduled_publish_time let scheduled_publish_time = match ( @@ -131,7 +130,7 @@ pub async fn update_post( body, alt_text, nsfw: data.nsfw, - language_id: data.language_id, + language_id: Some(language_id), updated: Some(Some(naive_now())), scheduled_publish_time, ..Default::default() diff --git a/crates/db_schema/src/impls/actor_language.rs b/crates/db_schema/src/impls/actor_language.rs index b4ad0d347..8d4c471be 100644 --- a/crates/db_schema/src/impls/actor_language.rs +++ b/crates/db_schema/src/impls/actor_language.rs @@ -197,7 +197,7 @@ impl SiteLanguage { impl CommunityLanguage { /// Returns true if the given language is one of configured languages for given community - pub async fn is_allowed_community_language( + async fn is_allowed_community_language( pool: &mut DbPool<'_>, for_language_id: LanguageId, for_community_id: CommunityId, @@ -319,29 +319,38 @@ impl CommunityLanguage { } } -pub async fn default_post_language( +pub async fn validate_post_language( pool: &mut DbPool<'_>, + language_id: Option, community_id: CommunityId, local_user_id: LocalUserId, -) -> Result { +) -> LemmyResult { use crate::schema::{community_language::dsl as cl, local_user_language::dsl as ul}; let conn = &mut get_conn(pool).await?; - let mut intersection = ul::local_user_language - .inner_join(cl::community_language.on(ul::language_id.eq(cl::language_id))) - .filter(ul::local_user_id.eq(local_user_id)) - .filter(cl::community_id.eq(community_id)) - .select(cl::language_id) - .get_results::(conn) - .await?; + let language_id = match language_id { + None | Some(LanguageId(0)) => { + let mut intersection = ul::local_user_language + .inner_join(cl::community_language.on(ul::language_id.eq(cl::language_id))) + .filter(ul::local_user_id.eq(local_user_id)) + .filter(cl::community_id.eq(community_id)) + .select(cl::language_id) + .get_results::(conn) + .await?; - if intersection.len() == 1 { - Ok(intersection.pop().unwrap_or(UNDETERMINED_ID)) - } else if intersection.len() == 2 && intersection.contains(&UNDETERMINED_ID) { - intersection.retain(|i| i != &UNDETERMINED_ID); - Ok(intersection.pop().unwrap_or(UNDETERMINED_ID)) - } else { - Ok(UNDETERMINED_ID) - } + if intersection.len() == 1 { + intersection.pop().unwrap_or(UNDETERMINED_ID) + } else if intersection.len() == 2 && intersection.contains(&UNDETERMINED_ID) { + intersection.retain(|i| i != &UNDETERMINED_ID); + intersection.pop().unwrap_or(UNDETERMINED_ID) + } else { + UNDETERMINED_ID + } + } + Some(lid) => lid, + }; + + CommunityLanguage::is_allowed_community_language(pool, language_id, community_id).await?; + Ok(language_id) } /// If no language is given, set all languages @@ -590,7 +599,7 @@ mod tests { #[tokio::test] #[serial] - async fn test_default_post_language() -> Result<(), Error> { + async fn test_validate_post_language() -> LemmyResult<()> { let pool = &build_db_pool_for_tests(); let pool = &mut pool.into(); let (site, instance) = create_test_site(pool).await?; @@ -613,8 +622,11 @@ mod tests { LocalUserLanguage::update(pool, test_langs2, local_user.id).await?; // no overlap in user/community languages, so defaults to undetermined - let def1 = default_post_language(pool, community.id, local_user.id).await?; - assert_eq!(UNDETERMINED_ID, def1); + let def1 = validate_post_language(pool, None, community.id, local_user.id).await; + assert_eq!( + Some(LemmyErrorType::LanguageNotAllowed), + def1.err().map(|e| e.error_type) + ); let ru = Language::read_id_from_code(pool, "ru").await?; let test_langs3 = vec![ @@ -626,7 +638,7 @@ mod tests { LocalUserLanguage::update(pool, test_langs3, local_user.id).await?; // this time, both have ru as common lang - let def2 = default_post_language(pool, community.id, local_user.id).await?; + let def2 = validate_post_language(pool, None, community.id, local_user.id).await?; assert_eq!(ru, def2); Person::delete(pool, person.id).await?; diff --git a/crates/utils/src/settings/structs.rs b/crates/utils/src/settings/structs.rs index c95f66644..e8106d482 100644 --- a/crates/utils/src/settings/structs.rs +++ b/crates/utils/src/settings/structs.rs @@ -52,7 +52,7 @@ pub struct Settings { /// Sets a response Access-Control-Allow-Origin CORS header /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin #[default(None)] - #[doku(example = "*")] + #[doku(example = "lemmy.tld")] cors_origin: Option, } diff --git a/src/lib.rs b/src/lib.rs index 9da09f65b..b94b5eab1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -339,23 +339,31 @@ fn create_http_server( fn cors_config(settings: &Settings) -> Cors { let self_origin = settings.get_protocol_and_hostname(); let cors_origin_setting = settings.cors_origin(); + + // A default setting for either wildcard, or None + let cors_default = Cors::default() + .allow_any_origin() + .allow_any_method() + .allow_any_header() + .expose_any_header() + .max_age(3600); + match (cors_origin_setting.clone(), cfg!(debug_assertions)) { (Some(origin), false) => { // Need to call send_wildcard() explicitly, passing this into allowed_origin() results in // error - if cors_origin_setting.as_deref() == Some("*") { - Cors::default().allow_any_origin().send_wildcard() + if origin == "*" { + cors_default } else { Cors::default() .allowed_origin(&origin) .allowed_origin(&self_origin) + .allow_any_method() + .allow_any_header() + .expose_any_header() + .max_age(3600) } } - _ => Cors::default() - .allow_any_origin() - .allow_any_method() - .allow_any_header() - .expose_any_header() - .max_age(3600), + _ => cors_default, } }