_websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
let data: &MarkCommentAsRead = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let comment_id = data.comment_id;
let orig_comment = blocking(context.pool(), move |conn| {
_websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
let data: &SaveComment = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let comment_saved_form = CommentSavedForm {
comment_id: data.comment_id,
websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
let data: &CreateCommentLike = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let mut recipient_ids = Vec::<LocalUserId>::new();
websocket_id: Option<ConnectionId>,
) -> Result<CreateCommentReportResponse, LemmyError> {
let data: &CreateCommentReport = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// check size of report and check for whitespace
let reason = data.reason.trim();
websocket_id: Option<ConnectionId>,
) -> Result<ResolveCommentReportResponse, LemmyError> {
let data: &ResolveCommentReport = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let report_id = data.report_id;
let report = blocking(context.pool(), move |conn| {
websocket_id: Option<ConnectionId>,
) -> Result<ListCommentReportsResponse, LemmyError> {
let data: &ListCommentReports = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let person_id = local_user_view.person.id;
let community_id = data.community;
_websocket_id: Option<ConnectionId>,
) -> Result<CommunityResponse, LemmyError> {
let data: &FollowCommunity = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let community_id = data.community_id;
let community = blocking(context.pool(), move |conn| {
_websocket_id: Option<ConnectionId>,
) -> Result<BlockCommunityResponse, LemmyError> {
let data: &BlockCommunity = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let community_id = data.community_id;
let person_id = local_user_view.person.id;
websocket_id: Option<ConnectionId>,
) -> Result<BanFromCommunityResponse, LemmyError> {
let data: &BanFromCommunity = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let community_id = data.community_id;
let banned_person_id = data.person_id;
websocket_id: Option<ConnectionId>,
) -> Result<AddModToCommunityResponse, LemmyError> {
let data: &AddModToCommunity = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let community_id = data.community_id;
_websocket_id: Option<ConnectionId>,
) -> Result<GetCommunityResponse, LemmyError> {
let data: &TransferCommunity = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let site_creator_id = blocking(context.pool(), move |conn| {
Site::read(conn, 1).map(|s| s.creator_id)
use lemmy_api_common::check_validator_time;
use lemmy_db_queries::{
establish_unpooled_connection,
- source::{local_user::LocalUser_, secret::SecretSingleton},
+ source::{local_user::LocalUser_, secret::Secret_},
Crud,
};
use lemmy_db_schema::source::{
person::{Person, PersonForm},
secret::Secret,
};
- use lemmy_utils::claims::Claims;
+ use lemmy_utils::{claims::Claims, settings::structs::Settings};
#[test]
fn test_should_not_validate_user_token_after_password_change() {
let conn = establish_unpooled_connection();
+ let secret = Secret::init(&conn).unwrap();
+ let settings = Settings::init().unwrap();
let new_person = PersonForm {
name: "Gerry9812".into(),
let inserted_local_user = LocalUser::create(&conn, &local_user_form).unwrap();
- let jwt_secret = Secret::get().jwt_secret;
- let jwt = Claims::jwt(inserted_local_user.id.0, &jwt_secret).unwrap();
- let claims = Claims::decode(&jwt, jwt_secret.as_ref()).unwrap().claims;
+ let jwt = Claims::jwt(
+ inserted_local_user.id.0,
+ &secret.jwt_secret,
+ &settings.hostname,
+ )
+ .unwrap();
+ let claims = Claims::decode(&jwt, &secret.jwt_secret).unwrap().claims;
let check = check_validator_time(&inserted_local_user.validator_time, &claims);
assert!(check.is_ok());
person_mention::PersonMention_,
post::Post_,
private_message::PrivateMessage_,
- secret::SecretSingleton,
},
Blockable,
Crud,
person_mention::*,
post::Post,
private_message::PrivateMessage,
- secret::Secret,
site::*,
},
};
claims::Claims,
email::send_email,
location_info,
- settings::structs::Settings,
utils::{generate_random_string, is_valid_display_name, is_valid_matrix_id, naive_from_unix},
ApiError,
ConnectionId,
}
// Return the jwt
- let jwt_secret = Secret::get().jwt_secret;
Ok(LoginResponse {
- jwt: Claims::jwt(local_user_view.local_user.id.0, &jwt_secret)?,
+ jwt: Claims::jwt(
+ local_user_view.local_user.id.0,
+ &context.secret().jwt_secret,
+ &context.settings().hostname,
+ )?,
})
}
}
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<Self::Response, LemmyError> {
- let captcha_settings = Settings::get().captcha;
+ let captcha_settings = context.settings().captcha;
if !captcha_settings.enabled {
return Ok(GetCaptchaResponse { ok: None });
_websocket_id: Option<ConnectionId>,
) -> Result<LoginResponse, LemmyError> {
let data: &SaveUserSettings = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let avatar = diesel_option_overwrite_to_url(&data.avatar)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
}
if let Some(Some(display_name)) = &display_name {
- if !is_valid_display_name(display_name.trim()) {
+ if !is_valid_display_name(
+ display_name.trim(),
+ context.settings().actor_name_max_length,
+ ) {
return Err(ApiError::err("invalid_username").into());
}
}
};
// Return the jwt
- let jwt_secret = Secret::get().jwt_secret;
Ok(LoginResponse {
- jwt: Claims::jwt(updated_local_user.id.0, &jwt_secret)?,
+ jwt: Claims::jwt(
+ updated_local_user.id.0,
+ &context.secret().jwt_secret,
+ &context.settings().hostname,
+ )?,
})
}
}
_websocket_id: Option<ConnectionId>,
) -> Result<LoginResponse, LemmyError> {
let data: &ChangePassword = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
password_length_check(&data.new_password)?;
.await??;
// Return the jwt
- let jwt_secret = Secret::get().jwt_secret;
Ok(LoginResponse {
- jwt: Claims::jwt(updated_local_user.id.0, &jwt_secret)?,
+ jwt: Claims::jwt(
+ updated_local_user.id.0,
+ &context.secret().jwt_secret,
+ &context.settings().hostname,
+ )?,
})
}
}
websocket_id: Option<ConnectionId>,
) -> Result<AddAdminResponse, LemmyError> {
let data: &AddAdmin = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// Make sure user is an admin
is_admin(&local_user_view)?;
websocket_id: Option<ConnectionId>,
) -> Result<BanPersonResponse, LemmyError> {
let data: &BanPerson = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// Make sure user is an admin
is_admin(&local_user_view)?;
_websocket_id: Option<ConnectionId>,
) -> Result<BlockPersonResponse, LemmyError> {
let data: &BlockPerson = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let target_id = data.person_id;
let person_id = local_user_view.person.id;
_websocket_id: Option<ConnectionId>,
) -> Result<GetRepliesResponse, LemmyError> {
let data: &GetReplies = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
_websocket_id: Option<ConnectionId>,
) -> Result<GetPersonMentionsResponse, LemmyError> {
let data: &GetPersonMentions = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let sort: Option<SortType> = from_opt_str_to_opt_enum(&data.sort);
_websocket_id: Option<ConnectionId>,
) -> Result<PersonMentionResponse, LemmyError> {
let data: &MarkPersonMentionAsRead = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let person_mention_id = data.person_mention_id;
let read_person_mention = blocking(context.pool(), move |conn| {
_websocket_id: Option<ConnectionId>,
) -> Result<GetRepliesResponse, LemmyError> {
let data: &MarkAllAsRead = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let person_id = local_user_view.person.id;
let replies = blocking(context.pool(), move |conn| {
// TODO no i18n support here.
let email = &local_user_view.local_user.email.expect("email");
let subject = &format!("Password reset for {}", local_user_view.person.name);
- let hostname = &Settings::get().get_protocol_and_hostname();
- let html = &format!("<h1>Password Reset Request for {}</h1><br><a href={}/password_change/{}>Click here to reset your password</a>", local_user_view.person.name, hostname, &token);
- send_email(subject, email, &local_user_view.person.name, html)
- .map_err(|e| ApiError::err(&e))?;
+ let protocol_and_hostname = &context.settings().get_protocol_and_hostname();
+ let html = &format!("<h1>Password Reset Request for {}</h1><br><a href={}/password_change/{}>Click here to reset your password</a>", local_user_view.person.name, protocol_and_hostname, &token);
+ send_email(
+ subject,
+ email,
+ &local_user_view.person.name,
+ html,
+ &context.settings(),
+ )
+ .map_err(|e| ApiError::err(&e))?;
Ok(PasswordResetResponse {})
}
.map_err(|_| ApiError::err("couldnt_update_user"))?;
// Return the jwt
- let jwt_secret = Secret::get().jwt_secret;
Ok(LoginResponse {
- jwt: Claims::jwt(updated_local_user.id.0, &jwt_secret)?,
+ jwt: Claims::jwt(
+ updated_local_user.id.0,
+ &context.secret().jwt_secret,
+ &context.settings().hostname,
+ )?,
})
}
}
websocket_id: Option<ConnectionId>,
) -> Result<GetReportCountResponse, LemmyError> {
let data: &GetReportCount = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let person_id = local_user_view.person.id;
let community_id = data.community;
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
let data: &CreatePostLike = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// Don't do a downvote if site has downvotes disabled
check_downvotes_enabled(data.score, context.pool()).await?;
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
let data: &LockPost = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let post_id = data.post_id;
let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
let data: &StickyPost = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let post_id = data.post_id;
let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
_websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
let data: &SavePost = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let post_saved_form = PostSavedForm {
post_id: data.post_id,
websocket_id: Option<ConnectionId>,
) -> Result<CreatePostReportResponse, LemmyError> {
let data: &CreatePostReport = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// check size of report and check for whitespace
let reason = data.reason.trim();
websocket_id: Option<ConnectionId>,
) -> Result<ResolvePostReportResponse, LemmyError> {
let data: &ResolvePostReport = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let report_id = data.report_id;
let report = blocking(context.pool(), move |conn| {
websocket_id: Option<ConnectionId>,
) -> Result<ListPostReportsResponse, LemmyError> {
let data: &ListPostReports = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let person_id = local_user_view.person.id;
let community_id = data.community;
websocket_id: Option<ConnectionId>,
) -> Result<PrivateMessageResponse, LemmyError> {
let data: &MarkPrivateMessageAsRead = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// Checking permissions
let private_message_id = data.private_message_id;
) -> Result<SearchResponse, LemmyError> {
let data: &Search = self;
- let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?;
let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
let show_bot_accounts = local_user_view
let community_actor_id = data
.community_name
.as_ref()
- .map(|t| build_actor_id_from_shortname(EndpointType::Community, t).ok())
+ .map(|t| build_actor_id_from_shortname(EndpointType::Community, t, &context.settings()).ok())
.unwrap_or(None);
let creator_id = data.creator_id;
match search_type {
context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>,
) -> Result<ResolveObjectResponse, LemmyError> {
- let local_user_view = get_local_user_view_from_jwt_opt(&self.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt_opt(&self.auth, context.pool(), context.secret()).await?;
let res = search_by_apub_id(&self.q, context)
.await
.map_err(|_| ApiError::err("couldnt_find_object"))?;
_websocket_id: Option<ConnectionId>,
) -> Result<GetSiteResponse, LemmyError> {
let data: &TransferSite = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
is_admin(&local_user_view)?;
admins.insert(0, creator_person);
let banned = blocking(context.pool(), move |conn| PersonViewSafe::banned(conn)).await??;
- let federated_instances = build_federated_instances(context.pool()).await?;
+ let federated_instances = build_federated_instances(
+ context.pool(),
+ &context.settings().federation,
+ &context.settings().hostname,
+ )
+ .await?;
Ok(GetSiteResponse {
site_view: Some(site_view),
_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()).await?;
+ 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)?;
_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()).await?;
+ 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)?;
websocket_id: Option<ConnectionId>,
) -> Result<UserJoinResponse, LemmyError> {
let data: &UserJoin = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
if let Some(ws_id) = websocket_id {
context.chat_server().do_send(JoinUserRoom {
source::{
community::{CommunityModerator_, Community_},
person_block::PersonBlock_,
- secret::SecretSingleton,
site::Site_,
},
Crud,
use lemmy_utils::{
claims::Claims,
email::send_email,
- settings::structs::Settings,
+ settings::structs::{FederationConfig, Settings},
utils::MentionData,
ApiError,
LemmyError,
post: Post,
pool: &DbPool,
do_send_email: bool,
+ settings: &Settings,
) -> Result<Vec<LocalUserId>, LemmyError> {
+ let settings = settings.to_owned();
let ids = blocking(pool, move |conn| {
- do_send_local_notifs(conn, &mentions, &comment, &person, &post, do_send_email)
+ do_send_local_notifs(
+ conn,
+ &mentions,
+ &comment,
+ &person,
+ &post,
+ do_send_email,
+ &settings,
+ )
})
.await?;
person: &Person,
post: &Post,
do_send_email: bool,
+ settings: &Settings,
) -> Vec<LocalUserId> {
let mut recipient_ids = Vec::new();
// Send the local mentions
for mention in mentions
.iter()
- .filter(|m| m.is_local() && m.name.ne(&person.name))
+ .filter(|m| m.is_local(&settings.hostname) && m.name.ne(&person.name))
.collect::<Vec<&MentionData>>()
{
if let Ok(mention_user_view) = LocalUserView::read_from_name(conn, &mention.name) {
"Mentioned by",
"Person Mention",
&comment.content,
+ settings,
)
}
}
"Reply from",
"Comment Reply",
&comment.content,
+ settings,
)
}
}
"Reply from",
"Post Reply",
&comment.content,
+ settings,
)
}
}
subject_text: &str,
body_text: &str,
comment_content: &str,
+ settings: &Settings,
) {
if local_user_view.person.banned || !local_user_view.local_user.send_notifications_to_email {
return;
if let Some(user_email) = &local_user_view.local_user.email {
let subject = &format!(
"{} - {} {}",
- subject_text,
- Settings::get().hostname,
- local_user_view.person.name,
+ subject_text, settings.hostname, local_user_view.person.name,
);
let html = &format!(
"<h1>{}</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
body_text,
local_user_view.person.name,
comment_content,
- Settings::get().get_protocol_and_hostname()
+ settings.get_protocol_and_hostname()
);
- match send_email(subject, user_email, &local_user_view.person.name, html) {
+ match send_email(
+ subject,
+ user_email,
+ &local_user_view.person.name,
+ html,
+ settings,
+ ) {
Ok(_o) => _o,
Err(e) => error!("{}", e),
};
pub async fn get_local_user_view_from_jwt(
jwt: &str,
pool: &DbPool,
+ secret: &Secret,
) -> Result<LocalUserView, LemmyError> {
- let jwt_secret = Secret::get().jwt_secret;
- let claims = Claims::decode(jwt, &jwt_secret)
+ let claims = Claims::decode(jwt, &secret.jwt_secret)
.map_err(|_| ApiError::err("not_logged_in"))?
.claims;
let local_user_id = LocalUserId(claims.sub);
pub async fn get_local_user_view_from_jwt_opt(
jwt: &Option<String>,
pool: &DbPool,
+ secret: &Secret,
) -> Result<Option<LocalUserView>, LemmyError> {
match jwt {
- Some(jwt) => Ok(Some(get_local_user_view_from_jwt(jwt, pool).await?)),
+ Some(jwt) => Ok(Some(get_local_user_view_from_jwt(jwt, pool, secret).await?)),
None => Ok(None),
}
}
pub async fn get_local_user_settings_view_from_jwt(
jwt: &str,
pool: &DbPool,
+ secret: &Secret,
) -> Result<LocalUserSettingsView, LemmyError> {
- let jwt_secret = Secret::get().jwt_secret;
- let claims = Claims::decode(jwt, &jwt_secret)
+ let claims = Claims::decode(jwt, &secret.jwt_secret)
.map_err(|_| ApiError::err("not_logged_in"))?
.claims;
let local_user_id = LocalUserId(claims.sub);
pub async fn get_local_user_settings_view_from_jwt_opt(
jwt: &Option<String>,
pool: &DbPool,
+ secret: &Secret,
) -> Result<Option<LocalUserSettingsView>, LemmyError> {
match jwt {
Some(jwt) => Ok(Some(
- get_local_user_settings_view_from_jwt(jwt, pool).await?,
+ get_local_user_settings_view_from_jwt(jwt, pool, secret).await?,
)),
None => Ok(None),
}
pub async fn build_federated_instances(
pool: &DbPool,
+ federation_config: &FederationConfig,
+ hostname: &str,
) -> Result<Option<FederatedInstances>, LemmyError> {
- if Settings::get().federation.enabled {
+ let federation = federation_config.to_owned();
+ if federation.enabled {
let distinct_communities = blocking(pool, move |conn| {
Community::distinct_federated_communities(conn)
})
.await??;
- let allowed = Settings::get().federation.allowed_instances;
- let blocked = Settings::get().federation.blocked_instances;
+ let allowed = federation.allowed_instances;
+ let blocked = federation.blocked_instances;
let mut linked = distinct_communities
.iter()
}
if let Some(blocked) = blocked.as_ref() {
- linked.retain(|a| !blocked.contains(a) && !a.eq(&Settings::get().hostname));
+ linked.retain(|a| !blocked.contains(a) && !a.eq(hostname));
}
// Sort and remove dupes
websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
let data: &CreateComment = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
- let content_slurs_removed = remove_slurs(&data.content.to_owned());
+ let content_slurs_removed =
+ remove_slurs(&data.content.to_owned(), &context.settings().slur_regex());
// Check for a community ban
let post_id = data.post_id;
// Necessary to update the ap_id
let inserted_comment_id = inserted_comment.id;
+ let protocol_and_hostname = context.settings().get_protocol_and_hostname();
+
let updated_comment: Comment =
blocking(context.pool(), move |conn| -> Result<Comment, LemmyError> {
- let apub_id =
- generate_apub_endpoint(EndpointType::Comment, &inserted_comment_id.to_string())?;
+ let apub_id = generate_apub_endpoint(
+ EndpointType::Comment,
+ &inserted_comment_id.to_string(),
+ &protocol_and_hostname,
+ )?;
Ok(Comment::update_ap_id(conn, inserted_comment_id, apub_id)?)
})
.await?
post,
context.pool(),
true,
+ &context.settings(),
)
.await?;
websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
let data: &DeleteComment = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let comment_id = data.comment_id;
let orig_comment = blocking(context.pool(), move |conn| {
post,
context.pool(),
false,
+ &context.settings(),
)
.await?;
websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
let data: &RemoveComment = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let comment_id = data.comment_id;
let orig_comment = blocking(context.pool(), move |conn| {
post,
context.pool(),
false,
+ &context.settings(),
)
.await?;
_websocket_id: Option<ConnectionId>,
) -> Result<GetCommentsResponse, LemmyError> {
let data: &GetComments = self;
- let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?;
let show_bot_accounts = local_user_view
.as_ref()
let community_actor_id = data
.community_name
.as_ref()
- .map(|t| build_actor_id_from_shortname(EndpointType::Community, t).ok())
+ .map(|t| build_actor_id_from_shortname(EndpointType::Community, t, &context.settings()).ok())
.unwrap_or(None);
let saved_only = data.saved_only;
let page = data.page;
websocket_id: Option<ConnectionId>,
) -> Result<CommentResponse, LemmyError> {
let data: &EditComment = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let comment_id = data.comment_id;
let orig_comment = blocking(context.pool(), move |conn| {
}
// Do the update
- let content_slurs_removed = remove_slurs(&data.content.to_owned());
+ let content_slurs_removed =
+ remove_slurs(&data.content.to_owned(), &context.settings().slur_regex());
let comment_id = data.comment_id;
let updated_comment = blocking(context.pool(), move |conn| {
Comment::update_content(conn, comment_id, &content_slurs_removed)
orig_comment.post,
context.pool(),
false,
+ &context.settings(),
)
.await?;
_websocket_id: Option<ConnectionId>,
) -> Result<CommunityResponse, LemmyError> {
let data: &CreateCommunity = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let site = blocking(context.pool(), move |conn| Site::read(conn, 0)).await??;
if site.community_creation_admin_only && is_admin(&local_user_view).is_err() {
return Err(ApiError::err("only_admins_can_create_communities").into());
}
- check_slurs(&data.name)?;
- check_slurs(&data.title)?;
- check_slurs_opt(&data.description)?;
+ check_slurs(&data.name, &context.settings().slur_regex())?;
+ check_slurs(&data.title, &context.settings().slur_regex())?;
+ check_slurs_opt(&data.description, &context.settings().slur_regex())?;
- if !is_valid_actor_name(&data.name) {
+ if !is_valid_actor_name(&data.name, context.settings().actor_name_max_length) {
return Err(ApiError::err("invalid_community_name").into());
}
// Double check for duplicate community actor_ids
- let community_actor_id = generate_apub_endpoint(EndpointType::Community, &data.name)?;
+ let community_actor_id = generate_apub_endpoint(
+ EndpointType::Community,
+ &data.name,
+ &context.settings().get_protocol_and_hostname(),
+ )?;
let actor_id_cloned = community_actor_id.to_owned();
let community_dupe = blocking(context.pool(), move |conn| {
Community::read_from_apub_id(conn, &actor_id_cloned)
websocket_id: Option<ConnectionId>,
) -> Result<CommunityResponse, LemmyError> {
let data: &DeleteCommunity = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// Fetch the community mods
let community_id = data.community_id;
websocket_id: Option<ConnectionId>,
) -> Result<CommunityResponse, LemmyError> {
let data: &RemoveCommunity = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// Verify its an admin (only an admin can remove a community)
is_admin(&local_user_view)?;
_websocket_id: Option<ConnectionId>,
) -> Result<GetCommunityResponse, LemmyError> {
let data: &GetCommunity = self;
- let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?;
let person_id = local_user_view.map(|u| u.person.id);
let community_id = match data.id {
Some(id) => id,
None => {
let name = data.name.to_owned().unwrap_or_else(|| "main".to_string());
- let community_actor_id = build_actor_id_from_shortname(EndpointType::Community, &name)?;
+ let community_actor_id =
+ build_actor_id_from_shortname(EndpointType::Community, &name, &context.settings())?;
blocking(context.pool(), move |conn| {
Community::read_from_apub_id(conn, &community_actor_id)
_websocket_id: Option<ConnectionId>,
) -> Result<ListCommunitiesResponse, LemmyError> {
let data: &ListCommunities = self;
- let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?;
let person_id = local_user_view.to_owned().map(|l| l.person.id);
websocket_id: Option<ConnectionId>,
) -> Result<CommunityResponse, LemmyError> {
let data: &EditCommunity = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
- check_slurs_opt(&data.title)?;
- check_slurs_opt(&data.description)?;
+ check_slurs_opt(&data.title, &context.settings().slur_regex())?;
+ check_slurs_opt(&data.description, &context.settings().slur_regex())?;
// Verify its a mod (only mods can edit it)
let community_id = data.community_id;
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
let data: &CreatePost = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
- check_slurs(&data.name)?;
- check_slurs_opt(&data.body)?;
+ let slur_regex = &context.settings().slur_regex();
+ check_slurs(&data.name, slur_regex)?;
+ check_slurs_opt(&data.body, slur_regex)?;
if !is_valid_post_title(&data.name) {
return Err(ApiError::err("invalid_post_title").into());
// Fetch post links and pictrs cached image
let data_url = data.url.as_ref();
- let (metadata_res, pictrs_thumbnail) = fetch_site_data(context.client(), data_url).await;
+ let (metadata_res, pictrs_thumbnail) =
+ fetch_site_data(context.client(), &context.settings(), data_url).await;
let (embed_title, embed_description, embed_html) = metadata_res
.map(|u| (u.title, u.description, u.html))
.unwrap_or((None, None, None));
};
let inserted_post_id = inserted_post.id;
+ let protocol_and_hostname = context.settings().get_protocol_and_hostname();
let updated_post = blocking(context.pool(), move |conn| -> Result<Post, LemmyError> {
- let apub_id = generate_apub_endpoint(EndpointType::Post, &inserted_post_id.to_string())?;
+ let apub_id = generate_apub_endpoint(
+ EndpointType::Post,
+ &inserted_post_id.to_string(),
+ &protocol_and_hostname,
+ )?;
Ok(Post::update_ap_id(conn, inserted_post_id, apub_id)?)
})
.await?
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
let data: &DeletePost = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let post_id = data.post_id;
let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
let data: &RemovePost = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let post_id = data.post_id;
let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
_websocket_id: Option<ConnectionId>,
) -> Result<GetPostResponse, LemmyError> {
let data: &GetPost = self;
- let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?;
let show_bot_accounts = local_user_view
.as_ref()
_websocket_id: Option<ConnectionId>,
) -> Result<GetPostsResponse, LemmyError> {
let data: &GetPosts = self;
- let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?;
let person_id = local_user_view.to_owned().map(|l| l.person.id);
let community_actor_id = data
.community_name
.as_ref()
- .map(|t| build_actor_id_from_shortname(EndpointType::Community, t).ok())
+ .map(|t| build_actor_id_from_shortname(EndpointType::Community, t, &context.settings()).ok())
.unwrap_or(None);
let saved_only = data.saved_only;
websocket_id: Option<ConnectionId>,
) -> Result<PostResponse, LemmyError> {
let data: &EditPost = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
- check_slurs_opt(&data.name)?;
- check_slurs_opt(&data.body)?;
+ let slur_regex = &context.settings().slur_regex();
+ check_slurs_opt(&data.name, slur_regex)?;
+ check_slurs_opt(&data.body, slur_regex)?;
if let Some(name) = &data.name {
if !is_valid_post_title(name) {
// Fetch post links and Pictrs cached image
let data_url = data.url.as_ref();
- let (metadata_res, pictrs_thumbnail) = fetch_site_data(context.client(), data_url).await;
+ let (metadata_res, pictrs_thumbnail) =
+ fetch_site_data(context.client(), &context.settings(), data_url).await;
let (embed_title, embed_description, embed_html) = metadata_res
.map(|u| (u.title, u.description, u.html))
.unwrap_or((None, None, None));
websocket_id: Option<ConnectionId>,
) -> Result<PrivateMessageResponse, LemmyError> {
let data: &CreatePrivateMessage = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
- let content_slurs_removed = remove_slurs(&data.content.to_owned());
+ let content_slurs_removed =
+ remove_slurs(&data.content.to_owned(), &context.settings().slur_regex());
check_person_block(local_user_view.person.id, data.recipient_id, context.pool()).await?;
};
let inserted_private_message_id = inserted_private_message.id;
+ let protocol_and_hostname = context.settings().get_protocol_and_hostname();
let updated_private_message = blocking(
context.pool(),
move |conn| -> Result<PrivateMessage, LemmyError> {
let apub_id = generate_apub_endpoint(
EndpointType::PrivateMessage,
&inserted_private_message_id.to_string(),
+ &protocol_and_hostname,
)?;
Ok(PrivateMessage::update_ap_id(
conn,
"Private Message from",
"Private Message",
&content_slurs_removed,
+ &context.settings(),
);
}
websocket_id: Option<ConnectionId>,
) -> Result<PrivateMessageResponse, LemmyError> {
let data: &DeletePrivateMessage = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// Checking permissions
let private_message_id = data.private_message_id;
_websocket_id: Option<ConnectionId>,
) -> Result<PrivateMessagesResponse, LemmyError> {
let data: &GetPrivateMessages = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
let person_id = local_user_view.person.id;
let page = data.page;
websocket_id: Option<ConnectionId>,
) -> Result<PrivateMessageResponse, LemmyError> {
let data: &EditPrivateMessage = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// Checking permissions
let private_message_id = data.private_message_id;
}
// Doing the update
- let content_slurs_removed = remove_slurs(&data.content);
+ let content_slurs_removed = remove_slurs(&data.content, &context.settings().slur_regex());
let private_message_id = data.private_message_id;
let updated_private_message = blocking(context.pool(), move |conn| {
PrivateMessage::update_content(conn, private_message_id, &content_slurs_removed)
return Err(ApiError::err("site_already_exists").into());
};
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
- check_slurs(&data.name)?;
- check_slurs_opt(&data.description)?;
+ check_slurs(&data.name, &context.settings().slur_regex())?;
+ check_slurs_opt(&data.description, &context.settings().slur_regex())?;
// Make sure user is an admin
is_admin(&local_user_view)?;
person_block_view::PersonBlockView,
person_view::PersonViewSafe,
};
-use lemmy_utils::{settings::structs::Settings, version, ApiError, ConnectionId, LemmyError};
+use lemmy_utils::{version, ApiError, ConnectionId, LemmyError};
use lemmy_websocket::{messages::GetUsersOnline, LemmyContext};
use log::info;
Ok(site_view) => Some(site_view),
// If the site isn't created yet, check the setup
Err(_) => {
- if let Some(setup) = Settings::get().setup.as_ref() {
+ if let Some(setup) = context.settings().setup.as_ref() {
let register = Register {
username: setup.admin_username.to_owned(),
email: setup.admin_email.to_owned(),
// Build the local user
let my_user = if let Some(local_user_view) =
- get_local_user_settings_view_from_jwt_opt(&data.auth, context.pool()).await?
+ get_local_user_settings_view_from_jwt_opt(&data.auth, context.pool(), context.secret())
+ .await?
{
let person_id = local_user_view.person.id;
let follows = blocking(context.pool(), move |conn| {
None
};
- let federated_instances = build_federated_instances(context.pool()).await?;
+ let federated_instances = build_federated_instances(
+ context.pool(),
+ &context.settings().federation,
+ &context.settings().hostname,
+ )
+ .await?;
Ok(GetSiteResponse {
site_view,
websocket_id: Option<ConnectionId>,
) -> Result<SiteResponse, LemmyError> {
let data: &EditSite = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
- check_slurs_opt(&data.name)?;
- check_slurs_opt(&data.description)?;
+ check_slurs_opt(&data.name, &context.settings().slur_regex())?;
+ check_slurs_opt(&data.description, &context.settings().slur_regex())?;
// Make sure user is an admin
is_admin(&local_user_view)?;
EndpointType,
};
use lemmy_db_queries::{
- source::{local_user::LocalUser_, secret::SecretSingleton, site::Site_},
+ source::{local_user::LocalUser_, site::Site_},
Crud,
Followable,
Joinable,
community::*,
local_user::{LocalUser, LocalUserForm},
person::*,
- secret::Secret,
site::*,
},
CommunityId,
use lemmy_utils::{
apub::generate_actor_keypair,
claims::Claims,
- settings::structs::Settings,
utils::{check_slurs, is_valid_actor_name},
ApiError,
ConnectionId,
.await??;
// If its not the admin, check the captcha
- if !no_admins && Settings::get().captcha.enabled {
+ if !no_admins && context.settings().captcha.enabled {
let check = context
.chat_server()
.send(CheckCaptcha {
}
}
- check_slurs(&data.username)?;
+ check_slurs(&data.username, &context.settings().slur_regex())?;
let actor_keypair = generate_actor_keypair()?;
- if !is_valid_actor_name(&data.username) {
+ if !is_valid_actor_name(&data.username, context.settings().actor_name_max_length) {
return Err(ApiError::err("invalid_username").into());
}
- let actor_id = generate_apub_endpoint(EndpointType::Person, &data.username)?;
+ let actor_id = generate_apub_endpoint(
+ EndpointType::Person,
+ &data.username,
+ &context.settings().get_protocol_and_hostname(),
+ )?;
// We have to create both a person, and local_user
let main_community_keypair = generate_actor_keypair()?;
// Create the main community if it doesn't exist
+ let protocol_and_hostname = context.settings().get_protocol_and_hostname();
let main_community = match blocking(context.pool(), move |conn| {
Community::read(conn, CommunityId(2))
})
Ok(c) => c,
Err(_e) => {
let default_community_name = "main";
- let actor_id = generate_apub_endpoint(EndpointType::Community, default_community_name)?;
+ let actor_id = generate_apub_endpoint(
+ EndpointType::Community,
+ default_community_name,
+ &protocol_and_hostname,
+ )?;
let community_form = CommunityForm {
name: default_community_name.to_string(),
title: "The Default Community".to_string(),
}
// Return the jwt
- let jwt_secret = Secret::get().jwt_secret;
Ok(LoginResponse {
- jwt: Claims::jwt(inserted_local_user.id.0, &jwt_secret)?,
+ jwt: Claims::jwt(
+ inserted_local_user.id.0,
+ &context.secret().jwt_secret,
+ &context.settings().hostname,
+ )?,
})
}
}
_websocket_id: Option<ConnectionId>,
) -> Result<LoginResponse, LemmyError> {
let data: &DeleteAccount = self;
- let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
// Verify the password
let valid: bool = verify(
_websocket_id: Option<ConnectionId>,
) -> Result<GetPersonDetailsResponse, LemmyError> {
let data: &GetPersonDetails = self;
- let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?;
+ let local_user_view =
+ get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?;
let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
let show_bot_accounts = local_user_view
.username
.to_owned()
.unwrap_or_else(|| "admin".to_string());
- let actor_id = build_actor_id_from_shortname(EndpointType::Person, &name)?;
+ let actor_id =
+ build_actor_id_from_shortname(EndpointType::Person, &name, &context.settings())?;
let person = blocking(context.pool(), move |conn| {
Person::read_from_apub_id(conn, &actor_id)
})
.await??;
- let id = generate_activity_id(kind.clone())?;
+ let id = generate_activity_id(
+ kind.clone(),
+ &context.settings().get_protocol_and_hostname(),
+ )?;
let maa = collect_non_local_mentions(comment, &community, context).await?;
let create_or_update = CreateOrUpdateComment {
let community = extract_community(&self.cc, context, request_counter).await?;
let community_id = ObjectId::new(community.actor_id());
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_person_in_community(&self.actor, &community_id, context, request_counter).await?;
verify_domains_match(self.actor.inner(), self.object.id_unchecked())?;
// TODO: should add a check that the correct community is in cc (probably needs changes to
};
use lemmy_utils::{
request::{retry, RecvError},
- settings::structs::Settings,
utils::{scrape_text_for_mentions, MentionData},
LemmyError,
};
use lemmy_websocket::LemmyContext;
use log::debug;
-use reqwest::Client;
use url::Url;
pub mod create_or_update;
// anyway.
// TODO: for compatibility with other projects, it would be much better to read this from cc or tags
let mentions = scrape_text_for_mentions(&comment.content);
- send_local_notifs(mentions, comment.clone(), actor, post, context.pool(), true).await
+ send_local_notifs(
+ mentions,
+ comment.clone(),
+ actor,
+ post,
+ context.pool(),
+ true,
+ &context.settings(),
+ )
+ .await
}
pub struct MentionsAndAddresses {
let mentions = scrape_text_for_mentions(&comment.content)
.into_iter()
// Filter only the non-local ones
- .filter(|m| !m.is_local())
+ .filter(|m| !m.is_local(&context.settings().hostname))
.collect::<Vec<MentionData>>();
for mention in &mentions {
// TODO should it be fetching it every time?
- if let Ok(actor_id) = fetch_webfinger_url(mention, context.client()).await {
+ if let Ok(actor_id) = fetch_webfinger_url(mention, context).await {
let actor_id: ObjectId<Person> = ObjectId::new(actor_id);
debug!("mention actor_id: {}", actor_id);
addressed_ccs.push(actor_id.to_owned().to_string().parse()?);
/// Turns a person id like `@name@example.com` into an apub ID, like `https://example.com/user/name`,
/// using webfinger.
-async fn fetch_webfinger_url(mention: &MentionData, client: &Client) -> Result<Url, LemmyError> {
+async fn fetch_webfinger_url(
+ mention: &MentionData,
+ context: &LemmyContext,
+) -> Result<Url, LemmyError> {
let fetch_url = format!(
"{}://{}/.well-known/webfinger?resource=acct:{}@{}",
- Settings::get().get_protocol_string(),
+ context.settings().get_protocol_string(),
mention.domain,
mention.name,
mention.domain
);
debug!("Fetching webfinger url: {}", &fetch_url);
- let response = retry(|| client.get(&fetch_url).send()).await?;
+ let response = retry(|| context.client().get(&fetch_url).send()).await?;
let res: WebfingerResponse = response
.json()
actor: &Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
- let id = generate_activity_id(AddType::Add)?;
+ let id = generate_activity_id(
+ AddType::Add,
+ &context.settings().get_protocol_and_hostname(),
+ )?;
let add = AddMod {
actor: ObjectId::new(actor.actor_id()),
to: [PublicUrl::Public],
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
verify_mod_action(&self.actor, self.cc[0].clone(), context).await?;
verify_add_remove_moderator_target(&self.target, &self.cc[0])?;
object,
cc: vec![community.followers_url()],
kind: AnnounceType::Announce,
- id: generate_activity_id(&AnnounceType::Announce)?,
+ id: generate_activity_id(
+ &AnnounceType::Announce,
+ &context.settings().get_protocol_and_hostname(),
+ )?,
context: lemmy_context(),
unparsed: Default::default(),
};
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_community(&self.actor, context, request_counter).await?;
self.object.verify(context, request_counter).await?;
Ok(())
community: &Community,
target: &Person,
actor: &Person,
+ context: &LemmyContext,
) -> Result<BlockUserFromCommunity, LemmyError> {
Ok(BlockUserFromCommunity {
actor: ObjectId::new(actor.actor_id()),
object: ObjectId::new(target.actor_id()),
cc: [ObjectId::new(community.actor_id())],
kind: BlockType::Block,
- id: generate_activity_id(BlockType::Block)?,
+ id: generate_activity_id(
+ BlockType::Block,
+ &context.settings().get_protocol_and_hostname(),
+ )?,
context: lemmy_context(),
unparsed: Default::default(),
})
actor: &Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
- let block = BlockUserFromCommunity::new(community, target, actor)?;
+ let block = BlockUserFromCommunity::new(community, target, actor, context)?;
let block_id = block.id.clone();
let activity = AnnouncableActivities::BlockUserFromCommunity(block);
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
verify_mod_action(&self.actor, self.cc[0].clone(), context).await?;
Ok(())
use crate::{check_is_apub_id_valid, CommunityType};
use itertools::Itertools;
use lemmy_db_schema::source::community::Community;
-use lemmy_utils::{settings::structs::Settings, LemmyError};
+use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use url::Url;
) -> Result<Vec<Url>, LemmyError> {
Ok(
vec![
- community.get_follower_inboxes(context.pool()).await?,
+ community
+ .get_follower_inboxes(context.pool(), &context.settings())
+ .await?,
additional_inboxes,
]
.iter()
.flatten()
.unique()
- .filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname))
- .filter(|inbox| check_is_apub_id_valid(inbox, false).is_ok())
+ .filter(|inbox| inbox.host_str() != Some(&context.settings().hostname))
+ .filter(|inbox| check_is_apub_id_valid(inbox, false, &context.settings()).is_ok())
.map(|inbox| inbox.to_owned())
.collect(),
)
actor: &Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
- let id = generate_activity_id(RemoveType::Remove)?;
+ let id = generate_activity_id(
+ RemoveType::Remove,
+ &context.settings().get_protocol_and_hostname(),
+ )?;
let remove = RemoveMod {
actor: ObjectId::new(actor.actor_id()),
to: [PublicUrl::Public],
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
if let Some(target) = &self.target {
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
verify_mod_action(&self.actor, self.cc[0].clone(), context).await?;
actor: &Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
- let block = BlockUserFromCommunity::new(community, target, actor)?;
+ let block = BlockUserFromCommunity::new(community, target, actor, context)?;
- let id = generate_activity_id(UndoType::Undo)?;
+ let id = generate_activity_id(
+ UndoType::Undo,
+ &context.settings().get_protocol_and_hostname(),
+ )?;
let undo = UndoBlockUserFromCommunity {
actor: ObjectId::new(actor.actor_id()),
to: [PublicUrl::Public],
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
verify_mod_action(&self.actor, self.cc[0].clone(), context).await?;
self.object.verify(context, request_counter).await?;
actor: &Person,
context: &LemmyContext,
) -> Result<(), LemmyError> {
- let id = generate_activity_id(UpdateType::Update)?;
+ let id = generate_activity_id(
+ UpdateType::Update,
+ &context.settings().get_protocol_and_hostname(),
+ )?;
let update = UpdateCommunity {
actor: ObjectId::new(actor.actor_id()),
to: [PublicUrl::Public],
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
verify_mod_action(&self.actor, self.cc[0].clone(), context).await?;
Ok(())
})
.await??;
- let updated_community =
- Group::from_apub_to_form(&self.object, &community.actor_id.clone().into()).await?;
+ let updated_community = Group::from_apub_to_form(
+ &self.object,
+ &community.actor_id.clone().into(),
+ &context.settings(),
+ )
+ .await?;
let cf = CommunityForm {
name: updated_community.name,
title: updated_community.title,
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_delete_activity(
&self.object,
self,
community: &Community,
object_id: Url,
summary: Option<String>,
+ context: &LemmyContext,
) -> Result<Delete, LemmyError> {
Ok(Delete {
actor: ObjectId::new(actor.actor_id()),
cc: [ObjectId::new(community.actor_id())],
kind: DeleteType::Delete,
summary,
- id: generate_activity_id(DeleteType::Delete)?,
+ id: generate_activity_id(
+ DeleteType::Delete,
+ &context.settings().get_protocol_and_hostname(),
+ )?,
context: lemmy_context(),
unparsed: Default::default(),
})
summary: Option<String>,
context: &LemmyContext,
) -> Result<(), LemmyError> {
- let delete = Delete::new(actor, community, object_id, summary)?;
+ let delete = Delete::new(actor, community, object_id, summary, context)?;
let delete_id = delete.id.clone();
let activity = AnnouncableActivities::Delete(delete);
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
self.object.verify(context, request_counter).await?;
verify_delete_activity(
&self.object.object,
summary: Option<String>,
context: &LemmyContext,
) -> Result<(), LemmyError> {
- let object = Delete::new(actor, community, object_id, summary)?;
+ let object = Delete::new(actor, community, object_id, summary, context)?;
- let id = generate_activity_id(UndoType::Undo)?;
+ let id = generate_activity_id(
+ UndoType::Undo,
+ &context.settings().get_protocol_and_hostname(),
+ )?;
let undo = UndoDelete {
actor: ObjectId::new(actor.actor_id()),
to: [PublicUrl::Public],
to: ObjectId::new(person.actor_id()),
object: follow,
kind: AcceptType::Accept,
- id: generate_activity_id(AcceptType::Accept)?,
+ id: generate_activity_id(
+ AcceptType::Accept,
+ &context.settings().get_protocol_and_hostname(),
+ )?,
context: lemmy_context(),
unparsed: Default::default(),
};
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_urls_match(self.to.inner(), self.object.actor())?;
verify_urls_match(self.actor(), self.object.to.inner())?;
verify_community(&self.actor, context, request_counter).await?;
pub(in crate::activities::following) fn new(
actor: &Person,
community: &Community,
+ context: &LemmyContext,
) -> Result<FollowCommunity, LemmyError> {
Ok(FollowCommunity {
actor: ObjectId::new(actor.actor_id()),
to: ObjectId::new(community.actor_id()),
object: ObjectId::new(community.actor_id()),
kind: FollowType::Follow,
- id: generate_activity_id(FollowType::Follow)?,
+ id: generate_activity_id(
+ FollowType::Follow,
+ &context.settings().get_protocol_and_hostname(),
+ )?,
context: lemmy_context(),
unparsed: Default::default(),
})
})
.await?;
- let follow = FollowCommunity::new(actor, community)?;
+ let follow = FollowCommunity::new(actor, community, context)?;
let inbox = vec![community.inbox_url.clone().into()];
send_activity_new(context, &follow, &follow.id, actor, inbox, true).await
}
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_urls_match(self.to.inner(), self.object.inner())?;
verify_person(&self.actor, context, request_counter).await?;
Ok(())
community: &Community,
context: &LemmyContext,
) -> Result<(), LemmyError> {
- let object = FollowCommunity::new(actor, community)?;
+ let object = FollowCommunity::new(actor, community, context)?;
let undo = UndoFollowCommunity {
actor: ObjectId::new(actor.actor_id()),
to: ObjectId::new(community.actor_id()),
object,
kind: UndoType::Undo,
- id: generate_activity_id(UndoType::Undo)?,
+ id: generate_activity_id(
+ UndoType::Undo,
+ &context.settings().get_protocol_and_hostname(),
+ )?,
context: lemmy_context(),
unparsed: Default::default(),
};
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_urls_match(self.to.inner(), self.object.object.inner())?;
verify_urls_match(self.actor(), self.object.actor())?;
verify_person(&self.actor, context, request_counter).await?;
Ok(())
}
-fn verify_activity(activity: &dyn ActivityFields) -> Result<(), LemmyError> {
- check_is_apub_id_valid(activity.actor(), false)?;
+fn verify_activity(activity: &dyn ActivityFields, settings: &Settings) -> Result<(), LemmyError> {
+ check_is_apub_id_valid(activity.actor(), false, settings)?;
verify_domains_match(activity.id_unchecked(), activity.actor())?;
Ok(())
}
/// Generate a unique ID for an activity, in the format:
/// `http(s)://example.com/receive/create/202daf0a-1489-45df-8d2e-c8a3173fed36`
-fn generate_activity_id<T>(kind: T) -> Result<Url, ParseError>
+fn generate_activity_id<T>(kind: T, protocol_and_hostname: &str) -> Result<Url, ParseError>
where
T: ToString,
{
let id = format!(
"{}/activities/{}/{}",
- Settings::get().get_protocol_and_hostname(),
+ protocol_and_hostname,
kind.to_string().to_lowercase(),
Uuid::new_v4()
);
})
.await??;
- let id = generate_activity_id(kind.clone())?;
+ let id = generate_activity_id(
+ kind.clone(),
+ &context.settings().get_protocol_and_hostname(),
+ )?;
let create_or_update = CreateOrUpdatePost {
actor: ObjectId::new(actor.actor_id()),
to: [PublicUrl::Public],
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
let community = self.cc[0].dereference(context, request_counter).await?;
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
match self.kind {
let recipient =
blocking(context.pool(), move |conn| Person::read(conn, recipient_id)).await??;
- let id = generate_activity_id(kind.clone())?;
+ let id = generate_activity_id(
+ kind.clone(),
+ &context.settings().get_protocol_and_hostname(),
+ )?;
let create_or_update = CreateOrUpdatePrivateMessage {
context: lemmy_context(),
id: id.clone(),
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_person(&self.actor, context, request_counter).await?;
verify_domains_match(self.actor.inner(), self.object.id_unchecked())?;
self.object.verify(context, request_counter).await?;
pub(in crate::activities::private_message) fn new(
actor: &Person,
pm: &PrivateMessage,
+ context: &LemmyContext,
) -> Result<DeletePrivateMessage, LemmyError> {
Ok(DeletePrivateMessage {
actor: ObjectId::new(actor.actor_id()),
to: ObjectId::new(actor.actor_id()),
object: pm.ap_id.clone().into(),
kind: DeleteType::Delete,
- id: generate_activity_id(DeleteType::Delete)?,
+ id: generate_activity_id(
+ DeleteType::Delete,
+ &context.settings().get_protocol_and_hostname(),
+ )?,
context: lemmy_context(),
unparsed: Default::default(),
})
pm: &PrivateMessage,
context: &LemmyContext,
) -> Result<(), LemmyError> {
- let delete = DeletePrivateMessage::new(actor, pm)?;
+ let delete = DeletePrivateMessage::new(actor, pm, context)?;
let delete_id = delete.id.clone();
let recipient_id = pm.recipient_id;
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_person(&self.actor, context, request_counter).await?;
verify_domains_match(self.actor.inner(), &self.object)?;
Ok(())
let recipient =
blocking(context.pool(), move |conn| Person::read(conn, recipient_id)).await??;
- let object = DeletePrivateMessage::new(actor, pm)?;
- let id = generate_activity_id(UndoType::Undo)?;
+ let object = DeletePrivateMessage::new(actor, pm, context)?;
+ let id = generate_activity_id(
+ UndoType::Undo,
+ &context.settings().get_protocol_and_hostname(),
+ )?;
let undo = UndoDeletePrivateMessage {
actor: ObjectId::new(actor.actor_id()),
to: ObjectId::new(recipient.actor_id()),
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_person(&self.actor, context, request_counter).await?;
verify_urls_match(self.actor(), self.object.actor())?;
verify_domains_match(self.actor(), &self.object.object)?;
use lemmy_db_queries::DbPool;
use lemmy_db_schema::source::community::Community;
use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
-use lemmy_utils::LemmyError;
+use lemmy_utils::{settings::structs::Settings, LemmyError};
use url::Url;
impl ActorType for Community {
}
/// For a given community, returns the inboxes of all followers.
- async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
+ async fn get_follower_inboxes(
+ &self,
+ pool: &DbPool,
+ settings: &Settings,
+ ) -> Result<Vec<Url>, LemmyError> {
let id = self.id;
let follows = blocking(pool, move |conn| {
.map(|i| i.into_inner())
.unique()
// Don't send to blocked instances
- .filter(|inbox| check_is_apub_id_valid(inbox, false).is_ok())
+ .filter(|inbox| check_is_apub_id_valid(inbox, false, settings).is_ok())
.collect();
Ok(inboxes)
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
self.object.verify(context, request_counter).await?;
verify_delete_activity(
})
.await??;
- let object = Vote::new(object, actor, &community, kind.clone())?;
- let id = generate_activity_id(UndoType::Undo)?;
+ let object = Vote::new(object, actor, &community, kind.clone(), context)?;
+ let id = generate_activity_id(
+ UndoType::Undo,
+ &context.settings().get_protocol_and_hostname(),
+ )?;
let undo_vote = UndoVote {
actor: ObjectId::new(actor.actor_id()),
to: [PublicUrl::Public],
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
verify_urls_match(self.actor(), self.object.actor())?;
self.object.verify(context, request_counter).await?;
actor: &Person,
community: &Community,
kind: VoteType,
+ context: &LemmyContext,
) -> Result<Vote, LemmyError> {
Ok(Vote {
actor: ObjectId::new(actor.actor_id()),
object: ObjectId::new(object.ap_id()),
cc: [ObjectId::new(community.actor_id())],
kind: kind.clone(),
- id: generate_activity_id(kind)?,
+ id: generate_activity_id(kind, &context.settings().get_protocol_and_hostname())?,
context: lemmy_context(),
unparsed: Default::default(),
})
Community::read(conn, community_id)
})
.await??;
- let vote = Vote::new(object, actor, &community, kind)?;
+ let vote = Vote::new(object, actor, &community, kind, context)?;
let vote_id = vote.id.clone();
let activity = AnnouncableActivities::Vote(vote);
context: &LemmyContext,
request_counter: &mut i32,
) -> Result<(), LemmyError> {
- verify_activity(self)?;
+ verify_activity(self, &context.settings())?;
verify_person_in_community(&self.actor, &self.cc[0], context, request_counter).await?;
Ok(())
}
WorkerConfig,
};
use lemmy_db_schema::source::community::Community;
-use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
+use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::LemmyContext;
use log::{info, warn};
use reqwest::Client;
where
T: Serialize,
{
- if !Settings::get().federation.enabled || inboxes.is_empty() {
+ if !context.settings().federation.enabled || inboxes.is_empty() {
return Ok(());
}
// Don't send anything to ourselves
// TODO: this should be a debug assert
- let hostname = Settings::get().get_hostname_without_port()?;
+ let hostname = context.settings().get_hostname_without_port()?;
let inboxes: Vec<&Url> = inboxes
.iter()
.filter(|i| i.domain().expect("valid inbox url") != hostname)
outbox: &Url,
recursion_counter: &mut i32,
) -> Result<(), LemmyError> {
- let outbox =
- fetch_remote_object::<OrderedCollection>(context.client(), outbox, recursion_counter).await?;
+ let outbox = fetch_remote_object::<OrderedCollection>(
+ context.client(),
+ &context.settings(),
+ outbox,
+ recursion_counter,
+ )
+ .await?;
let outbox_activities = outbox.items().context(location_info!())?.clone();
let mut outbox_activities = outbox_activities.many().context(location_info!())?;
if outbox_activities.len() > 20 {
recursion_counter: &mut i32,
) -> Result<Vec<Url>, LemmyError> {
if let Some(mods_url) = &group.moderators {
- let mods =
- fetch_remote_object::<OrderedCollection>(context.client(), mods_url, recursion_counter)
- .await?;
+ let mods = fetch_remote_object::<OrderedCollection>(
+ context.client(),
+ &context.settings(),
+ mods_url,
+ recursion_counter,
+ )
+ .await?;
let mods = mods
.items()
.map(|i| i.as_many())
use crate::{check_is_apub_id_valid, APUB_JSON_CONTENT_TYPE};
use anyhow::anyhow;
-use lemmy_utils::{request::retry, LemmyError};
+use lemmy_utils::{request::retry, settings::structs::Settings, LemmyError};
use log::info;
use reqwest::Client;
use serde::Deserialize;
/// timeouts etc.
pub(in crate::fetcher) async fn fetch_remote_object<Response>(
client: &Client,
+ settings: &Settings,
url: &Url,
recursion_counter: &mut i32,
) -> Result<Response, LemmyError>
if *recursion_counter > MAX_REQUEST_NUMBER {
return Err(anyhow!("Maximum recursion depth reached").into());
}
- check_is_apub_id_valid(url, false)?;
+ check_is_apub_id_valid(url, false, settings)?;
let timeout = Duration::from_secs(60);
--- /dev/null
+use crate::{
+ fetcher::fetch::fetch_remote_object,
+ objects::{comment::Note, post::Page, FromApub},
+ PostOrComment,
+};
+use anyhow::anyhow;
+use diesel::result::Error::NotFound;
+use lemmy_api_common::blocking;
+use lemmy_db_queries::{ApubObject, Crud};
+use lemmy_db_schema::source::{comment::Comment, post::Post};
+use lemmy_utils::LemmyError;
+use lemmy_websocket::LemmyContext;
+use log::debug;
+use url::Url;
+
+/// Gets a post by its apub ID. If it exists locally, it is returned directly. Otherwise it is
+/// pulled from its apub ID, inserted and returned.
+///
+/// The parent community is also pulled if necessary. Comments are not pulled.
+pub(crate) async fn get_or_fetch_and_insert_post(
+ post_ap_id: &Url,
+ context: &LemmyContext,
+ recursion_counter: &mut i32,
+) -> Result<Post, LemmyError> {
+ let post_ap_id_owned = post_ap_id.to_owned();
+ let post = blocking(context.pool(), move |conn| {
+ Post::read_from_apub_id(conn, &post_ap_id_owned.into())
+ })
+ .await?;
+
+ match post {
+ Ok(p) => Ok(p),
+ Err(NotFound {}) => {
+ debug!("Fetching and creating remote post: {}", post_ap_id);
+ let page = fetch_remote_object::<Page>(
+ context.client(),
+ &context.settings(),
+ post_ap_id,
+ recursion_counter,
+ )
+ .await?;
+ let post = Post::from_apub(&page, context, post_ap_id, recursion_counter).await?;
+
+ Ok(post)
+ }
+ Err(e) => Err(e.into()),
+ }
+}
+
+/// Gets a comment by its apub ID. If it exists locally, it is returned directly. Otherwise it is
+/// pulled from its apub ID, inserted and returned.
+///
+/// The parent community, post and comment are also pulled if necessary.
+pub(crate) async fn get_or_fetch_and_insert_comment(
+ comment_ap_id: &Url,
+ context: &LemmyContext,
+ recursion_counter: &mut i32,
+) -> Result<Comment, LemmyError> {
+ let comment_ap_id_owned = comment_ap_id.to_owned();
+ let comment = blocking(context.pool(), move |conn| {
+ Comment::read_from_apub_id(conn, &comment_ap_id_owned.into())
+ })
+ .await?;
+
+ match comment {
+ Ok(p) => Ok(p),
+ Err(NotFound {}) => {
+ debug!(
+ "Fetching and creating remote comment and its parents: {}",
+ comment_ap_id
+ );
+ let comment = fetch_remote_object::<Note>(
+ context.client(),
+ &context.settings(),
+ comment_ap_id,
+ recursion_counter,
+ )
+ .await?;
+ let comment = Comment::from_apub(&comment, context, comment_ap_id, recursion_counter).await?;
+
+ let post_id = comment.post_id;
+ let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+ if post.locked {
+ return Err(anyhow!("Post is locked").into());
+ }
+
+ Ok(comment)
+ }
+ Err(e) => Err(e.into()),
+ }
+}
+
+pub(crate) async fn get_or_fetch_and_insert_post_or_comment(
+ ap_id: &Url,
+ context: &LemmyContext,
+ recursion_counter: &mut i32,
+) -> Result<PostOrComment, LemmyError> {
+ Ok(
+ match get_or_fetch_and_insert_post(ap_id, context, recursion_counter).await {
+ Ok(p) => PostOrComment::Post(Box::new(p)),
+ Err(_) => {
+ let c = get_or_fetch_and_insert_comment(ap_id, context, recursion_counter).await?;
+ PostOrComment::Comment(Box::new(c))
+ }
+ },
+ )
+}
--- /dev/null
+use crate::{
+ fetcher::{fetch::fetch_remote_object, is_deleted, should_refetch_actor},
+ objects::{person::Person as ApubPerson, FromApub},
+};
+use anyhow::anyhow;
+use diesel::result::Error::NotFound;
+use lemmy_api_common::blocking;
+use lemmy_db_queries::{source::person::Person_, ApubObject};
+use lemmy_db_schema::source::person::Person;
+use lemmy_utils::LemmyError;
+use lemmy_websocket::LemmyContext;
+use log::debug;
+use url::Url;
+
+/// Get a person from its apub ID.
+///
+/// If it exists locally and `!should_refetch_actor()`, it is returned directly from the database.
+/// Otherwise it is fetched from the remote instance, stored and returned.
+pub(crate) async fn get_or_fetch_and_upsert_person(
+ apub_id: &Url,
+ context: &LemmyContext,
+ recursion_counter: &mut i32,
+) -> Result<Person, LemmyError> {
+ let apub_id_owned = apub_id.to_owned();
+ let person = blocking(context.pool(), move |conn| {
+ Person::read_from_apub_id(conn, &apub_id_owned.into())
+ })
+ .await?;
+
+ match person {
+ // If its older than a day, re-fetch it
+ Ok(u) if !u.local && should_refetch_actor(u.last_refreshed_at) => {
+ debug!("Fetching and updating from remote person: {}", apub_id);
+ let person = fetch_remote_object::<ApubPerson>(
+ context.client(),
+ &context.settings(),
+ apub_id,
+ recursion_counter,
+ )
+ .await;
+
+ if is_deleted(&person) {
+ // TODO: use Person::update_deleted() once implemented
+ blocking(context.pool(), move |conn| {
+ Person::delete_account(conn, u.id)
+ })
+ .await??;
+ return Err(anyhow!("Person was deleted by remote instance").into());
+ } else if person.is_err() {
+ return Ok(u);
+ }
+
+ let person = Person::from_apub(&person?, context, apub_id, recursion_counter).await?;
+
+ let person_id = person.id;
+ blocking(context.pool(), move |conn| {
+ Person::mark_as_updated(conn, person_id)
+ })
+ .await??;
+
+ Ok(person)
+ }
+ Ok(u) => Ok(u),
+ Err(NotFound {}) => {
+ debug!("Fetching and creating remote person: {}", apub_id);
+ let person = fetch_remote_object::<ApubPerson>(
+ context.client(),
+ &context.settings(),
+ apub_id,
+ recursion_counter,
+ )
+ .await?;
+
+ let person = Person::from_apub(&person, context, apub_id, recursion_counter).await?;
+
+ Ok(person)
+ }
+ Err(e) => Err(e.into()),
+ }
+}
// remote actor, use webfinger to resolve url
if name.contains('@') {
let (name, domain) = name.splitn(2, '@').collect_tuple().expect("invalid query");
- webfinger_resolve_actor(name, domain, kind, context.client()).await?
+ webfinger_resolve_actor(
+ name,
+ domain,
+ kind,
+ context.client(),
+ context.settings().get_protocol_string(),
+ )
+ .await?
}
// local actor, read from database and return
else {
use lemmy_apub_lib::{ActivityFields, ActivityHandler};
use lemmy_db_queries::{source::activity::Activity_, DbPool};
use lemmy_db_schema::source::activity::Activity;
-use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
+use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::LemmyContext;
use log::{info, trace};
use serde::{Deserialize, Serialize};
if is_activity_already_known(context.pool(), activity.id_unchecked()).await? {
return Ok(HttpResponse::Ok().finish());
}
- check_is_apub_id_valid(activity.actor(), false)?;
+ check_is_apub_id_valid(activity.actor(), false, &context.settings())?;
info!("Verifying activity {}", activity.id_unchecked().to_string());
activity.verify(context, request_counter).await?;
- assert_activity_not_local(&activity)?;
+ assert_activity_not_local(&activity, &context.settings().hostname)?;
// Log the activity, so we avoid receiving and parsing it twice. Note that this could still happen
// if we receive the same activity twice in very quick succession.
info: web::Path<ActivityQuery>,
context: web::Data<LemmyContext>,
) -> Result<HttpResponse<Body>, LemmyError> {
- let settings = Settings::get();
+ let settings = context.settings();
let activity_id = Url::parse(&format!(
"{}/activities/{}/{}",
settings.get_protocol_and_hostname(),
}
}
-fn assert_activity_not_local<T: Debug + ActivityFields>(activity: &T) -> Result<(), LemmyError> {
+fn assert_activity_not_local<T: Debug + ActivityFields>(
+ activity: &T,
+ hostname: &str,
+) -> Result<(), LemmyError> {
let activity_domain = activity.id_unchecked().domain().context(location_info!())?;
- if activity_domain == Settings::get().hostname {
+ if activity_domain == hostname {
return Err(
anyhow!(
"Error: received activity which was sent by local instance: {:?}",
static APUB_JSON_CONTENT_TYPE_LONG: &str =
"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"";
-pub fn config(cfg: &mut web::ServiceConfig) {
- if Settings::get().federation.enabled {
- println!("federation enabled, host is {}", Settings::get().hostname);
+pub fn config(cfg: &mut web::ServiceConfig, settings: &Settings) {
+ if settings.federation.enabled {
+ println!("federation enabled, host is {}", settings.hostname);
let digest_verifier = VerifyDigest::new(Sha256::new());
let header_guard_accept = guard::Any(guard::Header("Accept", APUB_JSON_CONTENT_TYPE))
pub(crate) fn check_is_apub_id_valid(
apub_id: &Url,
use_strict_allowlist: bool,
+ settings: &Settings,
) -> Result<(), LemmyError> {
- let settings = Settings::get();
let domain = apub_id.domain().context(location_info!())?.to_string();
let local_instance = settings.get_hostname_without_port()?;
return Err(anyhow!("invalid hostname {}: {}", host, apub_id).into());
}
- if apub_id.scheme() != Settings::get().get_protocol_string() {
+ if apub_id.scheme() != settings.get_protocol_string() {
return Err(anyhow!("invalid apub id scheme {}: {}", apub_id.scheme(), apub_id).into());
}
// TODO: might be good to put the part above in one method, and below in another
// (which only gets called in apub::objects)
// -> no that doesnt make sense, we still need the code below for blocklist and strict allowlist
- if let Some(blocked) = Settings::get().federation.blocked_instances {
+ if let Some(blocked) = settings.to_owned().federation.blocked_instances {
if blocked.contains(&domain) {
return Err(anyhow!("{} is in federation blocklist", domain).into());
}
}
- if let Some(mut allowed) = Settings::get().federation.allowed_instances {
+ if let Some(mut allowed) = settings.to_owned().federation.allowed_instances {
// Only check allowlist if this is a community, or strict allowlist is enabled.
- let strict_allowlist = Settings::get().federation.strict_allowlist;
+ let strict_allowlist = settings.to_owned().federation.strict_allowlist;
if use_strict_allowlist || strict_allowlist {
// need to allow this explicitly because apub receive might contain objects from our local
// instance.
#[async_trait::async_trait(?Send)]
pub trait CommunityType {
fn followers_url(&self) -> Url;
- async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError>;
+ async fn get_follower_inboxes(
+ &self,
+ pool: &DbPool,
+ settings: &Settings,
+ ) -> Result<Vec<Url>, LemmyError>;
}
pub enum EndpointType {
pub fn generate_apub_endpoint(
endpoint_type: EndpointType,
name: &str,
+ protocol_and_hostname: &str,
) -> Result<DbUrl, ParseError> {
- generate_apub_endpoint_for_domain(
- endpoint_type,
- name,
- &Settings::get().get_protocol_and_hostname(),
- )
+ generate_apub_endpoint_for_domain(endpoint_type, name, protocol_and_hostname)
}
pub fn generate_followers_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
pub fn build_actor_id_from_shortname(
endpoint_type: EndpointType,
short_name: &str,
+ settings: &Settings,
) -> Result<DbUrl, ParseError> {
let split = short_name.split('@').collect::<Vec<&str>>();
// If there's no @, its local
let domain = if split.len() == 1 {
- Settings::get().get_protocol_and_hostname()
+ settings.get_protocol_and_hostname()
} else {
- format!("{}://{}", Settings::get().get_protocol_string(), split[1])
+ format!("{}://{}", settings.get_protocol_string(), split[1])
};
generate_apub_endpoint_for_domain(endpoint_type, name, &domain)
}
let content = ¬e.source.content;
- let content_slurs_removed = remove_slurs(content);
+ let content_slurs_removed = remove_slurs(content, &context.settings().slur_regex());
let form = CommentForm {
creator_id: creator.id,
source::community::{Community, CommunityForm},
};
use lemmy_utils::{
+ settings::structs::Settings,
utils::{check_slurs, check_slurs_opt, convert_datetime, markdown_to_html},
LemmyError,
};
pub(crate) async fn from_apub_to_form(
group: &Group,
expected_domain: &Url,
+ settings: &Settings,
) -> Result<CommunityForm, LemmyError> {
let actor_id = Some(group.id(expected_domain)?.clone().into());
let name = group.preferred_username.clone();
let description = group.source.clone().map(|s| s.content);
let shared_inbox = group.endpoints.shared_inbox.clone().map(|s| s.into());
- check_slurs(&name)?;
- check_slurs(&title)?;
- check_slurs_opt(&description)?;
+ let slur_regex = &settings.slur_regex();
+ check_slurs(&name, slur_regex)?;
+ check_slurs(&title, slur_regex)?;
+ check_slurs_opt(&description, slur_regex)?;
Ok(CommunityForm {
name,
expected_domain: &Url,
request_counter: &mut i32,
) -> Result<Community, LemmyError> {
- let form = Group::from_apub_to_form(group, expected_domain).await?;
+ let form = Group::from_apub_to_form(group, expected_domain, &context.settings()).await?;
let community = blocking(context.pool(), move |conn| Community::upsert(conn, &form)).await??;
update_community_mods(group, &community, context, request_counter).await?;
UserTypes::Service => true,
};
- check_slurs(&name)?;
- check_slurs_opt(&display_name)?;
- check_slurs_opt(&bio)?;
- check_is_apub_id_valid(&person.id, false)?;
+ let slur_regex = &context.settings().slur_regex();
+ check_slurs(&name, slur_regex)?;
+ check_slurs_opt(&display_name, slur_regex)?;
+ check_slurs_opt(&bio, slur_regex)?;
+
+ check_is_apub_id_valid(&person.id, false, &context.settings())?;
let person_form = PersonForm {
name,
) -> Result<(), LemmyError> {
let community = extract_community(&self.to, context, request_counter).await?;
- check_slurs(&self.name)?;
+ check_slurs(&self.name, &context.settings().slur_regex())?;
verify_domains_match(self.attributed_to.inner(), &self.id)?;
verify_person_in_community(
&self.attributed_to,
let thumbnail_url: Option<Url> = page.image.clone().map(|i| i.url);
let (metadata_res, pictrs_thumbnail) = if let Some(url) = &page.url {
- fetch_site_data(context.client(), Some(url)).await
+ fetch_site_data(context.client(), &context.settings(), Some(url)).await
} else {
(None, thumbnail_url)
};
.map(|u| (u.title, u.description, u.html))
.unwrap_or((None, None, None));
- let body_slurs_removed = page.source.as_ref().map(|s| remove_slurs(&s.content));
+ let body_slurs_removed = page
+ .source
+ .as_ref()
+ .map(|s| remove_slurs(&s.content, &context.settings().slur_regex()));
let form = PostForm {
name: page.name.clone(),
url: page.url.clone().map(|u| u.into()),
use anyhow::anyhow;
use lemmy_utils::{
request::{retry, RecvError},
- settings::structs::Settings,
LemmyError,
};
use log::debug;
domain: &str,
webfinger_type: WebfingerType,
client: &Client,
+ protocol_string: &str,
) -> Result<Url, LemmyError> {
let webfinger_type = match webfinger_type {
WebfingerType::Person => "acct",
};
let fetch_url = format!(
"{}://{}/.well-known/webfinger?resource={}:{}@{}",
- Settings::get().get_protocol_string(),
- domain,
- webfinger_type,
- name,
- domain
+ protocol_string, domain, webfinger_type, name, domain
);
debug!("Fetching webfinger url: {}", &fetch_url);
use diesel::{result::Error, *};
use lemmy_db_schema::source::secret::Secret;
-use lemmy_utils::settings::structs::Settings;
-use std::sync::RwLock;
-use crate::get_database_url_from_env;
-
-lazy_static! {
- static ref SECRET: RwLock<Secret> = RwLock::new(init().expect("Failed to load secrets from DB."));
-}
-
-pub trait SecretSingleton {
- fn get() -> Secret;
+pub trait Secret_ {
+ fn init(conn: &PgConnection) -> Result<Secret, Error>;
}
-impl SecretSingleton for Secret {
- /// Returns the Secret as a struct
- fn get() -> Self {
- SECRET.read().expect("read secrets").to_owned()
+impl Secret_ for Secret {
+ /// Initialize the Secrets from the DB.
+ /// Warning: You should only call this once.
+ fn init(conn: &PgConnection) -> Result<Secret, Error> {
+ read_secrets(conn)
}
}
-/// Reads the secrets from the DB
-fn init() -> Result<Secret, Error> {
- let db_url = match get_database_url_from_env() {
- Ok(url) => url,
- Err(_) => Settings::get().get_database_url(),
- };
-
- let conn = PgConnection::establish(&db_url).expect("Couldn't get DB connection for Secrets.");
- read_secrets(&conn)
-}
-
fn read_secrets(conn: &PgConnection) -> Result<Secret, Error> {
use lemmy_db_schema::schema::secret::dsl::*;
secret.first::<Secret>(conn)
use diesel::PgConnection;
use lemmy_api_common::blocking;
use lemmy_db_queries::{
- source::{community::Community_, person::Person_, secret::SecretSingleton},
+ source::{community::Community_, person::Person_},
Crud,
ListingType,
SortType,
};
use lemmy_db_schema::{
- source::{community::Community, local_user::LocalUser, person::Person, secret::Secret},
+ source::{community::Community, local_user::LocalUser, person::Person},
LocalUserId,
};
use lemmy_db_views::{
site_view::SiteView,
};
use lemmy_db_views_actor::person_mention_view::{PersonMentionQueryBuilder, PersonMentionView};
-use lemmy_utils::{
- claims::Claims,
- settings::structs::Settings,
- utils::markdown_to_html,
- LemmyError,
-};
+use lemmy_utils::{claims::Claims, utils::markdown_to_html, LemmyError};
use lemmy_websocket::LemmyContext;
use rss::{
extension::dublincore::DublinCoreExtensionBuilder,
})
.await??;
- let items = create_post_items(posts)?;
+ let items = create_post_items(posts, &context.settings().get_protocol_and_hostname())?;
let mut channel_builder = ChannelBuilder::default();
channel_builder
site_view.site.name,
listing_type.to_string()
))
- .link(Settings::get().get_protocol_and_hostname())
+ .link(context.settings().get_protocol_and_hostname())
.items(items);
if let Some(site_desc) = site_view.site.description {
_ => return Err(ErrorBadRequest(LemmyError::from(anyhow!("wrong_type")))),
};
+ let jwt_secret = context.secret().jwt_secret.to_owned();
+ let protocol_and_hostname = context.settings().get_protocol_and_hostname();
+
let builder = blocking(context.pool(), move |conn| match request_type {
- RequestType::User => get_feed_user(conn, &sort_type, param),
- RequestType::Community => get_feed_community(conn, &sort_type, param),
- RequestType::Front => get_feed_front(conn, &sort_type, param),
- RequestType::Inbox => get_feed_inbox(conn, param),
+ RequestType::User => get_feed_user(conn, &sort_type, ¶m, &protocol_and_hostname),
+ RequestType::Community => get_feed_community(conn, &sort_type, ¶m, &protocol_and_hostname),
+ RequestType::Front => get_feed_front(
+ conn,
+ &jwt_secret,
+ &sort_type,
+ ¶m,
+ &protocol_and_hostname,
+ ),
+ RequestType::Inbox => get_feed_inbox(conn, &jwt_secret, ¶m, &protocol_and_hostname),
})
.await?
.map_err(ErrorBadRequest)?;
fn get_feed_user(
conn: &PgConnection,
sort_type: &SortType,
- user_name: String,
+ user_name: &str,
+ protocol_and_hostname: &str,
) -> Result<ChannelBuilder, LemmyError> {
let site_view = SiteView::read(conn)?;
- let person = Person::find_by_name(conn, &user_name)?;
+ let person = Person::find_by_name(conn, user_name)?;
let posts = PostQueryBuilder::create(conn)
.listing_type(ListingType::All)
.creator_id(person.id)
.list()?;
- let items = create_post_items(posts)?;
+ let items = create_post_items(posts, protocol_and_hostname)?;
let mut channel_builder = ChannelBuilder::default();
channel_builder
fn get_feed_community(
conn: &PgConnection,
sort_type: &SortType,
- community_name: String,
+ community_name: &str,
+ protocol_and_hostname: &str,
) -> Result<ChannelBuilder, LemmyError> {
let site_view = SiteView::read(conn)?;
- let community = Community::read_from_name(conn, &community_name)?;
+ let community = Community::read_from_name(conn, community_name)?;
let posts = PostQueryBuilder::create(conn)
.listing_type(ListingType::All)
.community_id(community.id)
.list()?;
- let items = create_post_items(posts)?;
+ let items = create_post_items(posts, protocol_and_hostname)?;
let mut channel_builder = ChannelBuilder::default();
channel_builder
fn get_feed_front(
conn: &PgConnection,
+ jwt_secret: &str,
sort_type: &SortType,
- jwt: String,
+ jwt: &str,
+ protocol_and_hostname: &str,
) -> Result<ChannelBuilder, LemmyError> {
let site_view = SiteView::read(conn)?;
- let jwt_secret = Secret::get().jwt_secret;
- let local_user_id = LocalUserId(Claims::decode(&jwt, &jwt_secret)?.claims.sub);
+ let local_user_id = LocalUserId(Claims::decode(jwt, jwt_secret)?.claims.sub);
let local_user = LocalUser::read(conn, local_user_id)?;
let posts = PostQueryBuilder::create(conn)
.sort(*sort_type)
.list()?;
- let items = create_post_items(posts)?;
+ let items = create_post_items(posts, protocol_and_hostname)?;
let mut channel_builder = ChannelBuilder::default();
channel_builder
.namespaces(RSS_NAMESPACE.to_owned())
.title(&format!("{} - Subscribed", site_view.site.name))
- .link(Settings::get().get_protocol_and_hostname())
+ .link(protocol_and_hostname)
.items(items);
if let Some(site_desc) = site_view.site.description {
Ok(channel_builder)
}
-fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, LemmyError> {
+fn get_feed_inbox(
+ conn: &PgConnection,
+ jwt_secret: &str,
+ jwt: &str,
+ protocol_and_hostname: &str,
+) -> Result<ChannelBuilder, LemmyError> {
let site_view = SiteView::read(conn)?;
- let jwt_secret = Secret::get().jwt_secret;
- let local_user_id = LocalUserId(Claims::decode(&jwt, &jwt_secret)?.claims.sub);
+ let local_user_id = LocalUserId(Claims::decode(jwt, jwt_secret)?.claims.sub);
let local_user = LocalUser::read(conn, local_user_id)?;
let person_id = local_user.person_id;
let show_bot_accounts = local_user.show_bot_accounts;
.sort(sort)
.list()?;
- let items = create_reply_and_mention_items(replies, mentions)?;
+ let items = create_reply_and_mention_items(replies, mentions, protocol_and_hostname)?;
let mut channel_builder = ChannelBuilder::default();
channel_builder
.namespaces(RSS_NAMESPACE.to_owned())
.title(&format!("{} - Inbox", site_view.site.name))
- .link(format!(
- "{}/inbox",
- Settings::get().get_protocol_and_hostname()
- ))
+ .link(format!("{}/inbox", protocol_and_hostname,))
.items(items);
if let Some(site_desc) = site_view.site.description {
fn create_reply_and_mention_items(
replies: Vec<CommentView>,
mentions: Vec<PersonMentionView>,
+ protocol_and_hostname: &str,
) -> Result<Vec<Item>, LemmyError> {
let mut reply_items: Vec<Item> = replies
.iter()
.map(|r| {
let reply_url = format!(
"{}/post/{}/comment/{}",
- Settings::get().get_protocol_and_hostname(),
- r.post.id,
- r.comment.id
+ protocol_and_hostname, r.post.id, r.comment.id
);
build_item(
&r.creator.name,
&r.comment.published,
&reply_url,
&r.comment.content,
+ protocol_and_hostname,
)
})
.collect::<Result<Vec<Item>, LemmyError>>()?;
.map(|m| {
let mention_url = format!(
"{}/post/{}/comment/{}",
- Settings::get().get_protocol_and_hostname(),
- m.post.id,
- m.comment.id
+ protocol_and_hostname, m.post.id, m.comment.id
);
build_item(
&m.creator.name,
&m.comment.published,
&mention_url,
&m.comment.content,
+ protocol_and_hostname,
)
})
.collect::<Result<Vec<Item>, LemmyError>>()?;
published: &NaiveDateTime,
url: &str,
content: &str,
+ protocol_and_hostname: &str,
) -> Result<Item, LemmyError> {
let mut i = ItemBuilder::default();
i.title(format!("Reply from {}", creator_name));
- let author_url = format!(
- "{}/u/{}",
- Settings::get().get_protocol_and_hostname(),
- creator_name
- );
+ let author_url = format!("{}/u/{}", protocol_and_hostname, creator_name);
i.author(format!(
"/u/{} <a href=\"{}\">(link)</a>",
creator_name, author_url
Ok(i.build().map_err(|e| anyhow!(e))?)
}
-fn create_post_items(posts: Vec<PostView>) -> Result<Vec<Item>, LemmyError> {
+fn create_post_items(
+ posts: Vec<PostView>,
+ protocol_and_hostname: &str,
+) -> Result<Vec<Item>, LemmyError> {
let mut items: Vec<Item> = Vec::new();
for p in posts {
let dt = DateTime::<Utc>::from_utc(p.post.published, Utc);
i.pub_date(dt.to_rfc2822());
- let post_url = format!(
- "{}/post/{}",
- Settings::get().get_protocol_and_hostname(),
- p.post.id
- );
+ let post_url = format!("{}/post/{}", protocol_and_hostname, p.post.id);
i.link(post_url.to_owned());
i.comments(post_url.to_owned());
let guid = GuidBuilder::default()
.map_err(|e| anyhow!(e))?;
i.guid(guid);
- let community_url = format!(
- "{}/c/{}",
- Settings::get().get_protocol_and_hostname(),
- p.community.name
- );
+ let community_url = format!("{}/c/{}", protocol_and_hostname, p.community.name);
// TODO add images
let mut description = format!("submitted by <a href=\"{}\">{}</a> to <a href=\"{}\">{}</a><br>{} points | <a href=\"{}\">{} comments</a>",
use actix_web::{body::BodyStream, http::StatusCode, web::Data, *};
use anyhow::anyhow;
use awc::Client;
-use lemmy_db_queries::source::secret::SecretSingleton;
-use lemmy_db_schema::source::secret::Secret;
-use lemmy_utils::{claims::Claims, rate_limit::RateLimit, settings::structs::Settings, LemmyError};
+use lemmy_utils::{claims::Claims, rate_limit::RateLimit, LemmyError};
+use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
use std::time::Duration;
req: HttpRequest,
body: web::Payload,
client: web::Data<Client>,
+ context: web::Data<LemmyContext>,
) -> Result<HttpResponse, Error> {
// TODO: check rate limit here
let jwt = req
.cookie("jwt")
.expect("No auth header for picture upload");
- let jwt_secret = Secret::get().jwt_secret;
- if Claims::decode(jwt.value(), &jwt_secret).is_err() {
+ if Claims::decode(jwt.value(), &context.secret().jwt_secret).is_err() {
return Ok(HttpResponse::Unauthorized().finish());
};
- let mut client_req = client.request_from(format!("{}/image", pictrs_url()?), req.head());
+ let mut client_req = client.request_from(
+ format!("{}/image", pictrs_url(context.settings().pictrs_url)?),
+ req.head(),
+ );
// remove content-encoding header so that pictrs doesnt send gzipped response
client_req.headers_mut().remove(ACCEPT_ENCODING);
web::Query(params): web::Query<PictrsParams>,
req: HttpRequest,
client: web::Data<Client>,
+ context: web::Data<LemmyContext>,
) -> Result<HttpResponse, Error> {
let name = &filename.into_inner();
// If there are no query params, the URL is original
+ let pictrs_url_settings = context.settings().pictrs_url;
let url = if params.format.is_none() && params.thumbnail.is_none() {
- format!("{}/image/original/{}", pictrs_url()?, name,)
+ format!(
+ "{}/image/original/{}",
+ pictrs_url(pictrs_url_settings)?,
+ name,
+ )
} else {
// Use jpg as a default when none is given
let format = params.format.unwrap_or_else(|| "jpg".to_string());
- let mut url = format!("{}/image/process.{}?src={}", pictrs_url()?, format, name,);
+ let mut url = format!(
+ "{}/image/process.{}?src={}",
+ pictrs_url(pictrs_url_settings)?,
+ format,
+ name,
+ );
if let Some(size) = params.thumbnail {
url = format!("{}&thumbnail={}", url, size,);
components: web::Path<(String, String)>,
req: HttpRequest,
client: web::Data<Client>,
+ context: web::Data<LemmyContext>,
) -> Result<HttpResponse, Error> {
let (token, file) = components.into_inner();
- let url = format!("{}/image/delete/{}/{}", pictrs_url()?, &token, &file);
+ let url = format!(
+ "{}/image/delete/{}/{}",
+ pictrs_url(context.settings().pictrs_url)?,
+ &token,
+ &file
+ );
let mut client_req = client.request_from(url, req.head());
client_req.headers_mut().remove(ACCEPT_ENCODING);
Ok(HttpResponse::build(res.status()).body(BodyStream::new(res)))
}
-fn pictrs_url() -> Result<String, LemmyError> {
- Settings::get()
- .pictrs_url
- .ok_or_else(|| anyhow!("images_disabled").into())
+fn pictrs_url(pictrs_url: Option<String>) -> Result<String, LemmyError> {
+ pictrs_url.ok_or_else(|| anyhow!("images_disabled").into())
}
use anyhow::anyhow;
use lemmy_api_common::blocking;
use lemmy_db_views::site_view::SiteView;
-use lemmy_utils::{settings::structs::Settings, version, LemmyError};
+use lemmy_utils::{version, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
use url::Url;
.route("/.well-known/nodeinfo", web::get().to(node_info_well_known));
}
-async fn node_info_well_known() -> Result<HttpResponse<Body>, LemmyError> {
+async fn node_info_well_known(
+ context: web::Data<LemmyContext>,
+) -> Result<HttpResponse<Body>, LemmyError> {
let node_info = NodeInfoWellKnown {
links: NodeInfoWellKnownLinks {
rel: Url::parse("http://nodeinfo.diaspora.software/ns/schema/2.0")?,
href: Url::parse(&format!(
"{}/nodeinfo/2.0.json",
- Settings::get().get_protocol_and_hostname()
+ &context.settings().get_protocol_and_hostname(),
))?,
},
};
.await?
.map_err(|_| ErrorBadRequest(LemmyError::from(anyhow!("not_found"))))?;
- let protocols = if Settings::get().federation.enabled {
+ let protocols = if context.settings().federation.enabled {
vec!["activitypub".to_string()]
} else {
vec![]
use lemmy_apub_lib::webfinger::{WebfingerLink, WebfingerResponse};
use lemmy_db_queries::source::{community::Community_, person::Person_};
use lemmy_db_schema::source::{community::Community, person::Person};
-use lemmy_utils::{
- settings::structs::Settings,
- LemmyError,
- WEBFINGER_COMMUNITY_REGEX,
- WEBFINGER_USERNAME_REGEX,
-};
+use lemmy_utils::{settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::Deserialize;
resource: String,
}
-pub fn config(cfg: &mut web::ServiceConfig) {
- if Settings::get().federation.enabled {
+pub fn config(cfg: &mut web::ServiceConfig, settings: &Settings) {
+ if settings.federation.enabled {
cfg.route(
".well-known/webfinger",
web::get().to(get_webfinger_response),
info: Query<Params>,
context: web::Data<LemmyContext>,
) -> Result<HttpResponse, Error> {
- let community_regex_parsed = WEBFINGER_COMMUNITY_REGEX
+ let community_regex_parsed = context
+ .settings()
+ .webfinger_community_regex()
.captures(&info.resource)
.map(|c| c.get(1))
.flatten();
- let username_regex_parsed = WEBFINGER_USERNAME_REGEX
+ let username_regex_parsed = context
+ .settings()
+ .webfinger_username_regex()
.captures(&info.resource)
.map(|c| c.get(1))
.flatten();
-use crate::{settings::structs::Settings, LemmyError};
+use crate::LemmyError;
use chrono::Utc;
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, TokenData, Validation};
use serde::{Deserialize, Serialize};
Ok(decode::<Claims>(jwt, &key, &v)?)
}
- pub fn jwt(local_user_id: i32, jwt_secret: &str) -> Result<Jwt, LemmyError> {
+ pub fn jwt(local_user_id: i32, jwt_secret: &str, hostname: &str) -> Result<Jwt, LemmyError> {
let my_claims = Claims {
sub: local_user_id,
- iss: Settings::get().hostname,
+ iss: hostname.to_string(),
iat: Utc::now().timestamp(),
};
to_email: &str,
to_username: &str,
html: &str,
+ settings: &Settings,
) -> Result<(), String> {
- let email_config = Settings::get().email.ok_or("no_email_setup")?;
- let domain = Settings::get().hostname;
+ let email_config = settings.email.to_owned().ok_or("no_email_setup")?;
+ let domain = settings.hostname.to_owned();
let (smtp_server, smtp_port) = {
let email_and_port = email_config.smtp_server.split(':').collect::<Vec<&str>>();
pub mod utils;
pub mod version;
-use crate::settings::structs::Settings;
use http::StatusCode;
-use regex::Regex;
+
use std::fmt;
use thiserror::Error;
}
}
}
-
-lazy_static! {
- pub static ref WEBFINGER_COMMUNITY_REGEX: Regex = Regex::new(&format!(
- "^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,}})@{}$",
- Settings::get().hostname
- ))
- .expect("compile webfinger regex");
-}
-use crate::{
- settings::structs::{RateLimitConfig, Settings},
- utils::get_ip,
- IpAddr,
- LemmyError,
-};
+use crate::{settings::structs::RateLimitConfig, utils::get_ip, IpAddr, LemmyError};
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
use futures::future::{ok, Ready};
use rate_limiter::{RateLimitType, RateLimiter};
// it might be reasonable to use a std::sync::Mutex here, since we don't need to lock this
// across await points
pub rate_limiter: Arc<Mutex<RateLimiter>>,
+ pub rate_limit_config: RateLimitConfig,
}
#[derive(Debug, Clone)]
pub struct RateLimited {
rate_limiter: Arc<Mutex<RateLimiter>>,
+ rate_limit_config: RateLimitConfig,
type_: RateLimitType,
}
fn kind(&self, type_: RateLimitType) -> RateLimited {
RateLimited {
rate_limiter: self.rate_limiter.clone(),
+ rate_limit_config: self.rate_limit_config.clone(),
type_,
}
}
{
// Does not need to be blocking because the RwLock in settings never held across await points,
// and the operation here locks only long enough to clone
- let rate_limit: RateLimitConfig = Settings::get().rate_limit.unwrap_or_default();
+ let rate_limit = self.rate_limit_config;
// before
{
pub(crate) async fn fetch_pictrs(
client: &Client,
+ settings: &Settings,
image_url: &Url,
) -> Result<PictrsResponse, LemmyError> {
- if let Some(pictrs_url) = Settings::get().pictrs_url {
+ if let Some(pictrs_url) = settings.pictrs_url.to_owned() {
is_image_content_type(client, image_url).await?;
let fetch_url = format!(
/// Returns the SiteMetadata, and a Pictrs URL, if there is a picture associated
pub async fn fetch_site_data(
client: &Client,
+ settings: &Settings,
url: Option<&Url>,
) -> (Option<SiteMetadata>, Option<Url>) {
match &url {
Some(metadata_res) => match &metadata_res.image {
// Metadata, with image
// Try to generate a small thumbnail if there's a full sized one from post-links
- Some(metadata_image) => fetch_pictrs(client, metadata_image)
+ Some(metadata_image) => fetch_pictrs(client, settings, metadata_image)
.await
.map(|r| r.files[0].file.to_owned()),
// Metadata, but no image
- None => fetch_pictrs(client, url)
+ None => fetch_pictrs(client, settings, url)
.await
.map(|r| r.files[0].file.to_owned()),
},
// No metadata, try to fetch the URL as an image
- None => fetch_pictrs(client, url)
+ None => fetch_pictrs(client, settings, url)
.await
.map(|r| r.files[0].file.to_owned()),
};
.map(|p| {
Url::parse(&format!(
"{}/pictrs/image/{}",
- Settings::get().get_protocol_and_hostname(),
+ settings.get_protocol_and_hostname(),
p
))
.ok()
use crate::{location_info, settings::structs::Settings, LemmyError};
use anyhow::{anyhow, Context};
use deser_hjson::from_str;
+use regex::{Regex, RegexBuilder};
use std::{env, fs, io::Error, sync::RwLock};
pub mod structs;
///
/// Note: The env var `LEMMY_DATABASE_URL` is parsed in
/// `lemmy_db_queries/src/lib.rs::get_database_url_from_env()`
- fn init() -> Result<Self, LemmyError> {
+ /// Warning: Only call this once.
+ pub fn init() -> Result<Self, LemmyError> {
// Read the config file
- let config = from_str::<Settings>(&Self::read_config_file()?)?;
+ let mut config = from_str::<Settings>(&Self::read_config_file()?)?;
if config.hostname == "unset" {
return Err(anyhow!("Hostname variable is not set!").into());
}
+ // Initialize the regexes
+ config.webfinger_community_regex = Some(
+ Regex::new(&format!("^group:([a-z0-9_]{{3,}})@{}$", config.hostname))
+ .expect("compile webfinger regex"),
+ );
+ config.webfinger_username_regex = Some(
+ Regex::new(&format!("^acct:([a-z0-9_]{{3,}})@{}$", config.hostname))
+ .expect("compile webfinger regex"),
+ );
+
Ok(config)
}
Ok(Self::read_config_file()?)
}
+
+ pub fn webfinger_community_regex(&self) -> Regex {
+ self
+ .webfinger_community_regex
+ .to_owned()
+ .expect("compile webfinger regex")
+ }
+
+ pub fn webfinger_username_regex(&self) -> Regex {
+ self
+ .webfinger_username_regex
+ .to_owned()
+ .expect("compile webfinger regex")
+ }
+
+ pub fn slur_regex(&self) -> Regex {
+ let mut slurs = r"(fag(g|got|tard)?\b|cock\s?sucker(s|ing)?|ni((g{2,}|q)+|[gq]{2,})[e3r]+(s|z)?|mudslime?s?|kikes?|\bspi(c|k)s?\b|\bchinks?|gooks?|bitch(es|ing|y)?|whor(es?|ing)|\btr(a|@)nn?(y|ies?)|\b(b|re|r)tard(ed)?s?)".to_string();
+ if let Some(additional_slurs) = &self.additional_slurs {
+ slurs.push('|');
+ slurs.push_str(additional_slurs);
+ };
+ RegexBuilder::new(&slurs)
+ .case_insensitive(true)
+ .build()
+ .expect("compile regex")
+ }
}
+use regex::Regex;
use serde::Deserialize;
use std::net::{IpAddr, Ipv4Addr};
pub additional_slurs: Option<String>,
#[default(20)]
pub actor_name_max_length: usize,
+ #[default(None)]
+ #[serde(skip)]
+ pub webfinger_community_regex: Option<Regex>,
+ #[default(None)]
+ #[serde(skip)]
+ pub webfinger_username_regex: Option<Regex>,
}
#[derive(Debug, Deserialize, Clone, SmartDefault)]
-use crate::utils::{
- is_valid_actor_name,
- is_valid_display_name,
- is_valid_matrix_id,
- is_valid_post_title,
- remove_slurs,
- scrape_text_for_mentions,
- slur_check,
- slurs_vec_to_str,
+use crate::{
+ settings::structs::Settings,
+ utils::{
+ is_valid_actor_name,
+ is_valid_display_name,
+ is_valid_matrix_id,
+ is_valid_post_title,
+ remove_slurs,
+ scrape_text_for_mentions,
+ slur_check,
+ slurs_vec_to_str,
+ },
};
#[test]
#[test]
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(""));
+ let actor_name_max_length = Settings::init().unwrap().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("Hello-98", actor_name_max_length));
+ assert!(!is_valid_actor_name("a", actor_name_max_length));
+ assert!(!is_valid_actor_name("", actor_name_max_length));
}
#[test]
fn test_valid_display_name() {
- assert!(is_valid_display_name("hello @there"));
- assert!(!is_valid_display_name("@hello there"));
+ let actor_name_max_length = Settings::init().unwrap().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
+ ));
// Make sure zero-space with an @ doesn't work
- assert!(!is_valid_display_name(&format!(
- "{}@my name is",
- '\u{200b}'
- )));
+ assert!(!is_valid_display_name(
+ &format!("{}@my name is", '\u{200b}'),
+ actor_name_max_length
+ ));
}
#[test]
#[test]
fn test_slur_filter() {
+ let slur_regex = Settings::init().unwrap().slur_regex();
let test =
"faggot test kike tranny cocksucker retardeds. Capitalized Niggerz. This is a bunch of other safe text.";
let slur_free = "No slurs here";
assert_eq!(
- remove_slurs(test),
+ remove_slurs(test, &slur_regex),
"*removed* test *removed* *removed* *removed* *removed*. Capitalized *removed*. This is a bunch of other safe text."
.to_string()
);
];
let has_slurs_err_str = "No slurs - Niggerz, cocksucker, faggot, kike, retardeds, tranny";
- assert_eq!(slur_check(test), Err(has_slurs_vec));
- assert_eq!(slur_check(slur_free), Ok(()));
- if let Err(slur_vec) = slur_check(test) {
+ assert_eq!(slur_check(test, &slur_regex), Err(has_slurs_vec));
+ assert_eq!(slur_check(slur_free, &slur_regex), Ok(()));
+ if let Err(slur_vec) = slur_check(test, &slur_regex) {
assert_eq!(&slurs_vec_to_str(slur_vec), has_slurs_err_str);
}
}
-use crate::{settings::structs::Settings, ApiError, IpAddr};
+use crate::{ApiError, IpAddr};
use actix_web::dev::ConnectionInfo;
use chrono::{DateTime, FixedOffset, NaiveDateTime};
use itertools::Itertools;
use rand::{distributions::Alphanumeric, thread_rng, Rng};
-use regex::{Regex, RegexBuilder};
+use regex::Regex;
use url::Url;
lazy_static! {
static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").expect("compile regex");
- static ref SLUR_REGEX: Regex = {
- let mut slurs = r"(fag(g|got|tard)?\b|cock\s?sucker(s|ing)?|ni((g{2,}|q)+|[gq]{2,})[e3r]+(s|z)?|mudslime?s?|kikes?|\bspi(c|k)s?\b|\bchinks?|gooks?|bitch(es|ing|y)?|whor(es?|ing)|\btr(a|@)nn?(y|ies?)|\b(b|re|r)tard(ed)?s?)".to_string();
- if let Some(additional_slurs) = Settings::get().additional_slurs {
- slurs.push('|');
- slurs.push_str(&additional_slurs);
- };
- RegexBuilder::new(&slurs).case_insensitive(true).build().expect("compile regex")
- };
-
static ref USERNAME_MATCHES_REGEX: Regex = Regex::new(r"/u/[a-zA-Z][0-9a-zA-Z_]*").expect("compile regex");
// TODO keep this old one, it didn't work with port well tho
DateTime::<FixedOffset>::from_utc(datetime, FixedOffset::east(0))
}
-pub fn remove_slurs(test: &str) -> String {
- SLUR_REGEX.replace_all(test, "*removed*").to_string()
+pub fn remove_slurs(test: &str, slur_regex: &Regex) -> String {
+ slur_regex.replace_all(test, "*removed*").to_string()
}
-pub(crate) fn slur_check(test: &str) -> Result<(), Vec<&str>> {
- let mut matches: Vec<&str> = SLUR_REGEX.find_iter(test).map(|mat| mat.as_str()).collect();
+pub(crate) fn slur_check<'a>(test: &'a str, slur_regex: &'a Regex) -> Result<(), Vec<&'a str>> {
+ let mut matches: Vec<&str> = slur_regex.find_iter(test).map(|mat| mat.as_str()).collect();
// Unique
matches.sort_unstable();
}
}
-pub fn check_slurs(text: &str) -> Result<(), ApiError> {
- if let Err(slurs) = slur_check(text) {
+pub fn check_slurs(text: &str, slur_regex: &Regex) -> Result<(), ApiError> {
+ if let Err(slurs) = slur_check(text, slur_regex) {
Err(ApiError::err(&slurs_vec_to_str(slurs)))
} else {
Ok(())
}
}
-pub fn check_slurs_opt(text: &Option<String>) -> Result<(), ApiError> {
+pub fn check_slurs_opt(text: &Option<String>, slur_regex: &Regex) -> Result<(), ApiError> {
match text {
- Some(t) => check_slurs(t),
+ Some(t) => check_slurs(t, slur_regex),
None => Ok(()),
}
}
}
impl MentionData {
- pub fn is_local(&self) -> bool {
- Settings::get().hostname.eq(&self.domain)
+ pub fn is_local(&self, hostname: &str) -> bool {
+ hostname.eq(&self.domain)
}
pub fn full_name(&self) -> String {
format!("@{}@{}", &self.name, &self.domain)
out.into_iter().unique().collect()
}
-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)
+pub fn is_valid_actor_name(name: &str, actor_name_max_length: usize) -> bool {
+ name.chars().count() <= actor_name_max_length && VALID_ACTOR_NAME_REGEX.is_match(name)
}
// Can't do a regex here, reverse lookarounds not supported
-pub fn is_valid_display_name(name: &str) -> bool {
+pub fn is_valid_display_name(name: &str, actor_name_max_length: usize) -> bool {
!name.starts_with('@')
&& !name.starts_with('\u{200b}')
&& name.chars().count() >= 3
- && name.chars().count() <= Settings::get().actor_name_max_length
+ && name.chars().count() <= actor_name_max_length
}
pub fn is_valid_matrix_id(matrix_id: &str) -> bool {
PgConnection,
};
use lemmy_api_common::{comment::*, post::*};
-use lemmy_db_schema::{CommunityId, LocalUserId, PostId};
+use lemmy_db_schema::{source::secret::Secret, CommunityId, LocalUserId, PostId};
use lemmy_utils::{
location_info,
rate_limit::RateLimit,
+ settings::structs::Settings,
ApiError,
ConnectionId,
IpAddr,
/// The DB Pool
pub(super) pool: Pool<ConnectionManager<PgConnection>>,
+ /// The Settings
+ pub(super) settings: Settings,
+
+ /// The Secrets
+ pub(super) secret: Secret,
+
/// Rate limiting based on rate type and IP addr
pub(super) rate_limiter: RateLimit,
/// And manages available rooms. Peers send messages to other peers in same
/// room through `ChatServer`.
impl ChatServer {
+ #![allow(clippy::too_many_arguments)]
pub fn startup(
pool: Pool<ConnectionManager<PgConnection>>,
rate_limiter: RateLimit,
message_handler_crud: MessageHandlerCrudType,
client: Client,
activity_queue: QueueHandle,
+ settings: Settings,
+ secret: Secret,
) -> ChatServer {
ChatServer {
sessions: HashMap::new(),
message_handler_crud,
client,
activity_queue,
+ settings,
+ secret,
}
}
chat_server: ctx.address(),
client: self.client.to_owned(),
activity_queue: self.activity_queue.to_owned(),
+ settings: self.settings.to_owned(),
+ secret: self.secret.to_owned(),
};
let message_handler_crud = self.message_handler_crud;
let message_handler = self.message_handler;
use actix::Addr;
use background_jobs::QueueHandle;
use lemmy_db_queries::DbPool;
-use lemmy_utils::LemmyError;
+use lemmy_db_schema::source::secret::Secret;
+use lemmy_utils::{settings::structs::Settings, LemmyError};
use reqwest::Client;
use serde::Serialize;
pub chat_server: Addr<ChatServer>,
pub client: Client,
pub activity_queue: QueueHandle,
+ pub settings: Settings,
+ pub secret: Secret,
}
impl LemmyContext {
chat_server: Addr<ChatServer>,
client: Client,
activity_queue: QueueHandle,
+ settings: Settings,
+ secret: Secret,
) -> LemmyContext {
LemmyContext {
pool,
chat_server,
client,
activity_queue,
+ settings,
+ secret,
}
}
pub fn pool(&self) -> &DbPool {
pub fn activity_queue(&self) -> &QueueHandle {
&self.activity_queue
}
+ pub fn settings(&self) -> Settings {
+ // TODO hacky solution to be able to hotload the settings.
+ Settings::get()
+ }
+ pub fn secret(&self) -> &Secret {
+ &self.secret
+ }
}
impl Clone for LemmyContext {
chat_server: self.chat_server.clone(),
client: self.client.clone(),
activity_queue: self.activity_queue.clone(),
+ settings: self.settings.clone(),
+ secret: self.secret.clone(),
}
}
}
private_message::PrivateMessage,
},
};
-use lemmy_utils::{apub::generate_actor_keypair, settings::structs::Settings, LemmyError};
+use lemmy_utils::{apub::generate_actor_keypair, LemmyError};
use log::info;
-pub fn run_advanced_migrations(conn: &PgConnection) -> Result<(), LemmyError> {
- user_updates_2020_04_02(conn)?;
- community_updates_2020_04_02(conn)?;
- post_updates_2020_04_03(conn)?;
- comment_updates_2020_04_03(conn)?;
- private_message_updates_2020_05_05(conn)?;
- post_thumbnail_url_updates_2020_07_27(conn)?;
+pub fn run_advanced_migrations(
+ conn: &PgConnection,
+ protocol_and_hostname: &str,
+) -> Result<(), LemmyError> {
+ user_updates_2020_04_02(conn, protocol_and_hostname)?;
+ community_updates_2020_04_02(conn, protocol_and_hostname)?;
+ post_updates_2020_04_03(conn, protocol_and_hostname)?;
+ comment_updates_2020_04_03(conn, protocol_and_hostname)?;
+ private_message_updates_2020_05_05(conn, protocol_and_hostname)?;
+ post_thumbnail_url_updates_2020_07_27(conn, protocol_and_hostname)?;
apub_columns_2021_02_02(conn)?;
Ok(())
}
-fn user_updates_2020_04_02(conn: &PgConnection) -> Result<(), LemmyError> {
+fn user_updates_2020_04_02(
+ conn: &PgConnection,
+ protocol_and_hostname: &str,
+) -> Result<(), LemmyError> {
use lemmy_db_schema::schema::person::dsl::*;
info!("Running user_updates_2020_04_02");
let form = PersonForm {
name: cperson.name.to_owned(),
- actor_id: Some(generate_apub_endpoint(EndpointType::Person, &cperson.name)?),
+ actor_id: Some(generate_apub_endpoint(
+ EndpointType::Person,
+ &cperson.name,
+ protocol_and_hostname,
+ )?),
private_key: Some(Some(keypair.private_key)),
public_key: Some(Some(keypair.public_key)),
last_refreshed_at: Some(naive_now()),
Ok(())
}
-fn community_updates_2020_04_02(conn: &PgConnection) -> Result<(), LemmyError> {
+fn community_updates_2020_04_02(
+ conn: &PgConnection,
+ protocol_and_hostname: &str,
+) -> Result<(), LemmyError> {
use lemmy_db_schema::schema::community::dsl::*;
info!("Running community_updates_2020_04_02");
for ccommunity in &incorrect_communities {
let keypair = generate_actor_keypair()?;
- let community_actor_id = generate_apub_endpoint(EndpointType::Community, &ccommunity.name)?;
+ let community_actor_id = generate_apub_endpoint(
+ EndpointType::Community,
+ &ccommunity.name,
+ protocol_and_hostname,
+ )?;
let form = CommunityForm {
name: ccommunity.name.to_owned(),
Ok(())
}
-fn post_updates_2020_04_03(conn: &PgConnection) -> Result<(), LemmyError> {
+fn post_updates_2020_04_03(
+ conn: &PgConnection,
+ protocol_and_hostname: &str,
+) -> Result<(), LemmyError> {
use lemmy_db_schema::schema::post::dsl::*;
info!("Running post_updates_2020_04_03");
.load::<Post>(conn)?;
for cpost in &incorrect_posts {
- let apub_id = generate_apub_endpoint(EndpointType::Post, &cpost.id.to_string())?;
+ let apub_id = generate_apub_endpoint(
+ EndpointType::Post,
+ &cpost.id.to_string(),
+ protocol_and_hostname,
+ )?;
Post::update_ap_id(conn, cpost.id, apub_id)?;
}
Ok(())
}
-fn comment_updates_2020_04_03(conn: &PgConnection) -> Result<(), LemmyError> {
+fn comment_updates_2020_04_03(
+ conn: &PgConnection,
+ protocol_and_hostname: &str,
+) -> Result<(), LemmyError> {
use lemmy_db_schema::schema::comment::dsl::*;
info!("Running comment_updates_2020_04_03");
.load::<Comment>(conn)?;
for ccomment in &incorrect_comments {
- let apub_id = generate_apub_endpoint(EndpointType::Comment, &ccomment.id.to_string())?;
+ let apub_id = generate_apub_endpoint(
+ EndpointType::Comment,
+ &ccomment.id.to_string(),
+ protocol_and_hostname,
+ )?;
Comment::update_ap_id(conn, ccomment.id, apub_id)?;
}
Ok(())
}
-fn private_message_updates_2020_05_05(conn: &PgConnection) -> Result<(), LemmyError> {
+fn private_message_updates_2020_05_05(
+ conn: &PgConnection,
+ protocol_and_hostname: &str,
+) -> Result<(), LemmyError> {
use lemmy_db_schema::schema::private_message::dsl::*;
info!("Running private_message_updates_2020_05_05");
.load::<PrivateMessage>(conn)?;
for cpm in &incorrect_pms {
- let apub_id = generate_apub_endpoint(EndpointType::PrivateMessage, &cpm.id.to_string())?;
+ let apub_id = generate_apub_endpoint(
+ EndpointType::PrivateMessage,
+ &cpm.id.to_string(),
+ protocol_and_hostname,
+ )?;
PrivateMessage::update_ap_id(conn, cpm.id, apub_id)?;
}
Ok(())
}
-fn post_thumbnail_url_updates_2020_07_27(conn: &PgConnection) -> Result<(), LemmyError> {
+fn post_thumbnail_url_updates_2020_07_27(
+ conn: &PgConnection,
+ protocol_and_hostname: &str,
+) -> Result<(), LemmyError> {
use lemmy_db_schema::schema::post::dsl::*;
info!("Running post_thumbnail_url_updates_2020_07_27");
- let domain_prefix = format!(
- "{}/pictrs/image/",
- Settings::get().get_protocol_and_hostname(),
- );
+ let domain_prefix = format!("{}/pictrs/image/", protocol_and_hostname,);
let incorrect_thumbnails = post.filter(thumbnail_url.not_like("http%"));
use lemmy_api_common::blocking;
use lemmy_api_crud::match_websocket_operation_crud;
use lemmy_apub::activity_queue::create_activity_queue;
-use lemmy_db_queries::get_database_url_from_env;
+use lemmy_db_queries::{get_database_url_from_env, source::secret::Secret_};
+use lemmy_db_schema::source::secret::Secret;
use lemmy_routes::{feeds, images, nodeinfo, webfinger};
use lemmy_server::{api_routes, code_migrations::run_advanced_migrations, scheduled_tasks};
use lemmy_utils::{
#[actix_web::main]
async fn main() -> Result<(), LemmyError> {
env_logger::init();
- let settings = Settings::get();
+ let settings = Settings::init().expect("Couldn't initialize settings.");
// Set up the r2d2 connection pool
let db_url = match get_database_url_from_env() {
.unwrap_or_else(|_| panic!("Error connecting to {}", db_url));
// Run the migrations from code
+ let protocol_and_hostname = settings.get_protocol_and_hostname();
blocking(&pool, move |conn| {
embedded_migrations::run(conn)?;
- run_advanced_migrations(conn)?;
+ run_advanced_migrations(conn, &protocol_and_hostname)?;
Ok(()) as Result<(), LemmyError>
})
.await??;
// Set up the rate limiter
let rate_limiter = RateLimit {
rate_limiter: Arc::new(Mutex::new(RateLimiter::default())),
+ rate_limit_config: settings.rate_limit.to_owned().unwrap_or_default(),
};
+ // Initialize the secrets
+ let conn = pool.get()?;
+ let secret = Secret::init(&conn).expect("Couldn't initialize secrets.");
+
println!(
"Starting http server at {}:{}",
settings.bind, settings.port
|c, i, o, d| Box::pin(match_websocket_operation_crud(c, i, o, d)),
Client::default(),
activity_queue.clone(),
+ settings.clone(),
+ secret.clone(),
)
.start();
// Create Http server with websocket support
+ let settings_bind = settings.clone();
HttpServer::new(move || {
let context = LemmyContext::create(
pool.clone(),
chat_server.to_owned(),
Client::default(),
activity_queue.to_owned(),
+ settings.to_owned(),
+ secret.to_owned(),
);
let rate_limiter = rate_limiter.clone();
App::new()
.app_data(Data::new(context))
// The routes
.configure(|cfg| api_routes::config(cfg, &rate_limiter))
- .configure(lemmy_apub::http::routes::config)
+ .configure(|cfg| lemmy_apub::http::routes::config(cfg, &settings))
.configure(feeds::config)
.configure(|cfg| images::config(cfg, &rate_limiter))
.configure(nodeinfo::config)
- .configure(webfinger::config)
+ .configure(|cfg| webfinger::config(cfg, &settings))
})
- .bind((settings.bind, settings.port))?
+ .bind((settings_bind.bind, settings_bind.port))?
.run()
.await?;