Remove update and read site config. Fixes #2306 (#2329)

* Remove update and read site config. Fixes #2306

* Removing lazy_static, removing Settings::get()
handle-better-deleted-actors
Dessalines 2022-06-22 16:24:54 -04:00 committed by GitHub
parent 8af913f583
commit a745fa6f43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 84 additions and 200 deletions

View File

@ -98,12 +98,6 @@ pub async fn match_websocket_operation(
// Site ops // Site ops
UserOperation::GetModlog => do_websocket_operation::<GetModlog>(context, id, op, data).await, UserOperation::GetModlog => do_websocket_operation::<GetModlog>(context, id, op, data).await,
UserOperation::GetSiteConfig => {
do_websocket_operation::<GetSiteConfig>(context, id, op, data).await
}
UserOperation::SaveSiteConfig => {
do_websocket_operation::<SaveSiteConfig>(context, id, op, data).await
}
UserOperation::PurgePerson => { UserOperation::PurgePerson => {
do_websocket_operation::<PurgePerson>(context, id, op, data).await do_websocket_operation::<PurgePerson>(context, id, op, data).await
} }
@ -226,13 +220,13 @@ mod tests {
traits::Crud, traits::Crud,
utils::establish_unpooled_connection, utils::establish_unpooled_connection,
}; };
use lemmy_utils::{claims::Claims, settings::structs::Settings}; use lemmy_utils::{claims::Claims, settings::SETTINGS};
#[test] #[test]
fn test_should_not_validate_user_token_after_password_change() { fn test_should_not_validate_user_token_after_password_change() {
let conn = establish_unpooled_connection(); let conn = establish_unpooled_connection();
let secret = Secret::init(&conn).unwrap(); let secret = Secret::init(&conn).unwrap();
let settings = Settings::init().unwrap(); let settings = &SETTINGS.to_owned();
let new_person = PersonForm { let new_person = PersonForm {
name: "Gerry9812".into(), name: "Gerry9812".into(),

View File

@ -52,7 +52,7 @@ impl Perform for BanPerson {
remove_user_data( remove_user_data(
person.id, person.id,
context.pool(), context.pool(),
&context.settings(), context.settings(),
context.client(), context.client(),
) )
.await?; .await?;

View File

@ -17,7 +17,7 @@ impl Perform for GetCaptcha {
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>, _websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> { ) -> Result<Self::Response, LemmyError> {
let captcha_settings = context.settings().captcha; let captcha_settings = &context.settings().captcha;
if !captcha_settings.enabled { if !captcha_settings.enabled {
return Ok(GetCaptchaResponse { ok: None }); return Ok(GetCaptchaResponse { ok: None });

View File

@ -29,7 +29,7 @@ impl Perform for PasswordReset {
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_that_username_or_email"))?; .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_that_username_or_email"))?;
// Email the pure token to the user. // Email the pure token to the user.
send_password_reset_email(&local_user_view, context.pool(), &context.settings()).await?; send_password_reset_email(&local_user_view, context.pool(), context.settings()).await?;
Ok(PasswordResetResponse {}) Ok(PasswordResetResponse {})
} }
} }

View File

@ -48,7 +48,7 @@ impl Perform for SaveUserSettings {
let previous_email = local_user_view.local_user.email.clone().unwrap_or_default(); let previous_email = local_user_view.local_user.email.clone().unwrap_or_default();
// Only send the verification email if there was an email change // Only send the verification email if there was an email change
if previous_email.ne(email) { if previous_email.ne(email) {
send_verification_email(&local_user_view, email, context.pool(), &context.settings()) send_verification_email(&local_user_view, email, context.pool(), context.settings())
.await?; .await?;
} }
} }

View File

@ -49,7 +49,7 @@ impl Perform for VerifyEmail {
}) })
.await??; .await??;
send_email_verification_success(&local_user_view, &context.settings())?; send_email_verification_success(&local_user_view, context.settings())?;
blocking(context.pool(), move |conn| { blocking(context.pool(), move |conn| {
EmailVerification::delete_old_tokens_for_local_user(conn, local_user_id) EmailVerification::delete_old_tokens_for_local_user(conn, local_user_id)

View File

@ -1,2 +0,0 @@
mod read;
mod update;

View File

@ -1,31 +0,0 @@
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
site::{GetSiteConfig, GetSiteConfigResponse},
utils::{get_local_user_view_from_jwt, is_admin},
};
use lemmy_utils::{error::LemmyError, settings::structs::Settings, ConnectionId};
use lemmy_websocket::LemmyContext;
#[async_trait::async_trait(?Send)]
impl Perform for GetSiteConfig {
type Response = GetSiteConfigResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<GetSiteConfigResponse, LemmyError> {
let data: &GetSiteConfig = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// Only let admins read this
is_admin(&local_user_view)?;
let config_hjson = Settings::read_config_file()?;
Ok(GetSiteConfigResponse { config_hjson })
}
}

View File

@ -1,33 +0,0 @@
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
site::{GetSiteConfigResponse, SaveSiteConfig},
utils::{get_local_user_view_from_jwt, is_admin},
};
use lemmy_utils::{error::LemmyError, settings::structs::Settings, ConnectionId};
use lemmy_websocket::LemmyContext;
#[async_trait::async_trait(?Send)]
impl Perform for SaveSiteConfig {
type Response = GetSiteConfigResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform(
&self,
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<GetSiteConfigResponse, LemmyError> {
let data: &SaveSiteConfig = self;
let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// Only let admins read this
is_admin(&local_user_view)?;
// Make sure docker doesn't have :ro at the end of the volume, so its not a read-only filesystem
let config_hjson = Settings::save_config_file(&data.config_hjson)
.map_err(|e| e.with_message("couldnt_update_site"))?;
Ok(GetSiteConfigResponse { config_hjson })
}
}

View File

@ -57,8 +57,7 @@ impl Perform for LeaveAdmin {
let site_view = blocking(context.pool(), SiteView::read_local).await??; let site_view = blocking(context.pool(), SiteView::read_local).await??;
let admins = blocking(context.pool(), PersonViewSafe::admins).await??; let admins = blocking(context.pool(), PersonViewSafe::admins).await??;
let federated_instances = let federated_instances = build_federated_instances(context.pool(), context.settings()).await?;
build_federated_instances(context.pool(), &context.settings()).await?;
Ok(GetSiteResponse { Ok(GetSiteResponse {
site_view: Some(site_view), site_view: Some(site_view),

View File

@ -1,4 +1,3 @@
mod config;
mod leave_admin; mod leave_admin;
mod mod_log; mod mod_log;
mod purge; mod purge;

View File

@ -41,13 +41,13 @@ impl Perform for PurgeCommunity {
.await??; .await??;
if let Some(banner) = community.banner { if let Some(banner) = community.banner {
purge_image_from_pictrs(context.client(), &context.settings(), &banner) purge_image_from_pictrs(context.client(), context.settings(), &banner)
.await .await
.ok(); .ok();
} }
if let Some(icon) = community.icon { if let Some(icon) = community.icon {
purge_image_from_pictrs(context.client(), &context.settings(), &icon) purge_image_from_pictrs(context.client(), context.settings(), &icon)
.await .await
.ok(); .ok();
} }
@ -55,7 +55,7 @@ impl Perform for PurgeCommunity {
purge_image_posts_for_community( purge_image_posts_for_community(
community_id, community_id,
context.pool(), context.pool(),
&context.settings(), context.settings(),
context.client(), context.client(),
) )
.await?; .await?;

View File

@ -37,13 +37,13 @@ impl Perform for PurgePerson {
let person = blocking(context.pool(), move |conn| Person::read(conn, person_id)).await??; let person = blocking(context.pool(), move |conn| Person::read(conn, person_id)).await??;
if let Some(banner) = person.banner { if let Some(banner) = person.banner {
purge_image_from_pictrs(context.client(), &context.settings(), &banner) purge_image_from_pictrs(context.client(), context.settings(), &banner)
.await .await
.ok(); .ok();
} }
if let Some(avatar) = person.avatar { if let Some(avatar) = person.avatar {
purge_image_from_pictrs(context.client(), &context.settings(), &avatar) purge_image_from_pictrs(context.client(), context.settings(), &avatar)
.await .await
.ok(); .ok();
} }
@ -51,7 +51,7 @@ impl Perform for PurgePerson {
purge_image_posts_for_person( purge_image_posts_for_person(
person_id, person_id,
context.pool(), context.pool(),
&context.settings(), context.settings(),
context.client(), context.client(),
) )
.await?; .await?;

View File

@ -39,13 +39,13 @@ impl Perform for PurgePost {
// Purge image // Purge image
if let Some(url) = post.url { if let Some(url) = post.url {
purge_image_from_pictrs(context.client(), &context.settings(), &url) purge_image_from_pictrs(context.client(), context.settings(), &url)
.await .await
.ok(); .ok();
} }
// Purge thumbnail // Purge thumbnail
if let Some(thumbnail_url) = post.thumbnail_url { if let Some(thumbnail_url) = post.thumbnail_url {
purge_image_from_pictrs(context.client(), &context.settings(), &thumbnail_url) purge_image_from_pictrs(context.client(), context.settings(), &thumbnail_url)
.await .await
.ok(); .ok();
} }

View File

@ -66,7 +66,7 @@ impl Perform for ApproveRegistrationApplication {
.await??; .await??;
if approved_local_user_view.local_user.email.is_some() { if approved_local_user_view.local_user.email.is_some() {
send_application_approved_email(&approved_local_user_view, &context.settings())?; send_application_approved_email(&approved_local_user_view, context.settings())?;
} }
} }

View File

@ -262,15 +262,15 @@ pub fn build_user_agent(settings: &Settings) -> String {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::request::{build_user_agent, fetch_site_metadata, SiteMetadata}; use crate::request::{build_user_agent, fetch_site_metadata, SiteMetadata};
use lemmy_utils::settings::structs::Settings; use lemmy_utils::settings::SETTINGS;
use url::Url; use url::Url;
// These helped with testing // These helped with testing
#[actix_rt::test] #[actix_rt::test]
async fn test_site_metadata() { async fn test_site_metadata() {
let settings = Settings::init().unwrap(); let settings = &SETTINGS.to_owned();
let client = reqwest::Client::builder() let client = reqwest::Client::builder()
.user_agent(build_user_agent(&settings)) .user_agent(build_user_agent(settings))
.build() .build()
.unwrap() .unwrap()
.into(); .into();

View File

@ -179,22 +179,6 @@ pub struct LeaveAdmin {
pub auth: Sensitive<String>, pub auth: Sensitive<String>,
} }
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GetSiteConfig {
pub auth: Sensitive<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GetSiteConfigResponse {
pub config_hjson: String,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SaveSiteConfig {
pub config_hjson: String,
pub auth: Sensitive<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct FederatedInstances { pub struct FederatedInstances {
pub linked: Vec<String>, pub linked: Vec<String>,

View File

@ -87,7 +87,7 @@ impl PerformCrud for CreatePost {
// Fetch post links and pictrs cached image // Fetch post links and pictrs cached image
let data_url = data.url.as_ref(); let data_url = data.url.as_ref();
let (metadata_res, thumbnail_url) = let (metadata_res, thumbnail_url) =
fetch_site_data(context.client(), &context.settings(), data_url).await; fetch_site_data(context.client(), context.settings(), data_url).await;
let (embed_title, embed_description, embed_video_url) = metadata_res let (embed_title, embed_description, embed_video_url) = metadata_res
.map(|u| (u.title, u.description, u.embed_video_url)) .map(|u| (u.title, u.description, u.embed_video_url))
.unwrap_or_default(); .unwrap_or_default();

View File

@ -70,7 +70,7 @@ impl PerformCrud for EditPost {
// Fetch post links and Pictrs cached image // Fetch post links and Pictrs cached image
let data_url = data.url.as_ref(); let data_url = data.url.as_ref();
let (metadata_res, thumbnail_url) = let (metadata_res, thumbnail_url) =
fetch_site_data(context.client(), &context.settings(), data_url).await; fetch_site_data(context.client(), context.settings(), data_url).await;
let (embed_title, embed_description, embed_video_url) = metadata_res let (embed_title, embed_description, embed_video_url) = metadata_res
.map(|u| (u.title, u.description, u.embed_video_url)) .map(|u| (u.title, u.description, u.embed_video_url))
.unwrap_or_default(); .unwrap_or_default();

View File

@ -119,7 +119,7 @@ impl PerformCrud for CreatePrivateMessage {
&content_slurs_removed, &content_slurs_removed,
&local_recipient.person.name, &local_recipient.person.name,
), ),
&context.settings(), context.settings(),
); );
} }

View File

@ -15,7 +15,6 @@ use lemmy_db_schema::{
use lemmy_db_views::structs::SiteView; use lemmy_db_views::structs::SiteView;
use lemmy_utils::{ use lemmy_utils::{
error::LemmyError, error::LemmyError,
settings::structs::Settings,
utils::{check_slurs, check_slurs_opt}, utils::{check_slurs, check_slurs_opt},
ConnectionId, ConnectionId,
}; };
@ -57,7 +56,7 @@ impl PerformCrud for CreateSite {
site_description_length_check(desc)?; site_description_length_check(desc)?;
} }
let actor_id: DbUrl = Url::parse(&Settings::get().get_protocol_and_hostname())?.into(); let actor_id: DbUrl = Url::parse(&context.settings().get_protocol_and_hostname())?.into();
let inbox_url = Some(generate_site_inbox_url(&actor_id)?); let inbox_url = Some(generate_site_inbox_url(&actor_id)?);
let keypair = generate_actor_keypair()?; let keypair = generate_actor_keypair()?;
let site_form = SiteForm { let site_form = SiteForm {

View File

@ -120,8 +120,7 @@ impl PerformCrud for GetSite {
None None
}; };
let federated_instances = let federated_instances = build_federated_instances(context.pool(), context.settings()).await?;
build_federated_instances(context.pool(), &context.settings()).await?;
Ok(GetSiteResponse { Ok(GetSiteResponse {
site_view, site_view,

View File

@ -211,13 +211,8 @@ impl PerformCrud for Register {
.email .email
.clone() .clone()
.expect("email was provided"); .expect("email was provided");
send_verification_email( send_verification_email(&local_user_view, &email, context.pool(), context.settings())
&local_user_view, .await?;
&email,
context.pool(),
&context.settings(),
)
.await?;
login_response.verify_email_sent = true; login_response.verify_email_sent = true;
} }

View File

@ -36,7 +36,7 @@ impl PerformCrud for DeleteAccount {
delete_user_account( delete_user_account(
local_user_view.person.id, local_user_view.person.id,
context.pool(), context.pool(),
&context.settings(), context.settings(),
context.client(), context.client(),
) )
.await?; .await?;

View File

@ -37,7 +37,7 @@ use lemmy_db_schema::{
}, },
traits::{Bannable, Crud, Followable}, traits::{Bannable, Crud, Followable},
}; };
use lemmy_utils::{error::LemmyError, settings::structs::Settings, utils::convert_datetime}; use lemmy_utils::{error::LemmyError, utils::convert_datetime};
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use url::Url; use url::Url;
@ -131,7 +131,7 @@ impl ActivityHandler for BlockUser {
{ {
SiteOrCommunity::Site(site) => { SiteOrCommunity::Site(site) => {
let domain = self.object.inner().domain().expect("url needs domain"); let domain = self.object.inner().domain().expect("url needs domain");
if Settings::get().hostname == domain { if context.settings().hostname == domain {
return Err( return Err(
anyhow!("Site bans from remote instance can't affect user's home instance").into(), anyhow!("Site bans from remote instance can't affect user's home instance").into(),
); );
@ -184,7 +184,7 @@ impl ActivityHandler for BlockUser {
remove_user_data( remove_user_data(
blocked_person.id, blocked_person.id,
context.pool(), context.pool(),
&context.settings(), context.settings(),
context.client(), context.client(),
) )
.await?; .await?;

View File

@ -54,7 +54,7 @@ impl ActivityHandler for DeleteUser {
delete_user_account( delete_user_account(
actor.id, actor.id,
context.pool(), context.pool(),
&context.settings(), context.settings(),
context.client(), context.client(),
) )
.await?; .await?;

View File

@ -3,7 +3,7 @@ use activitypub_federation::traits::ApubObject;
use itertools::Itertools; use itertools::Itertools;
use lemmy_api_common::utils::blocking; use lemmy_api_common::utils::blocking;
use lemmy_db_schema::traits::ApubActor; use lemmy_db_schema::traits::ApubActor;
use lemmy_utils::{error::LemmyError, settings::structs::Settings}; use lemmy_utils::error::LemmyError;
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
pub mod post_or_comment; pub mod post_or_comment;
@ -35,7 +35,7 @@ where
.collect_tuple() .collect_tuple()
.expect("invalid query"); .expect("invalid query");
let name = name.to_string(); let name = name.to_string();
let domain = format!("{}://{}", Settings::get().get_protocol_string(), domain); let domain = format!("{}://{}", context.settings().get_protocol_string(), domain);
let actor = blocking(context.pool(), move |conn| { let actor = blocking(context.pool(), move |conn| {
DbActor::read_from_name_and_domain(conn, &name, &domain) DbActor::read_from_name_and_domain(conn, &name, &domain)
}) })

View File

@ -8,7 +8,7 @@ use activitypub_federation::{deser::context::WithContext, traits::ApubObject};
use actix_web::{web, HttpRequest, HttpResponse}; use actix_web::{web, HttpRequest, HttpResponse};
use lemmy_api_common::utils::blocking; use lemmy_api_common::utils::blocking;
use lemmy_db_schema::source::site::Site; use lemmy_db_schema::source::site::Site;
use lemmy_utils::{error::LemmyError, settings::structs::Settings}; use lemmy_utils::error::LemmyError;
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use url::Url; use url::Url;
@ -24,10 +24,12 @@ pub(crate) async fn get_apub_site_http(
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) async fn get_apub_site_outbox() -> Result<HttpResponse, LemmyError> { pub(crate) async fn get_apub_site_outbox(
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, LemmyError> {
let outbox_id = format!( let outbox_id = format!(
"{}/site_outbox", "{}/site_outbox",
Settings::get().get_protocol_and_hostname() context.settings().get_protocol_and_hostname()
); );
let outbox = EmptyOutbox::new(Url::parse(&outbox_id)?).await?; let outbox = EmptyOutbox::new(Url::parse(&outbox_id)?).await?;
Ok(create_apub_response(&outbox)) Ok(create_apub_response(&outbox))

View File

@ -8,7 +8,11 @@ use activitypub_federation::{
use anyhow::Context; use anyhow::Context;
use lemmy_api_common::utils::blocking; use lemmy_api_common::utils::blocking;
use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, utils::DbPool}; use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, utils::DbPool};
use lemmy_utils::{error::LemmyError, location_info, settings::structs::Settings}; use lemmy_utils::{
error::LemmyError,
location_info,
settings::{structs::Settings, SETTINGS},
};
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use once_cell::sync::{Lazy, OnceCell}; use once_cell::sync::{Lazy, OnceCell};
use url::{ParseError, Url}; use url::{ParseError, Url};
@ -34,11 +38,13 @@ fn local_instance(context: &LemmyContext) -> &'static LocalInstance {
.http_fetch_retry_limit(context.settings().federation.http_fetch_retry_limit) .http_fetch_retry_limit(context.settings().federation.http_fetch_retry_limit)
.worker_count(context.settings().federation.worker_count) .worker_count(context.settings().federation.worker_count)
.debug(context.settings().federation.debug) .debug(context.settings().federation.debug)
.verify_url_function(|url| check_apub_id_valid(url, &Settings::get())) // TODO No idea why, but you can't pass context.settings() to the verify_url_function closure
// without the value getting captured.
.verify_url_function(|url| check_apub_id_valid(url, &SETTINGS.to_owned()))
.build() .build()
.expect("configure federation"); .expect("configure federation");
LocalInstance::new( LocalInstance::new(
context.settings().hostname, context.settings().hostname.to_owned(),
context.client().clone(), context.client().clone(),
settings, settings,
) )

View File

@ -142,8 +142,8 @@ impl ApubObject for ApubComment {
Community::read(conn, community_id) Community::read(conn, community_id)
}) })
.await??; .await??;
check_apub_id_valid_with_strictness(note.id.inner(), community.local, &context.settings())?; check_apub_id_valid_with_strictness(note.id.inner(), community.local, context.settings())?;
verify_is_remote_object(note.id.inner())?; verify_is_remote_object(note.id.inner(), context.settings())?;
verify_person_in_community( verify_person_in_community(
&note.attributed_to, &note.attributed_to,
&community.into(), &community.into(),

View File

@ -206,9 +206,7 @@ impl ApubCommunity {
.unique() .unique()
.filter(|inbox: &Url| inbox.host_str() != Some(&context.settings().hostname)) .filter(|inbox: &Url| inbox.host_str() != Some(&context.settings().hostname))
// Don't send to blocked instances // Don't send to blocked instances
.filter(|inbox| { .filter(|inbox| check_apub_id_valid_with_strictness(inbox, false, context.settings()).is_ok())
check_apub_id_valid_with_strictness(inbox, false, &context.settings()).is_ok()
})
.collect(); .collect();
Ok(inboxes) Ok(inboxes)

View File

@ -103,7 +103,7 @@ impl ApubObject for ApubSite {
data: &Self::DataType, data: &Self::DataType,
_request_counter: &mut i32, _request_counter: &mut i32,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
check_apub_id_valid_with_strictness(apub.id.inner(), true, &data.settings())?; check_apub_id_valid_with_strictness(apub.id.inner(), true, data.settings())?;
verify_domains_match(expected_domain, apub.id.inner())?; verify_domains_match(expected_domain, apub.id.inner())?;
let slur_regex = &data.settings().slur_regex(); let slur_regex = &data.settings().slur_regex();

View File

@ -43,8 +43,8 @@ pub(crate) fn read_from_string_or_source_opt(
/// wrapped in Announce. If we simply receive this like any other federated object, overwrite the /// wrapped in Announce. If we simply receive this like any other federated object, overwrite the
/// existing, local Post. In particular, it will set the field local = false, so that the object /// existing, local Post. In particular, it will set the field local = false, so that the object
/// can't be fetched from the Activitypub HTTP endpoint anymore (which only serves local objects). /// can't be fetched from the Activitypub HTTP endpoint anymore (which only serves local objects).
pub(crate) fn verify_is_remote_object(id: &Url) -> Result<(), LemmyError> { pub(crate) fn verify_is_remote_object(id: &Url, settings: &Settings) -> Result<(), LemmyError> {
let local_domain = Settings::get().get_hostname_without_port()?; let local_domain = settings.get_hostname_without_port()?;
if id.domain() == Some(&local_domain) { if id.domain() == Some(&local_domain) {
Err(anyhow!("cant accept local object from remote instance").into()) Err(anyhow!("cant accept local object from remote instance").into())
} else { } else {
@ -68,7 +68,7 @@ pub(crate) mod tests {
use lemmy_utils::{ use lemmy_utils::{
error::LemmyError, error::LemmyError,
rate_limit::{rate_limiter::RateLimiter, RateLimit}, rate_limit::{rate_limiter::RateLimiter, RateLimit},
settings::structs::Settings, settings::SETTINGS,
}; };
use lemmy_websocket::{chat_server::ChatServer, LemmyContext}; use lemmy_websocket::{chat_server::ChatServer, LemmyContext};
use parking_lot::Mutex; use parking_lot::Mutex;
@ -96,7 +96,7 @@ pub(crate) mod tests {
pub(crate) fn init_context() -> LemmyContext { pub(crate) fn init_context() -> LemmyContext {
// call this to run migrations // call this to run migrations
establish_unpooled_connection(); establish_unpooled_connection();
let settings = Settings::init().unwrap(); let settings = SETTINGS.to_owned();
let rate_limiter = RateLimit { let rate_limiter = RateLimit {
rate_limiter: Arc::new(Mutex::new(RateLimiter::default())), rate_limiter: Arc::new(Mutex::new(RateLimiter::default())),
rate_limit_config: settings.rate_limit.to_owned().unwrap_or_default(), rate_limit_config: settings.rate_limit.to_owned().unwrap_or_default(),

View File

@ -120,7 +120,7 @@ impl ApubObject for ApubPerson {
_request_counter: &mut i32, _request_counter: &mut i32,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
verify_domains_match(person.id.inner(), expected_domain)?; verify_domains_match(person.id.inner(), expected_domain)?;
check_apub_id_valid_with_strictness(person.id.inner(), false, &context.settings())?; check_apub_id_valid_with_strictness(person.id.inner(), false, context.settings())?;
let slur_regex = &context.settings().slur_regex(); let slur_regex = &context.settings().slur_regex();
check_slurs(&person.preferred_username, slur_regex)?; check_slurs(&person.preferred_username, slur_regex)?;

View File

@ -19,6 +19,7 @@ use activitystreams_kinds::public;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use lemmy_api_common::{request::fetch_site_data, utils::blocking}; use lemmy_api_common::{request::fetch_site_data, utils::blocking};
use lemmy_db_schema::{ use lemmy_db_schema::{
self,
source::{ source::{
community::Community, community::Community,
moderator::{ModLockPost, ModLockPostForm, ModStickyPost, ModStickyPostForm}, moderator::{ModLockPost, ModLockPostForm, ModStickyPost, ModStickyPostForm},
@ -26,7 +27,6 @@ use lemmy_db_schema::{
post::{Post, PostForm}, post::{Post, PostForm},
}, },
traits::Crud, traits::Crud,
{self},
}; };
use lemmy_utils::{ use lemmy_utils::{
error::LemmyError, error::LemmyError,
@ -132,11 +132,11 @@ impl ApubObject for ApubPost {
// instance from the post author. // instance from the post author.
if !page.is_mod_action(context).await? { if !page.is_mod_action(context).await? {
verify_domains_match(page.id.inner(), expected_domain)?; verify_domains_match(page.id.inner(), expected_domain)?;
verify_is_remote_object(page.id.inner())?; verify_is_remote_object(page.id.inner(), context.settings())?;
}; };
let community = page.extract_community(context, request_counter).await?; let community = page.extract_community(context, request_counter).await?;
check_apub_id_valid_with_strictness(page.id.inner(), community.local, &context.settings())?; check_apub_id_valid_with_strictness(page.id.inner(), community.local, context.settings())?;
verify_person_in_community(&page.creator()?, &community, context, request_counter).await?; verify_person_in_community(&page.creator()?, &community, context, request_counter).await?;
check_slurs(&page.name, &context.settings().slur_regex())?; check_slurs(&page.name, &context.settings().slur_regex())?;
verify_domains_match(page.creator()?.inner(), page.id.inner())?; verify_domains_match(page.creator()?.inner(), page.id.inner())?;
@ -168,7 +168,7 @@ impl ApubObject for ApubPost {
page.url page.url
}; };
let (metadata_res, thumbnail_url) = if let Some(url) = &url { let (metadata_res, thumbnail_url) = if let Some(url) = &url {
fetch_site_data(context.client(), &context.settings(), Some(url)).await fetch_site_data(context.client(), context.settings(), Some(url)).await
} else { } else {
(None, page.image.map(|i| i.url.into())) (None, page.image.map(|i| i.url.into()))
}; };

View File

@ -24,7 +24,6 @@ use lemmy_db_schema::{
}; };
use lemmy_utils::{ use lemmy_utils::{
error::LemmyError, error::LemmyError,
settings::structs::Settings,
utils::{convert_datetime, markdown_to_html}, utils::{convert_datetime, markdown_to_html},
}; };
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
@ -109,7 +108,7 @@ impl ApubObject for ApubPrivateMessage {
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
verify_domains_match(note.id.inner(), expected_domain)?; verify_domains_match(note.id.inner(), expected_domain)?;
verify_domains_match(note.attributed_to.inner(), note.id.inner())?; verify_domains_match(note.attributed_to.inner(), note.id.inner())?;
check_apub_id_valid_with_strictness(note.id.inner(), false, &Settings::get())?; check_apub_id_valid_with_strictness(note.id.inner(), false, context.settings())?;
let person = note let person = note
.attributed_to .attributed_to
.dereference(context, local_instance(context), request_counter) .dereference(context, local_instance(context), request_counter)

View File

@ -63,7 +63,7 @@ impl Group {
expected_domain: &Url, expected_domain: &Url,
context: &LemmyContext, context: &LemmyContext,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
check_apub_id_valid_with_strictness(self.id.inner(), true, &context.settings())?; check_apub_id_valid_with_strictness(self.id.inner(), true, context.settings())?;
verify_domains_match(expected_domain, self.id.inner())?; verify_domains_match(expected_domain, self.id.inner())?;
let slur_regex = &context.settings().slur_regex(); let slur_regex = &context.settings().slur_regex();

View File

@ -7,18 +7,18 @@ use anyhow::{anyhow, Context};
use deser_hjson::from_str; use deser_hjson::from_str;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::{Regex, RegexBuilder}; use regex::{Regex, RegexBuilder};
use std::{env, fs, io::Error, sync::RwLock}; use std::{env, fs, io::Error};
pub mod structs; pub mod structs;
static DEFAULT_CONFIG_FILE: &str = "config/config.hjson"; static DEFAULT_CONFIG_FILE: &str = "config/config.hjson";
static SETTINGS: Lazy<RwLock<Settings>> = pub static SETTINGS: Lazy<Settings> =
Lazy::new(|| RwLock::new(Settings::init().expect("Failed to load settings file"))); Lazy::new(|| Settings::init().expect("Failed to load settings file"));
static WEBFINGER_REGEX: Lazy<Regex> = Lazy::new(|| { static WEBFINGER_REGEX: Lazy<Regex> = Lazy::new(|| {
Regex::new(&format!( Regex::new(&format!(
"^acct:([a-zA-Z0-9_]{{3,}})@{}$", "^acct:([a-zA-Z0-9_]{{3,}})@{}$",
Settings::get().hostname SETTINGS.hostname
)) ))
.expect("compile webfinger regex") .expect("compile webfinger regex")
}); });
@ -29,7 +29,7 @@ impl Settings {
/// Note: The env var `LEMMY_DATABASE_URL` is parsed in /// Note: The env var `LEMMY_DATABASE_URL` is parsed in
/// `lemmy_db_schema/src/lib.rs::get_database_url_from_env()` /// `lemmy_db_schema/src/lib.rs::get_database_url_from_env()`
/// Warning: Only call this once. /// Warning: Only call this once.
pub fn init() -> Result<Self, LemmyError> { pub(crate) fn init() -> Result<Self, LemmyError> {
// Read the config file // Read the config file
let config = from_str::<Settings>(&Self::read_config_file()?)?; let config = from_str::<Settings>(&Self::read_config_file()?)?;
@ -40,11 +40,6 @@ impl Settings {
Ok(config) Ok(config)
} }
/// Returns the config as a struct.
pub fn get() -> Self {
SETTINGS.read().expect("read config").to_owned()
}
pub fn get_database_url(&self) -> String { pub fn get_database_url(&self) -> String {
let conf = &self.database; let conf = &self.database;
format!( format!(
@ -91,23 +86,6 @@ impl Settings {
) )
} }
pub fn save_config_file(data: &str) -> Result<String, LemmyError> {
// check that the config is valid
from_str::<Settings>(data)?;
fs::write(Settings::get_config_location(), data)?;
// Reload the new settings
// From https://stackoverflow.com/questions/29654927/how-do-i-assign-a-string-to-a-mutable-static-variable/47181804#47181804
let mut new_settings = SETTINGS.write().expect("write config");
*new_settings = match Settings::init() {
Ok(c) => c,
Err(e) => panic!("{}", e),
};
Ok(Self::read_config_file()?)
}
pub fn webfinger_regex(&self) -> Regex { pub fn webfinger_regex(&self) -> Regex {
WEBFINGER_REGEX.to_owned() WEBFINGER_REGEX.to_owned()
} }

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
settings::structs::Settings, settings::SETTINGS,
utils::{ utils::{
is_valid_actor_name, is_valid_actor_name,
is_valid_display_name, is_valid_display_name,
@ -24,7 +24,7 @@ fn test_mentions_regex() {
#[test] #[test]
fn test_valid_actor_name() { fn test_valid_actor_name() {
let actor_name_max_length = Settings::init().unwrap().actor_name_max_length; let actor_name_max_length = SETTINGS.actor_name_max_length;
assert!(is_valid_actor_name("Hello_98", actor_name_max_length)); assert!(is_valid_actor_name("Hello_98", actor_name_max_length));
assert!(is_valid_actor_name("ten", actor_name_max_length)); assert!(is_valid_actor_name("ten", actor_name_max_length));
assert!(!is_valid_actor_name("Hello-98", actor_name_max_length)); assert!(!is_valid_actor_name("Hello-98", actor_name_max_length));
@ -34,7 +34,7 @@ fn test_valid_actor_name() {
#[test] #[test]
fn test_valid_display_name() { fn test_valid_display_name() {
let actor_name_max_length = Settings::init().unwrap().actor_name_max_length; let actor_name_max_length = SETTINGS.actor_name_max_length;
assert!(is_valid_display_name("hello @there", actor_name_max_length)); assert!(is_valid_display_name("hello @there", actor_name_max_length));
assert!(!is_valid_display_name( assert!(!is_valid_display_name(
"@hello there", "@hello there",
@ -65,7 +65,7 @@ fn test_valid_matrix_id() {
#[test] #[test]
fn test_slur_filter() { fn test_slur_filter() {
let slur_regex = Settings::init().unwrap().slur_regex(); let slur_regex = SETTINGS.slur_regex();
let test = let test =
"faggot test kike tranny cocksucker retardeds. Capitalized Niggerz. This is a bunch of other safe text."; "faggot test kike tranny cocksucker retardeds. Capitalized Niggerz. This is a bunch of other safe text.";
let slur_free = "No slurs here"; let slur_free = "No slurs here";

View File

@ -4,7 +4,10 @@ extern crate strum_macros;
use crate::chat_server::ChatServer; use crate::chat_server::ChatServer;
use actix::Addr; use actix::Addr;
use lemmy_db_schema::{source::secret::Secret, utils::DbPool}; use lemmy_db_schema::{source::secret::Secret, utils::DbPool};
use lemmy_utils::{error::LemmyError, settings::structs::Settings}; use lemmy_utils::{
error::LemmyError,
settings::{structs::Settings, SETTINGS},
};
use reqwest_middleware::ClientWithMiddleware; use reqwest_middleware::ClientWithMiddleware;
use serde::Serialize; use serde::Serialize;
@ -47,9 +50,8 @@ impl LemmyContext {
pub fn client(&self) -> &ClientWithMiddleware { pub fn client(&self) -> &ClientWithMiddleware {
&self.client &self.client
} }
pub fn settings(&self) -> Settings { pub fn settings(&self) -> &'static Settings {
// TODO hacky solution to be able to hotload the settings. &SETTINGS
Settings::get()
} }
pub fn secret(&self) -> &Secret { pub fn secret(&self) -> &Secret {
&self.secret &self.secret
@ -133,8 +135,6 @@ pub enum UserOperation {
PasswordChange, PasswordChange,
MarkPrivateMessageAsRead, MarkPrivateMessageAsRead,
UserJoin, UserJoin,
GetSiteConfig,
SaveSiteConfig,
PostJoin, PostJoin,
CommunityJoin, CommunityJoin,
ModJoin, ModJoin,

View File

@ -217,7 +217,7 @@ pub async fn send_local_notifs(
&mention_user_view, &mention_user_view,
&lang.notification_mentioned_by_subject(&person.name), &lang.notification_mentioned_by_subject(&person.name),
&lang.notification_mentioned_by_body(&comment.content, &inbox_link, &person.name), &lang.notification_mentioned_by_body(&comment.content, &inbox_link, &person.name),
&context.settings(), context.settings(),
) )
} }
} }
@ -252,7 +252,7 @@ pub async fn send_local_notifs(
&parent_user_view, &parent_user_view,
&lang.notification_comment_reply_subject(&person.name), &lang.notification_comment_reply_subject(&person.name),
&lang.notification_comment_reply_body(&comment.content, &inbox_link, &person.name), &lang.notification_comment_reply_body(&comment.content, &inbox_link, &person.name),
&context.settings(), context.settings(),
) )
} }
} }
@ -282,7 +282,7 @@ pub async fn send_local_notifs(
&parent_user_view, &parent_user_view,
&lang.notification_post_reply_subject(&person.name), &lang.notification_post_reply_subject(&person.name),
&lang.notification_post_reply_body(&comment.content, &inbox_link, &person.name), &lang.notification_post_reply_body(&comment.content, &inbox_link, &person.name),
&context.settings(), context.settings(),
) )
} }
} }

View File

@ -18,9 +18,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
.route("", web::get().to(route_get_crud::<GetSite>)) .route("", web::get().to(route_get_crud::<GetSite>))
// Admin Actions // Admin Actions
.route("", web::post().to(route_post_crud::<CreateSite>)) .route("", web::post().to(route_post_crud::<CreateSite>))
.route("", web::put().to(route_post_crud::<EditSite>)) .route("", web::put().to(route_post_crud::<EditSite>)),
.route("/config", web::get().to(route_get::<GetSiteConfig>))
.route("/config", web::put().to(route_post::<SaveSiteConfig>)),
) )
.service( .service(
web::resource("/modlog") web::resource("/modlog")

View File

@ -26,7 +26,7 @@ use lemmy_server::{
use lemmy_utils::{ use lemmy_utils::{
error::LemmyError, error::LemmyError,
rate_limit::{rate_limiter::RateLimiter, RateLimit}, rate_limit::{rate_limiter::RateLimiter, RateLimit},
settings::structs::Settings, settings::{structs::Settings, SETTINGS},
}; };
use lemmy_websocket::{chat_server::ChatServer, LemmyContext}; use lemmy_websocket::{chat_server::ChatServer, LemmyContext};
use parking_lot::Mutex; use parking_lot::Mutex;
@ -54,7 +54,7 @@ async fn main() -> Result<(), LemmyError> {
return Ok(()); return Ok(());
} }
let settings = Settings::init().expect("Couldn't initialize settings."); let settings = SETTINGS.to_owned();
init_logging(settings.opentelemetry_url.as_deref())?; init_logging(settings.opentelemetry_url.as_deref())?;