diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index 21b07420a..66dcea19b 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -18,7 +18,7 @@ doctest = false workspace = true [dependencies] -lemmy_utils = { workspace = true, features = ["default"] } +lemmy_utils = { workspace = true } lemmy_db_schema = { workspace = true, features = ["full"] } lemmy_db_views = { workspace = true, features = ["full"] } lemmy_db_views_moderator = { workspace = true, features = ["full"] } diff --git a/crates/api/src/local_user/login.rs b/crates/api/src/local_user/login.rs index 956dcbba1..1fe337f3c 100644 --- a/crates/api/src/local_user/login.rs +++ b/crates/api/src/local_user/login.rs @@ -1,4 +1,4 @@ -use crate::check_totp_2fa_valid; +use crate::{check_totp_2fa_valid, local_user::check_email_verified}; use actix_web::{ web::{Data, Json}, HttpRequest, @@ -43,15 +43,7 @@ pub async fn login( Err(LemmyErrorType::IncorrectLogin)? } check_user_valid(&local_user_view.person)?; - - // Check if the user's email is verified if email verification is turned on - // However, skip checking verification if the user is an admin - if !local_user_view.local_user.admin - && site_view.local_site.require_email_verification - && !local_user_view.local_user.email_verified - { - Err(LemmyErrorType::EmailNotVerified)? - } + check_email_verified(&local_user_view, &site_view)?; check_registration_application(&local_user_view, &site_view.local_site, &mut context.pool()) .await?; diff --git a/crates/api/src/local_user/mod.rs b/crates/api/src/local_user/mod.rs index 98e023fa5..8bf2e5327 100644 --- a/crates/api/src/local_user/mod.rs +++ b/crates/api/src/local_user/mod.rs @@ -1,3 +1,6 @@ +use lemmy_db_views::structs::{LocalUserView, SiteView}; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; + pub mod add_admin; pub mod ban_person; pub mod block; @@ -16,3 +19,15 @@ pub mod save_settings; pub mod update_totp; pub mod validate_auth; pub mod verify_email; + +/// Check if the user's email is verified if email verification is turned on +/// However, skip checking verification if the user is an admin +fn check_email_verified(local_user_view: &LocalUserView, site_view: &SiteView) -> LemmyResult<()> { + if !local_user_view.local_user.admin + && site_view.local_site.require_email_verification + && !local_user_view.local_user.email_verified + { + Err(LemmyErrorType::EmailNotVerified)? + } + Ok(()) +} diff --git a/crates/api/src/local_user/reset_password.rs b/crates/api/src/local_user/reset_password.rs index 90aa910e0..414f506ba 100644 --- a/crates/api/src/local_user/reset_password.rs +++ b/crates/api/src/local_user/reset_password.rs @@ -1,3 +1,4 @@ +use crate::local_user::check_email_verified; use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, @@ -6,7 +7,7 @@ use lemmy_api_common::{ SuccessResponse, }; use lemmy_db_schema::source::password_reset_request::PasswordResetRequest; -use lemmy_db_views::structs::LocalUserView; +use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] @@ -29,6 +30,8 @@ pub async fn reset_password( if recent_resets_count >= 3 { Err(LemmyErrorType::PasswordResetLimitReached)? } + let site_view = SiteView::read_local(&mut context.pool()).await?; + check_email_verified(&local_user_view, &site_view)?; // Email the pure token to the user. send_password_reset_email(&local_user_view, &mut context.pool(), context.settings()).await?; diff --git a/crates/api_common/Cargo.toml b/crates/api_common/Cargo.toml index 9d144ddb4..0192099f3 100644 --- a/crates/api_common/Cargo.toml +++ b/crates/api_common/Cargo.toml @@ -23,7 +23,7 @@ full = [ "lemmy_db_views/full", "lemmy_db_views_actor/full", "lemmy_db_views_moderator/full", - "lemmy_utils/default", + "lemmy_utils/full", "activitypub_federation", "encoding", "reqwest-middleware", @@ -44,7 +44,7 @@ lemmy_db_views = { workspace = true } lemmy_db_views_moderator = { workspace = true } lemmy_db_views_actor = { workspace = true } lemmy_db_schema = { workspace = true } -lemmy_utils = { workspace = true, features = ["error-type"] } +lemmy_utils = { workspace = true } activitypub_federation = { workspace = true, optional = true } serde = { workspace = true } serde_with = { workspace = true } diff --git a/crates/api_crud/Cargo.toml b/crates/api_crud/Cargo.toml index 2211d84ad..af50c5648 100644 --- a/crates/api_crud/Cargo.toml +++ b/crates/api_crud/Cargo.toml @@ -13,7 +13,7 @@ repository.workspace = true workspace = true [dependencies] -lemmy_utils = { workspace = true, features = ["default"] } +lemmy_utils = { workspace = true, features = ["full"] } lemmy_db_schema = { workspace = true, features = ["full"] } lemmy_db_views = { workspace = true, features = ["full"] } lemmy_db_views_actor = { workspace = true, features = ["full"] } diff --git a/crates/apub/Cargo.toml b/crates/apub/Cargo.toml index 33778a1b0..4c3189a09 100644 --- a/crates/apub/Cargo.toml +++ b/crates/apub/Cargo.toml @@ -18,7 +18,7 @@ doctest = false workspace = true [dependencies] -lemmy_utils = { workspace = true, features = ["default"] } +lemmy_utils = { workspace = true, features = ["full"] } lemmy_db_schema = { workspace = true, features = ["full"] } lemmy_db_views = { workspace = true, features = ["full"] } lemmy_db_views_actor = { workspace = true, features = ["full"] } diff --git a/crates/db_perf/Cargo.toml b/crates/db_perf/Cargo.toml index f1e8faba3..ebadde00b 100644 --- a/crates/db_perf/Cargo.toml +++ b/crates/db_perf/Cargo.toml @@ -19,6 +19,6 @@ diesel = { workspace = true } diesel-async = { workspace = true } lemmy_db_schema = { workspace = true } lemmy_db_views = { workspace = true, features = ["full"] } -lemmy_utils = { workspace = true, features = ["default"] } +lemmy_utils = { workspace = true, features = ["full"] } tokio = { workspace = true } url = { workspace = true } diff --git a/crates/db_schema/Cargo.toml b/crates/db_schema/Cargo.toml index 6d227ad40..d0d66d69f 100644 --- a/crates/db_schema/Cargo.toml +++ b/crates/db_schema/Cargo.toml @@ -18,6 +18,7 @@ workspace = true [features] full = [ + "lemmy_utils/full", "diesel", "diesel-derive-newtype", "diesel-derive-enum", @@ -48,7 +49,7 @@ strum = { workspace = true } strum_macros = { workspace = true } serde_json = { workspace = true, optional = true } activitypub_federation = { workspace = true, optional = true } -lemmy_utils = { workspace = true, optional = true, features = ["default"] } +lemmy_utils = { workspace = true, optional = true } bcrypt = { workspace = true, optional = true } diesel = { workspace = true, features = [ "postgres", diff --git a/crates/db_views/Cargo.toml b/crates/db_views/Cargo.toml index e70030b64..cdd44869c 100644 --- a/crates/db_views/Cargo.toml +++ b/crates/db_views/Cargo.toml @@ -29,7 +29,7 @@ full = [ [dependencies] lemmy_db_schema = { workspace = true } -lemmy_utils = { workspace = true, optional = true, features = ["default"] } +lemmy_utils = { workspace = true, optional = true } diesel = { workspace = true, optional = true } diesel-async = { workspace = true, optional = true } diesel_ltree = { workspace = true, optional = true } diff --git a/crates/routes/Cargo.toml b/crates/routes/Cargo.toml index 324894ab9..1403f92e7 100644 --- a/crates/routes/Cargo.toml +++ b/crates/routes/Cargo.toml @@ -16,7 +16,7 @@ doctest = false workspace = true [dependencies] -lemmy_utils = { workspace = true, features = ["default"] } +lemmy_utils = { workspace = true, features = ["full"] } lemmy_db_views = { workspace = true } lemmy_db_views_actor = { workspace = true } lemmy_db_schema = { workspace = true } diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index 326cbf2e4..2a832bec0 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -16,23 +16,24 @@ doctest = false [[bin]] name = "lemmy_util_bin" path = "src/main.rs" -required-features = ["default"] +required-features = ["full"] [lints] workspace = true [features] -default = [ - "error-type", - "dep:serde_json", - "dep:anyhow", - "dep:tracing-error", +full = [ + "dep:ts-rs", "dep:diesel", - "dep:http", + "dep:rosetta-i18n", "dep:actix-web", "dep:reqwest-middleware", "dep:tracing", "dep:actix-web", + "dep:serde_json", + "dep:anyhow", + "dep:tracing-error", + "dep:http", "dep:deser-hjson", "dep:regex", "dep:urlencoding", @@ -47,27 +48,23 @@ default = [ "dep:html2text", "dep:lettre", "dep:uuid", - "dep:rosetta-i18n", "dep:itertools", "dep:markdown-it", - ] -full = ["default", "dep:ts-rs"] -error-type = ["dep:serde", "dep:strum"] [dependencies] regex = { workspace = true, optional = true } tracing = { workspace = true, optional = true } tracing-error = { workspace = true, optional = true } itertools = { workspace = true, optional = true } -serde = { workspace = true, optional = true } +serde = { workspace = true } serde_json = { workspace = true, optional = true } once_cell = { workspace = true, optional = true } url = { workspace = true, optional = true } actix-web = { workspace = true, optional = true } anyhow = { workspace = true, optional = true } reqwest-middleware = { workspace = true, optional = true } -strum = { workspace = true, optional = true } +strum = { workspace = true } strum_macros = { workspace = true } futures = { workspace = true, optional = true } diesel = { workspace = true, features = ["chrono"], optional = true } diff --git a/crates/utils/src/error.rs b/crates/utils/src/error.rs index 0f68d70da..ad3f4371f 100644 --- a/crates/utils/src/error.rs +++ b/crates/utils/src/error.rs @@ -2,12 +2,10 @@ use cfg_if::cfg_if; use serde::{Deserialize, Serialize}; use std::fmt::Debug; use strum_macros::{Display, EnumIter}; -#[cfg(feature = "ts-rs")] -use ts_rs::TS; #[derive(Display, Debug, Serialize, Deserialize, Clone, PartialEq, Eq, EnumIter, Hash)] -#[cfg_attr(feature = "ts-rs", derive(TS))] -#[cfg_attr(feature = "ts-rs", ts(export))] +#[cfg_attr(feature = "full", derive(ts_rs::TS))] +#[cfg_attr(feature = "full", ts(export))] #[serde(tag = "error", content = "message", rename_all = "snake_case")] #[non_exhaustive] // TODO: order these based on the crate they belong to (utils, federation, db, api) @@ -168,7 +166,7 @@ pub enum LemmyErrorType { } cfg_if! { - if #[cfg(feature = "default")] { + if #[cfg(feature = "full")] { use tracing_error::SpanTrace; use std::fmt; @@ -276,52 +274,52 @@ cfg_if! { self.map_err(|e| e.inner) } } - } -} -#[cfg(test)] -mod tests { - #![allow(clippy::unwrap_used)] - #![allow(clippy::indexing_slicing)] - use super::*; - use actix_web::{body::MessageBody, ResponseError}; - use pretty_assertions::assert_eq; - use std::fs::read_to_string; - use strum::IntoEnumIterator; + #[cfg(test)] + mod tests { + #![allow(clippy::unwrap_used)] + #![allow(clippy::indexing_slicing)] + use super::*; + use actix_web::{body::MessageBody, ResponseError}; + use pretty_assertions::assert_eq; + use std::fs::read_to_string; + use strum::IntoEnumIterator; - #[test] - fn deserializes_no_message() { - let err = LemmyError::from(LemmyErrorType::Banned).error_response(); - let json = String::from_utf8(err.into_body().try_into_bytes().unwrap().to_vec()).unwrap(); - assert_eq!(&json, "{\"error\":\"banned\"}") - } + #[test] + fn deserializes_no_message() { + let err = LemmyError::from(LemmyErrorType::Banned).error_response(); + let json = String::from_utf8(err.into_body().try_into_bytes().unwrap().to_vec()).unwrap(); + assert_eq!(&json, "{\"error\":\"banned\"}") + } - #[test] - fn deserializes_with_message() { - let reg_banned = LemmyErrorType::PersonIsBannedFromSite(String::from("reason")); - let err = LemmyError::from(reg_banned).error_response(); - let json = String::from_utf8(err.into_body().try_into_bytes().unwrap().to_vec()).unwrap(); - assert_eq!( - &json, - "{\"error\":\"person_is_banned_from_site\",\"message\":\"reason\"}" - ) - } + #[test] + fn deserializes_with_message() { + let reg_banned = LemmyErrorType::PersonIsBannedFromSite(String::from("reason")); + let err = LemmyError::from(reg_banned).error_response(); + let json = String::from_utf8(err.into_body().try_into_bytes().unwrap().to_vec()).unwrap(); + assert_eq!( + &json, + "{\"error\":\"person_is_banned_from_site\",\"message\":\"reason\"}" + ) + } - /// Check if errors match translations. Disabled because many are not translated at all. - #[test] - #[ignore] - fn test_translations_match() { - #[derive(Deserialize)] - struct Err { - error: String, + /// Check if errors match translations. Disabled because many are not translated at all. + #[test] + #[ignore] + fn test_translations_match() { + #[derive(Deserialize)] + struct Err { + error: String, + } + + let translations = read_to_string("translations/translations/en.json").unwrap(); + LemmyErrorType::iter().for_each(|e| { + let msg = serde_json::to_string(&e).unwrap(); + let msg: Err = serde_json::from_str(&msg).unwrap(); + let msg = msg.error; + assert!(translations.contains(&format!("\"{msg}\"")), "{msg}"); + }); + } } - - let translations = read_to_string("translations/translations/en.json").unwrap(); - LemmyErrorType::iter().for_each(|e| { - let msg = serde_json::to_string(&e).unwrap(); - let msg: Err = serde_json::from_str(&msg).unwrap(); - let msg = msg.error; - assert!(translations.contains(&format!("\"{msg}\"")), "{msg}"); - }); } } diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 65dbaaa45..c2760d9d9 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -1,28 +1,21 @@ use cfg_if::cfg_if; cfg_if! { - if #[cfg(feature = "default")] { + if #[cfg(feature = "full")] { pub mod apub; pub mod cache_header; pub mod email; - pub mod error; pub mod rate_limit; pub mod request; pub mod response; pub mod settings; pub mod utils; pub mod version; - } else { - mod error; - } -} - -cfg_if! { - if #[cfg(feature = "error-type")] { - pub use error::LemmyErrorType; } } +pub mod error; +pub use error::LemmyErrorType; use std::time::Duration; pub type ConnectionId = usize; @@ -41,7 +34,7 @@ macro_rules! location_info { }; } -#[cfg(feature = "default")] +#[cfg(feature = "full")] /// tokio::spawn, but accepts a future that may fail and also /// * logs errors /// * attaches the spawned task to the tracing span of the caller for better logging diff --git a/crates/utils/src/main.rs b/crates/utils/src/main.rs index c2365f233..ed658b097 100644 --- a/crates/utils/src/main.rs +++ b/crates/utils/src/main.rs @@ -1,16 +1,24 @@ -use doku::json::{AutoComments, CommentsStyle, Formatting, ObjectsStyle}; -use lemmy_utils::settings::structs::Settings; +use cfg_if::cfg_if; + fn main() { - let fmt = Formatting { - auto_comments: AutoComments::none(), - comments_style: CommentsStyle { - separator: "#".to_owned(), - }, - objects_style: ObjectsStyle { - surround_keys_with_quotes: false, - use_comma_as_separator: false, - }, - ..Default::default() - }; - println!("{}", doku::to_json_fmt_val(&fmt, &Settings::default())); + cfg_if! { + if #[cfg(feature = "full")] { + use doku::json::{AutoComments, CommentsStyle, Formatting, ObjectsStyle}; + use lemmy_utils::settings::structs::Settings; + let fmt = Formatting { + auto_comments: AutoComments::none(), + comments_style: CommentsStyle { + separator: "#".to_owned(), + }, + objects_style: ObjectsStyle { + surround_keys_with_quotes: false, + use_comma_as_separator: false, + }, + ..Default::default() + }; + println!("{}", doku::to_json_fmt_val(&fmt, &Settings::default())); + } else { + + } + } } diff --git a/scripts/update_config_defaults.sh b/scripts/update_config_defaults.sh index 0984c247c..de7fa6479 100755 --- a/scripts/update_config_defaults.sh +++ b/scripts/update_config_defaults.sh @@ -3,4 +3,4 @@ set -e dest=${1-config/defaults.hjson} -cargo run --manifest-path crates/utils/Cargo.toml > "$dest" +cargo run --manifest-path crates/utils/Cargo.toml --features full > "$dest"