Merge remote-tracking branch 'origin/main' into content_removal_remote_users

content_removal_remote_users
Dessalines 2024-02-29 09:29:21 -05:00
commit 8cc80703d8
16 changed files with 113 additions and 106 deletions

View File

@ -18,7 +18,7 @@ doctest = false
workspace = true workspace = true
[dependencies] [dependencies]
lemmy_utils = { workspace = true, features = ["default"] } lemmy_utils = { workspace = true }
lemmy_db_schema = { workspace = true, features = ["full"] } lemmy_db_schema = { workspace = true, features = ["full"] }
lemmy_db_views = { workspace = true, features = ["full"] } lemmy_db_views = { workspace = true, features = ["full"] }
lemmy_db_views_moderator = { workspace = true, features = ["full"] } lemmy_db_views_moderator = { workspace = true, features = ["full"] }

View File

@ -1,4 +1,4 @@
use crate::check_totp_2fa_valid; use crate::{check_totp_2fa_valid, local_user::check_email_verified};
use actix_web::{ use actix_web::{
web::{Data, Json}, web::{Data, Json},
HttpRequest, HttpRequest,
@ -43,15 +43,7 @@ pub async fn login(
Err(LemmyErrorType::IncorrectLogin)? Err(LemmyErrorType::IncorrectLogin)?
} }
check_user_valid(&local_user_view.person)?; check_user_valid(&local_user_view.person)?;
check_email_verified(&local_user_view, &site_view)?;
// 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_registration_application(&local_user_view, &site_view.local_site, &mut context.pool()) check_registration_application(&local_user_view, &site_view.local_site, &mut context.pool())
.await?; .await?;

View File

@ -1,3 +1,6 @@
use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
pub mod add_admin; pub mod add_admin;
pub mod ban_person; pub mod ban_person;
pub mod block; pub mod block;
@ -16,3 +19,15 @@ pub mod save_settings;
pub mod update_totp; pub mod update_totp;
pub mod validate_auth; pub mod validate_auth;
pub mod verify_email; 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(())
}

View File

@ -1,3 +1,4 @@
use crate::local_user::check_email_verified;
use actix_web::web::{Data, Json}; use actix_web::web::{Data, Json};
use lemmy_api_common::{ use lemmy_api_common::{
context::LemmyContext, context::LemmyContext,
@ -6,7 +7,7 @@ use lemmy_api_common::{
SuccessResponse, SuccessResponse,
}; };
use lemmy_db_schema::source::password_reset_request::PasswordResetRequest; 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}; use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
#[tracing::instrument(skip(context))] #[tracing::instrument(skip(context))]
@ -29,6 +30,8 @@ pub async fn reset_password(
if recent_resets_count >= 3 { if recent_resets_count >= 3 {
Err(LemmyErrorType::PasswordResetLimitReached)? 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. // Email the pure token to the user.
send_password_reset_email(&local_user_view, &mut context.pool(), context.settings()).await?; send_password_reset_email(&local_user_view, &mut context.pool(), context.settings()).await?;

View File

@ -23,7 +23,7 @@ full = [
"lemmy_db_views/full", "lemmy_db_views/full",
"lemmy_db_views_actor/full", "lemmy_db_views_actor/full",
"lemmy_db_views_moderator/full", "lemmy_db_views_moderator/full",
"lemmy_utils/default", "lemmy_utils/full",
"activitypub_federation", "activitypub_federation",
"encoding", "encoding",
"reqwest-middleware", "reqwest-middleware",
@ -44,7 +44,7 @@ lemmy_db_views = { workspace = true }
lemmy_db_views_moderator = { workspace = true } lemmy_db_views_moderator = { workspace = true }
lemmy_db_views_actor = { workspace = true } lemmy_db_views_actor = { workspace = true }
lemmy_db_schema = { workspace = true } lemmy_db_schema = { workspace = true }
lemmy_utils = { workspace = true, features = ["error-type"] } lemmy_utils = { workspace = true }
activitypub_federation = { workspace = true, optional = true } activitypub_federation = { workspace = true, optional = true }
serde = { workspace = true } serde = { workspace = true }
serde_with = { workspace = true } serde_with = { workspace = true }

View File

@ -13,7 +13,7 @@ repository.workspace = true
workspace = true workspace = true
[dependencies] [dependencies]
lemmy_utils = { workspace = true, features = ["default"] } lemmy_utils = { workspace = true, features = ["full"] }
lemmy_db_schema = { workspace = true, features = ["full"] } lemmy_db_schema = { workspace = true, features = ["full"] }
lemmy_db_views = { workspace = true, features = ["full"] } lemmy_db_views = { workspace = true, features = ["full"] }
lemmy_db_views_actor = { workspace = true, features = ["full"] } lemmy_db_views_actor = { workspace = true, features = ["full"] }

View File

@ -18,7 +18,7 @@ doctest = false
workspace = true workspace = true
[dependencies] [dependencies]
lemmy_utils = { workspace = true, features = ["default"] } lemmy_utils = { workspace = true, features = ["full"] }
lemmy_db_schema = { workspace = true, features = ["full"] } lemmy_db_schema = { workspace = true, features = ["full"] }
lemmy_db_views = { workspace = true, features = ["full"] } lemmy_db_views = { workspace = true, features = ["full"] }
lemmy_db_views_actor = { workspace = true, features = ["full"] } lemmy_db_views_actor = { workspace = true, features = ["full"] }

View File

@ -19,6 +19,6 @@ diesel = { workspace = true }
diesel-async = { workspace = true } diesel-async = { workspace = true }
lemmy_db_schema = { workspace = true } lemmy_db_schema = { workspace = true }
lemmy_db_views = { workspace = true, features = ["full"] } lemmy_db_views = { workspace = true, features = ["full"] }
lemmy_utils = { workspace = true, features = ["default"] } lemmy_utils = { workspace = true, features = ["full"] }
tokio = { workspace = true } tokio = { workspace = true }
url = { workspace = true } url = { workspace = true }

View File

@ -18,6 +18,7 @@ workspace = true
[features] [features]
full = [ full = [
"lemmy_utils/full",
"diesel", "diesel",
"diesel-derive-newtype", "diesel-derive-newtype",
"diesel-derive-enum", "diesel-derive-enum",
@ -48,7 +49,7 @@ strum = { workspace = true }
strum_macros = { workspace = true } strum_macros = { workspace = true }
serde_json = { workspace = true, optional = true } serde_json = { workspace = true, optional = true }
activitypub_federation = { 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 } bcrypt = { workspace = true, optional = true }
diesel = { workspace = true, features = [ diesel = { workspace = true, features = [
"postgres", "postgres",

View File

@ -29,7 +29,7 @@ full = [
[dependencies] [dependencies]
lemmy_db_schema = { workspace = true } 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 = { workspace = true, optional = true }
diesel-async = { workspace = true, optional = true } diesel-async = { workspace = true, optional = true }
diesel_ltree = { workspace = true, optional = true } diesel_ltree = { workspace = true, optional = true }

View File

@ -16,7 +16,7 @@ doctest = false
workspace = true workspace = true
[dependencies] [dependencies]
lemmy_utils = { workspace = true, features = ["default"] } lemmy_utils = { workspace = true, features = ["full"] }
lemmy_db_views = { workspace = true } lemmy_db_views = { workspace = true }
lemmy_db_views_actor = { workspace = true } lemmy_db_views_actor = { workspace = true }
lemmy_db_schema = { workspace = true } lemmy_db_schema = { workspace = true }

View File

@ -16,23 +16,24 @@ doctest = false
[[bin]] [[bin]]
name = "lemmy_util_bin" name = "lemmy_util_bin"
path = "src/main.rs" path = "src/main.rs"
required-features = ["default"] required-features = ["full"]
[lints] [lints]
workspace = true workspace = true
[features] [features]
default = [ full = [
"error-type", "dep:ts-rs",
"dep:serde_json",
"dep:anyhow",
"dep:tracing-error",
"dep:diesel", "dep:diesel",
"dep:http", "dep:rosetta-i18n",
"dep:actix-web", "dep:actix-web",
"dep:reqwest-middleware", "dep:reqwest-middleware",
"dep:tracing", "dep:tracing",
"dep:actix-web", "dep:actix-web",
"dep:serde_json",
"dep:anyhow",
"dep:tracing-error",
"dep:http",
"dep:deser-hjson", "dep:deser-hjson",
"dep:regex", "dep:regex",
"dep:urlencoding", "dep:urlencoding",
@ -47,27 +48,23 @@ default = [
"dep:html2text", "dep:html2text",
"dep:lettre", "dep:lettre",
"dep:uuid", "dep:uuid",
"dep:rosetta-i18n",
"dep:itertools", "dep:itertools",
"dep:markdown-it", "dep:markdown-it",
] ]
full = ["default", "dep:ts-rs"]
error-type = ["dep:serde", "dep:strum"]
[dependencies] [dependencies]
regex = { workspace = true, optional = true } regex = { workspace = true, optional = true }
tracing = { workspace = true, optional = true } tracing = { workspace = true, optional = true }
tracing-error = { workspace = true, optional = true } tracing-error = { workspace = true, optional = true }
itertools = { workspace = true, optional = true } itertools = { workspace = true, optional = true }
serde = { workspace = true, optional = true } serde = { workspace = true }
serde_json = { workspace = true, optional = true } serde_json = { workspace = true, optional = true }
once_cell = { workspace = true, optional = true } once_cell = { workspace = true, optional = true }
url = { workspace = true, optional = true } url = { workspace = true, optional = true }
actix-web = { workspace = true, optional = true } actix-web = { workspace = true, optional = true }
anyhow = { workspace = true, optional = true } anyhow = { workspace = true, optional = true }
reqwest-middleware = { workspace = true, optional = true } reqwest-middleware = { workspace = true, optional = true }
strum = { workspace = true, optional = true } strum = { workspace = true }
strum_macros = { workspace = true } strum_macros = { workspace = true }
futures = { workspace = true, optional = true } futures = { workspace = true, optional = true }
diesel = { workspace = true, features = ["chrono"], optional = true } diesel = { workspace = true, features = ["chrono"], optional = true }

View File

@ -2,12 +2,10 @@ use cfg_if::cfg_if;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
use strum_macros::{Display, EnumIter}; use strum_macros::{Display, EnumIter};
#[cfg(feature = "ts-rs")]
use ts_rs::TS;
#[derive(Display, Debug, Serialize, Deserialize, Clone, PartialEq, Eq, EnumIter, Hash)] #[derive(Display, Debug, Serialize, Deserialize, Clone, PartialEq, Eq, EnumIter, Hash)]
#[cfg_attr(feature = "ts-rs", derive(TS))] #[cfg_attr(feature = "full", derive(ts_rs::TS))]
#[cfg_attr(feature = "ts-rs", ts(export))] #[cfg_attr(feature = "full", ts(export))]
#[serde(tag = "error", content = "message", rename_all = "snake_case")] #[serde(tag = "error", content = "message", rename_all = "snake_case")]
#[non_exhaustive] #[non_exhaustive]
// TODO: order these based on the crate they belong to (utils, federation, db, api) // TODO: order these based on the crate they belong to (utils, federation, db, api)
@ -168,7 +166,7 @@ pub enum LemmyErrorType {
} }
cfg_if! { cfg_if! {
if #[cfg(feature = "default")] { if #[cfg(feature = "full")] {
use tracing_error::SpanTrace; use tracing_error::SpanTrace;
use std::fmt; use std::fmt;
@ -276,52 +274,52 @@ cfg_if! {
self.map_err(|e| e.inner) self.map_err(|e| e.inner)
} }
} }
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(clippy::unwrap_used)] #![allow(clippy::unwrap_used)]
#![allow(clippy::indexing_slicing)] #![allow(clippy::indexing_slicing)]
use super::*; use super::*;
use actix_web::{body::MessageBody, ResponseError}; use actix_web::{body::MessageBody, ResponseError};
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use std::fs::read_to_string; use std::fs::read_to_string;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
#[test] #[test]
fn deserializes_no_message() { fn deserializes_no_message() {
let err = LemmyError::from(LemmyErrorType::Banned).error_response(); let err = LemmyError::from(LemmyErrorType::Banned).error_response();
let json = String::from_utf8(err.into_body().try_into_bytes().unwrap().to_vec()).unwrap(); let json = String::from_utf8(err.into_body().try_into_bytes().unwrap().to_vec()).unwrap();
assert_eq!(&json, "{\"error\":\"banned\"}") assert_eq!(&json, "{\"error\":\"banned\"}")
} }
#[test] #[test]
fn deserializes_with_message() { fn deserializes_with_message() {
let reg_banned = LemmyErrorType::PersonIsBannedFromSite(String::from("reason")); let reg_banned = LemmyErrorType::PersonIsBannedFromSite(String::from("reason"));
let err = LemmyError::from(reg_banned).error_response(); let err = LemmyError::from(reg_banned).error_response();
let json = String::from_utf8(err.into_body().try_into_bytes().unwrap().to_vec()).unwrap(); let json = String::from_utf8(err.into_body().try_into_bytes().unwrap().to_vec()).unwrap();
assert_eq!( assert_eq!(
&json, &json,
"{\"error\":\"person_is_banned_from_site\",\"message\":\"reason\"}" "{\"error\":\"person_is_banned_from_site\",\"message\":\"reason\"}"
) )
} }
/// Check if errors match translations. Disabled because many are not translated at all. /// Check if errors match translations. Disabled because many are not translated at all.
#[test] #[test]
#[ignore] #[ignore]
fn test_translations_match() { fn test_translations_match() {
#[derive(Deserialize)] #[derive(Deserialize)]
struct Err { struct Err {
error: String, 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}");
});
} }
} }

View File

@ -1,28 +1,21 @@
use cfg_if::cfg_if; use cfg_if::cfg_if;
cfg_if! { cfg_if! {
if #[cfg(feature = "default")] { if #[cfg(feature = "full")] {
pub mod apub; pub mod apub;
pub mod cache_header; pub mod cache_header;
pub mod email; pub mod email;
pub mod error;
pub mod rate_limit; pub mod rate_limit;
pub mod request; pub mod request;
pub mod response; pub mod response;
pub mod settings; pub mod settings;
pub mod utils; pub mod utils;
pub mod version; 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; use std::time::Duration;
pub type ConnectionId = usize; 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 /// tokio::spawn, but accepts a future that may fail and also
/// * logs errors /// * logs errors
/// * attaches the spawned task to the tracing span of the caller for better logging /// * attaches the spawned task to the tracing span of the caller for better logging

View File

@ -1,16 +1,24 @@
use doku::json::{AutoComments, CommentsStyle, Formatting, ObjectsStyle}; use cfg_if::cfg_if;
use lemmy_utils::settings::structs::Settings;
fn main() { fn main() {
let fmt = Formatting { cfg_if! {
auto_comments: AutoComments::none(), if #[cfg(feature = "full")] {
comments_style: CommentsStyle { use doku::json::{AutoComments, CommentsStyle, Formatting, ObjectsStyle};
separator: "#".to_owned(), use lemmy_utils::settings::structs::Settings;
}, let fmt = Formatting {
objects_style: ObjectsStyle { auto_comments: AutoComments::none(),
surround_keys_with_quotes: false, comments_style: CommentsStyle {
use_comma_as_separator: false, separator: "#".to_owned(),
}, },
..Default::default() objects_style: ObjectsStyle {
}; surround_keys_with_quotes: false,
println!("{}", doku::to_json_fmt_val(&fmt, &Settings::default())); use_comma_as_separator: false,
},
..Default::default()
};
println!("{}", doku::to_json_fmt_val(&fmt, &Settings::default()));
} else {
}
}
} }

View File

@ -3,4 +3,4 @@ set -e
dest=${1-config/defaults.hjson} 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"