2020-09-24 13:53:21 +00:00
|
|
|
use actix_web::{web, web::Data};
|
2021-04-01 17:30:24 +00:00
|
|
|
use captcha::Captcha;
|
2022-09-19 22:58:42 +00:00
|
|
|
use lemmy_api_common::{
|
2022-11-19 04:33:54 +00:00
|
|
|
comment::{
|
|
|
|
CreateCommentLike,
|
|
|
|
CreateCommentReport,
|
|
|
|
ListCommentReports,
|
|
|
|
ResolveCommentReport,
|
|
|
|
SaveComment,
|
|
|
|
},
|
|
|
|
community::{
|
|
|
|
AddModToCommunity,
|
|
|
|
BanFromCommunity,
|
|
|
|
BlockCommunity,
|
|
|
|
FollowCommunity,
|
|
|
|
TransferCommunity,
|
|
|
|
},
|
|
|
|
person::{
|
|
|
|
AddAdmin,
|
|
|
|
BanPerson,
|
|
|
|
BlockPerson,
|
|
|
|
ChangePassword,
|
|
|
|
GetBannedPersons,
|
|
|
|
GetCaptcha,
|
|
|
|
GetPersonMentions,
|
|
|
|
GetReplies,
|
|
|
|
GetReportCount,
|
|
|
|
GetUnreadCount,
|
|
|
|
Login,
|
|
|
|
MarkAllAsRead,
|
|
|
|
MarkCommentReplyAsRead,
|
|
|
|
MarkPersonMentionAsRead,
|
|
|
|
PasswordChangeAfterReset,
|
|
|
|
PasswordReset,
|
|
|
|
SaveUserSettings,
|
|
|
|
VerifyEmail,
|
|
|
|
},
|
|
|
|
post::{
|
|
|
|
CreatePostLike,
|
|
|
|
CreatePostReport,
|
|
|
|
GetSiteMetadata,
|
|
|
|
ListPostReports,
|
|
|
|
LockPost,
|
|
|
|
MarkPostAsRead,
|
|
|
|
ResolvePostReport,
|
|
|
|
SavePost,
|
|
|
|
StickyPost,
|
|
|
|
},
|
|
|
|
private_message::{
|
|
|
|
CreatePrivateMessageReport,
|
|
|
|
ListPrivateMessageReports,
|
|
|
|
MarkPrivateMessageAsRead,
|
|
|
|
ResolvePrivateMessageReport,
|
|
|
|
},
|
|
|
|
site::{
|
|
|
|
ApproveRegistrationApplication,
|
|
|
|
GetModlog,
|
|
|
|
GetUnreadRegistrationApplicationCount,
|
|
|
|
LeaveAdmin,
|
|
|
|
ListRegistrationApplications,
|
|
|
|
PurgeComment,
|
|
|
|
PurgeCommunity,
|
|
|
|
PurgePerson,
|
|
|
|
PurgePost,
|
|
|
|
ResolveObject,
|
|
|
|
Search,
|
|
|
|
},
|
2022-10-27 09:24:07 +00:00
|
|
|
utils::local_site_to_slur_regex,
|
2022-11-19 04:33:54 +00:00
|
|
|
websocket::{CommunityJoin, ModJoin, PostJoin, UserJoin},
|
2022-09-19 22:58:42 +00:00
|
|
|
};
|
2022-10-27 09:24:07 +00:00
|
|
|
use lemmy_db_schema::source::local_site::LocalSite;
|
2022-09-19 22:58:42 +00:00
|
|
|
use lemmy_utils::{error::LemmyError, utils::check_slurs, ConnectionId};
|
2020-09-24 13:53:21 +00:00
|
|
|
use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
|
|
|
|
use serde::Deserialize;
|
|
|
|
|
2021-03-25 19:19:40 +00:00
|
|
|
mod comment;
|
|
|
|
mod comment_report;
|
|
|
|
mod community;
|
|
|
|
mod local_user;
|
|
|
|
mod post;
|
|
|
|
mod post_report;
|
|
|
|
mod private_message;
|
2022-09-19 22:58:42 +00:00
|
|
|
mod private_message_report;
|
2021-03-25 19:19:40 +00:00
|
|
|
mod site;
|
|
|
|
mod websocket;
|
2020-09-24 13:53:21 +00:00
|
|
|
|
|
|
|
#[async_trait::async_trait(?Send)]
|
|
|
|
pub trait Perform {
|
|
|
|
type Response: serde::ser::Serialize + Send;
|
|
|
|
|
|
|
|
async fn perform(
|
|
|
|
&self,
|
|
|
|
context: &Data<LemmyContext>,
|
|
|
|
websocket_id: Option<ConnectionId>,
|
|
|
|
) -> Result<Self::Response, LemmyError>;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn match_websocket_operation(
|
|
|
|
context: LemmyContext,
|
|
|
|
id: ConnectionId,
|
|
|
|
op: UserOperation,
|
|
|
|
data: &str,
|
|
|
|
) -> Result<String, LemmyError> {
|
|
|
|
match op {
|
|
|
|
// User ops
|
|
|
|
UserOperation::Login => do_websocket_operation::<Login>(context, id, op, data).await,
|
|
|
|
UserOperation::GetCaptcha => do_websocket_operation::<GetCaptcha>(context, id, op, data).await,
|
|
|
|
UserOperation::GetReplies => do_websocket_operation::<GetReplies>(context, id, op, data).await,
|
|
|
|
UserOperation::AddAdmin => do_websocket_operation::<AddAdmin>(context, id, op, data).await,
|
2021-12-15 19:49:59 +00:00
|
|
|
UserOperation::GetUnreadRegistrationApplicationCount => {
|
|
|
|
do_websocket_operation::<GetUnreadRegistrationApplicationCount>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::ListRegistrationApplications => {
|
|
|
|
do_websocket_operation::<ListRegistrationApplications>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::ApproveRegistrationApplication => {
|
|
|
|
do_websocket_operation::<ApproveRegistrationApplication>(context, id, op, data).await
|
|
|
|
}
|
2021-03-10 22:33:55 +00:00
|
|
|
UserOperation::BanPerson => do_websocket_operation::<BanPerson>(context, id, op, data).await,
|
2021-11-19 20:56:41 +00:00
|
|
|
UserOperation::GetBannedPersons => {
|
|
|
|
do_websocket_operation::<GetBannedPersons>(context, id, op, data).await
|
|
|
|
}
|
2021-08-19 20:54:15 +00:00
|
|
|
UserOperation::BlockPerson => {
|
|
|
|
do_websocket_operation::<BlockPerson>(context, id, op, data).await
|
|
|
|
}
|
2021-03-10 22:33:55 +00:00
|
|
|
UserOperation::GetPersonMentions => {
|
|
|
|
do_websocket_operation::<GetPersonMentions>(context, id, op, data).await
|
2020-09-24 13:53:21 +00:00
|
|
|
}
|
2021-03-10 22:33:55 +00:00
|
|
|
UserOperation::MarkPersonMentionAsRead => {
|
|
|
|
do_websocket_operation::<MarkPersonMentionAsRead>(context, id, op, data).await
|
2020-09-24 13:53:21 +00:00
|
|
|
}
|
2022-07-30 03:55:59 +00:00
|
|
|
UserOperation::MarkCommentReplyAsRead => {
|
|
|
|
do_websocket_operation::<MarkCommentReplyAsRead>(context, id, op, data).await
|
|
|
|
}
|
2020-09-24 13:53:21 +00:00
|
|
|
UserOperation::MarkAllAsRead => {
|
|
|
|
do_websocket_operation::<MarkAllAsRead>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::PasswordReset => {
|
|
|
|
do_websocket_operation::<PasswordReset>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::PasswordChange => {
|
2022-04-13 18:12:25 +00:00
|
|
|
do_websocket_operation::<PasswordChangeAfterReset>(context, id, op, data).await
|
2020-09-24 13:53:21 +00:00
|
|
|
}
|
|
|
|
UserOperation::UserJoin => do_websocket_operation::<UserJoin>(context, id, op, data).await,
|
|
|
|
UserOperation::PostJoin => do_websocket_operation::<PostJoin>(context, id, op, data).await,
|
|
|
|
UserOperation::CommunityJoin => {
|
|
|
|
do_websocket_operation::<CommunityJoin>(context, id, op, data).await
|
|
|
|
}
|
2020-11-04 02:15:11 +00:00
|
|
|
UserOperation::ModJoin => do_websocket_operation::<ModJoin>(context, id, op, data).await,
|
2020-09-24 13:53:21 +00:00
|
|
|
UserOperation::SaveUserSettings => {
|
|
|
|
do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
|
|
|
|
}
|
2021-04-01 21:39:01 +00:00
|
|
|
UserOperation::ChangePassword => {
|
|
|
|
do_websocket_operation::<ChangePassword>(context, id, op, data).await
|
|
|
|
}
|
2020-10-25 02:59:13 +00:00
|
|
|
UserOperation::GetReportCount => {
|
|
|
|
do_websocket_operation::<GetReportCount>(context, id, op, data).await
|
|
|
|
}
|
2021-10-16 10:43:41 +00:00
|
|
|
UserOperation::GetUnreadCount => {
|
|
|
|
do_websocket_operation::<GetUnreadCount>(context, id, op, data).await
|
|
|
|
}
|
2021-12-15 19:49:59 +00:00
|
|
|
UserOperation::VerifyEmail => {
|
|
|
|
do_websocket_operation::<VerifyEmail>(context, id, op, data).await
|
|
|
|
}
|
2020-09-24 13:53:21 +00:00
|
|
|
|
|
|
|
// Private Message ops
|
|
|
|
UserOperation::MarkPrivateMessageAsRead => {
|
|
|
|
do_websocket_operation::<MarkPrivateMessageAsRead>(context, id, op, data).await
|
|
|
|
}
|
2022-09-19 22:58:42 +00:00
|
|
|
UserOperation::CreatePrivateMessageReport => {
|
|
|
|
do_websocket_operation::<CreatePrivateMessageReport>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::ResolvePrivateMessageReport => {
|
|
|
|
do_websocket_operation::<ResolvePrivateMessageReport>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::ListPrivateMessageReports => {
|
|
|
|
do_websocket_operation::<ListPrivateMessageReports>(context, id, op, data).await
|
|
|
|
}
|
2020-09-24 13:53:21 +00:00
|
|
|
|
|
|
|
// Site ops
|
|
|
|
UserOperation::GetModlog => do_websocket_operation::<GetModlog>(context, id, op, data).await,
|
2022-06-13 19:15:04 +00:00
|
|
|
UserOperation::PurgePerson => {
|
|
|
|
do_websocket_operation::<PurgePerson>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::PurgeCommunity => {
|
|
|
|
do_websocket_operation::<PurgeCommunity>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::PurgePost => do_websocket_operation::<PurgePost>(context, id, op, data).await,
|
|
|
|
UserOperation::PurgeComment => {
|
|
|
|
do_websocket_operation::<PurgeComment>(context, id, op, data).await
|
|
|
|
}
|
2020-09-24 13:53:21 +00:00
|
|
|
UserOperation::Search => do_websocket_operation::<Search>(context, id, op, data).await,
|
2021-07-20 07:00:20 +00:00
|
|
|
UserOperation::ResolveObject => {
|
|
|
|
do_websocket_operation::<ResolveObject>(context, id, op, data).await
|
|
|
|
}
|
2020-09-24 13:53:21 +00:00
|
|
|
UserOperation::TransferCommunity => {
|
|
|
|
do_websocket_operation::<TransferCommunity>(context, id, op, data).await
|
|
|
|
}
|
2022-01-26 17:57:16 +00:00
|
|
|
UserOperation::LeaveAdmin => do_websocket_operation::<LeaveAdmin>(context, id, op, data).await,
|
2020-09-24 13:53:21 +00:00
|
|
|
|
|
|
|
// Community ops
|
|
|
|
UserOperation::FollowCommunity => {
|
|
|
|
do_websocket_operation::<FollowCommunity>(context, id, op, data).await
|
|
|
|
}
|
2021-08-19 20:54:15 +00:00
|
|
|
UserOperation::BlockCommunity => {
|
|
|
|
do_websocket_operation::<BlockCommunity>(context, id, op, data).await
|
2020-09-24 13:53:21 +00:00
|
|
|
}
|
|
|
|
UserOperation::BanFromCommunity => {
|
|
|
|
do_websocket_operation::<BanFromCommunity>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::AddModToCommunity => {
|
|
|
|
do_websocket_operation::<AddModToCommunity>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
|
|
|
|
// Post ops
|
|
|
|
UserOperation::LockPost => do_websocket_operation::<LockPost>(context, id, op, data).await,
|
|
|
|
UserOperation::StickyPost => do_websocket_operation::<StickyPost>(context, id, op, data).await,
|
|
|
|
UserOperation::CreatePostLike => {
|
|
|
|
do_websocket_operation::<CreatePostLike>(context, id, op, data).await
|
|
|
|
}
|
2021-11-23 14:15:43 +00:00
|
|
|
UserOperation::MarkPostAsRead => {
|
|
|
|
do_websocket_operation::<MarkPostAsRead>(context, id, op, data).await
|
|
|
|
}
|
2020-09-24 13:53:21 +00:00
|
|
|
UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
|
2020-10-25 02:59:13 +00:00
|
|
|
UserOperation::CreatePostReport => {
|
|
|
|
do_websocket_operation::<CreatePostReport>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::ListPostReports => {
|
|
|
|
do_websocket_operation::<ListPostReports>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::ResolvePostReport => {
|
|
|
|
do_websocket_operation::<ResolvePostReport>(context, id, op, data).await
|
|
|
|
}
|
2021-08-19 14:12:49 +00:00
|
|
|
UserOperation::GetSiteMetadata => {
|
|
|
|
do_websocket_operation::<GetSiteMetadata>(context, id, op, data).await
|
|
|
|
}
|
2020-09-24 13:53:21 +00:00
|
|
|
|
|
|
|
// Comment ops
|
|
|
|
UserOperation::SaveComment => {
|
|
|
|
do_websocket_operation::<SaveComment>(context, id, op, data).await
|
|
|
|
}
|
|
|
|
UserOperation::CreateCommentLike => {
|
|
|
|
do_websocket_operation::<CreateCommentLike>(context, id, op, data).await
|
|
|
|
}
|
2020-10-25 02:59:13 +00:00
|
|
|
UserOperation::CreateCommentReport => {
|
|
|
|
do_websocket_operation::<CreateCommentReport>(context, id, op, data).await
|
2020-10-21 00:31:01 +00:00
|
|
|
}
|
2020-10-25 02:59:13 +00:00
|
|
|
UserOperation::ListCommentReports => {
|
|
|
|
do_websocket_operation::<ListCommentReports>(context, id, op, data).await
|
2020-10-13 23:32:35 +00:00
|
|
|
}
|
2020-10-25 02:59:13 +00:00
|
|
|
UserOperation::ResolveCommentReport => {
|
|
|
|
do_websocket_operation::<ResolveCommentReport>(context, id, op, data).await
|
2020-10-13 23:32:35 +00:00
|
|
|
}
|
2020-09-24 13:53:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn do_websocket_operation<'a, 'b, Data>(
|
|
|
|
context: LemmyContext,
|
|
|
|
id: ConnectionId,
|
|
|
|
op: UserOperation,
|
|
|
|
data: &str,
|
|
|
|
) -> Result<String, LemmyError>
|
|
|
|
where
|
|
|
|
for<'de> Data: Deserialize<'de> + 'a,
|
|
|
|
Data: Perform,
|
|
|
|
{
|
2021-07-05 16:07:26 +00:00
|
|
|
let parsed_data: Data = serde_json::from_str(data)?;
|
2020-09-24 13:53:21 +00:00
|
|
|
let res = parsed_data
|
|
|
|
.perform(&web::Data::new(context), Some(id))
|
|
|
|
.await?;
|
|
|
|
serialize_websocket_message(&op, &res)
|
|
|
|
}
|
|
|
|
|
2021-04-01 17:30:24 +00:00
|
|
|
/// Converts the captcha to a base64 encoded wav audio file
|
|
|
|
pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String {
|
|
|
|
let letters = captcha.as_wav();
|
2020-09-24 13:53:21 +00:00
|
|
|
|
2021-04-01 17:30:24 +00:00
|
|
|
let mut concat_letters: Vec<u8> = Vec::new();
|
2020-09-24 13:53:21 +00:00
|
|
|
|
2021-04-01 17:30:24 +00:00
|
|
|
for letter in letters {
|
|
|
|
let bytes = letter.unwrap_or_default();
|
|
|
|
concat_letters.extend(bytes);
|
2020-09-24 13:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Convert to base64
|
2021-04-01 17:30:24 +00:00
|
|
|
base64::encode(concat_letters)
|
2020-09-24 13:53:21 +00:00
|
|
|
}
|
|
|
|
|
2022-09-19 22:58:42 +00:00
|
|
|
/// Check size of report and remove whitespace
|
2022-10-27 09:24:07 +00:00
|
|
|
pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> Result<(), LemmyError> {
|
|
|
|
let slur_regex = &local_site_to_slur_regex(local_site);
|
|
|
|
|
|
|
|
check_slurs(reason, slur_regex)?;
|
2022-09-19 22:58:42 +00:00
|
|
|
if reason.is_empty() {
|
|
|
|
return Err(LemmyError::from_message("report_reason_required"));
|
|
|
|
}
|
|
|
|
if reason.chars().count() > 1000 {
|
|
|
|
return Err(LemmyError::from_message("report_too_long"));
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-09-24 13:53:21 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2022-05-03 17:44:13 +00:00
|
|
|
use lemmy_api_common::utils::check_validator_time;
|
2021-10-16 13:33:38 +00:00
|
|
|
use lemmy_db_schema::{
|
|
|
|
source::{
|
2022-10-27 09:24:07 +00:00
|
|
|
instance::Instance,
|
|
|
|
local_user::{LocalUser, LocalUserInsertForm},
|
|
|
|
person::{Person, PersonInsertForm},
|
2021-10-16 13:33:38 +00:00
|
|
|
secret::Secret,
|
|
|
|
},
|
|
|
|
traits::Crud,
|
2022-11-09 10:05:00 +00:00
|
|
|
utils::build_db_pool_for_tests,
|
2021-03-13 18:16:35 +00:00
|
|
|
};
|
2022-06-22 20:24:54 +00:00
|
|
|
use lemmy_utils::{claims::Claims, settings::SETTINGS};
|
2022-11-09 10:05:00 +00:00
|
|
|
use serial_test::serial;
|
2021-03-13 18:16:35 +00:00
|
|
|
|
2022-11-09 10:05:00 +00:00
|
|
|
#[tokio::test]
|
|
|
|
#[serial]
|
|
|
|
async fn test_should_not_validate_user_token_after_password_change() {
|
|
|
|
let pool = &build_db_pool_for_tests().await;
|
|
|
|
let secret = Secret::init(pool).await.unwrap();
|
2022-06-22 20:24:54 +00:00
|
|
|
let settings = &SETTINGS.to_owned();
|
2021-03-13 18:16:35 +00:00
|
|
|
|
2022-11-09 10:05:00 +00:00
|
|
|
let inserted_instance = Instance::create(pool, "my_domain.tld").await.unwrap();
|
2022-10-27 09:24:07 +00:00
|
|
|
|
|
|
|
let new_person = PersonInsertForm::builder()
|
|
|
|
.name("Gerry9812".into())
|
|
|
|
.public_key("pubkey".to_string())
|
|
|
|
.instance_id(inserted_instance.id)
|
|
|
|
.build();
|
2021-03-13 18:16:35 +00:00
|
|
|
|
2022-11-09 10:05:00 +00:00
|
|
|
let inserted_person = Person::create(pool, &new_person).await.unwrap();
|
2021-03-13 18:16:35 +00:00
|
|
|
|
2022-10-27 09:24:07 +00:00
|
|
|
let local_user_form = LocalUserInsertForm::builder()
|
|
|
|
.person_id(inserted_person.id)
|
|
|
|
.password_encrypted("123456".to_string())
|
|
|
|
.build();
|
2021-03-13 20:36:40 +00:00
|
|
|
|
2022-11-09 10:05:00 +00:00
|
|
|
let inserted_local_user = LocalUser::create(pool, &local_user_form).await.unwrap();
|
2021-03-13 18:16:35 +00:00
|
|
|
|
2021-09-22 15:57:09 +00:00
|
|
|
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;
|
2021-03-19 04:31:49 +00:00
|
|
|
let check = check_validator_time(&inserted_local_user.validator_time, &claims);
|
|
|
|
assert!(check.is_ok());
|
2021-03-13 18:16:35 +00:00
|
|
|
|
2021-03-19 04:31:49 +00:00
|
|
|
// The check should fail, since the validator time is now newer than the jwt issue time
|
|
|
|
let updated_local_user =
|
2022-11-09 10:05:00 +00:00
|
|
|
LocalUser::update_password(pool, inserted_local_user.id, "password111")
|
|
|
|
.await
|
|
|
|
.unwrap();
|
2021-03-19 04:31:49 +00:00
|
|
|
let check_after = check_validator_time(&updated_local_user.validator_time, &claims);
|
|
|
|
assert!(check_after.is_err());
|
2021-03-13 18:16:35 +00:00
|
|
|
|
2022-11-09 10:05:00 +00:00
|
|
|
let num_deleted = Person::delete(pool, inserted_person.id).await.unwrap();
|
2021-03-19 04:31:49 +00:00
|
|
|
assert_eq!(1, num_deleted);
|
2021-03-13 18:16:35 +00:00
|
|
|
}
|
2020-09-24 13:53:21 +00:00
|
|
|
}
|