1 use actix_web::{web, web::Data};
3 use lemmy_api_common::{
10 utils::local_site_to_slur_regex,
13 use lemmy_db_schema::source::local_site::LocalSite;
14 use lemmy_utils::{error::LemmyError, utils::check_slurs, ConnectionId};
15 use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
16 use serde::Deserialize;
25 mod private_message_report;
29 #[async_trait::async_trait(?Send)]
31 type Response: serde::ser::Serialize + Send;
35 context: &Data<LemmyContext>,
36 websocket_id: Option<ConnectionId>,
37 ) -> Result<Self::Response, LemmyError>;
40 pub async fn match_websocket_operation(
41 context: LemmyContext,
45 ) -> Result<String, LemmyError> {
48 UserOperation::Login => do_websocket_operation::<Login>(context, id, op, data).await,
49 UserOperation::GetCaptcha => do_websocket_operation::<GetCaptcha>(context, id, op, data).await,
50 UserOperation::GetReplies => do_websocket_operation::<GetReplies>(context, id, op, data).await,
51 UserOperation::AddAdmin => do_websocket_operation::<AddAdmin>(context, id, op, data).await,
52 UserOperation::GetUnreadRegistrationApplicationCount => {
53 do_websocket_operation::<GetUnreadRegistrationApplicationCount>(context, id, op, data).await
55 UserOperation::ListRegistrationApplications => {
56 do_websocket_operation::<ListRegistrationApplications>(context, id, op, data).await
58 UserOperation::ApproveRegistrationApplication => {
59 do_websocket_operation::<ApproveRegistrationApplication>(context, id, op, data).await
61 UserOperation::BanPerson => do_websocket_operation::<BanPerson>(context, id, op, data).await,
62 UserOperation::GetBannedPersons => {
63 do_websocket_operation::<GetBannedPersons>(context, id, op, data).await
65 UserOperation::BlockPerson => {
66 do_websocket_operation::<BlockPerson>(context, id, op, data).await
68 UserOperation::GetPersonMentions => {
69 do_websocket_operation::<GetPersonMentions>(context, id, op, data).await
71 UserOperation::MarkPersonMentionAsRead => {
72 do_websocket_operation::<MarkPersonMentionAsRead>(context, id, op, data).await
74 UserOperation::MarkCommentReplyAsRead => {
75 do_websocket_operation::<MarkCommentReplyAsRead>(context, id, op, data).await
77 UserOperation::MarkAllAsRead => {
78 do_websocket_operation::<MarkAllAsRead>(context, id, op, data).await
80 UserOperation::PasswordReset => {
81 do_websocket_operation::<PasswordReset>(context, id, op, data).await
83 UserOperation::PasswordChange => {
84 do_websocket_operation::<PasswordChangeAfterReset>(context, id, op, data).await
86 UserOperation::UserJoin => do_websocket_operation::<UserJoin>(context, id, op, data).await,
87 UserOperation::PostJoin => do_websocket_operation::<PostJoin>(context, id, op, data).await,
88 UserOperation::CommunityJoin => {
89 do_websocket_operation::<CommunityJoin>(context, id, op, data).await
91 UserOperation::ModJoin => do_websocket_operation::<ModJoin>(context, id, op, data).await,
92 UserOperation::SaveUserSettings => {
93 do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
95 UserOperation::ChangePassword => {
96 do_websocket_operation::<ChangePassword>(context, id, op, data).await
98 UserOperation::GetReportCount => {
99 do_websocket_operation::<GetReportCount>(context, id, op, data).await
101 UserOperation::GetUnreadCount => {
102 do_websocket_operation::<GetUnreadCount>(context, id, op, data).await
104 UserOperation::VerifyEmail => {
105 do_websocket_operation::<VerifyEmail>(context, id, op, data).await
108 // Private Message ops
109 UserOperation::MarkPrivateMessageAsRead => {
110 do_websocket_operation::<MarkPrivateMessageAsRead>(context, id, op, data).await
112 UserOperation::CreatePrivateMessageReport => {
113 do_websocket_operation::<CreatePrivateMessageReport>(context, id, op, data).await
115 UserOperation::ResolvePrivateMessageReport => {
116 do_websocket_operation::<ResolvePrivateMessageReport>(context, id, op, data).await
118 UserOperation::ListPrivateMessageReports => {
119 do_websocket_operation::<ListPrivateMessageReports>(context, id, op, data).await
123 UserOperation::GetModlog => do_websocket_operation::<GetModlog>(context, id, op, data).await,
124 UserOperation::PurgePerson => {
125 do_websocket_operation::<PurgePerson>(context, id, op, data).await
127 UserOperation::PurgeCommunity => {
128 do_websocket_operation::<PurgeCommunity>(context, id, op, data).await
130 UserOperation::PurgePost => do_websocket_operation::<PurgePost>(context, id, op, data).await,
131 UserOperation::PurgeComment => {
132 do_websocket_operation::<PurgeComment>(context, id, op, data).await
134 UserOperation::Search => do_websocket_operation::<Search>(context, id, op, data).await,
135 UserOperation::ResolveObject => {
136 do_websocket_operation::<ResolveObject>(context, id, op, data).await
138 UserOperation::TransferCommunity => {
139 do_websocket_operation::<TransferCommunity>(context, id, op, data).await
141 UserOperation::LeaveAdmin => do_websocket_operation::<LeaveAdmin>(context, id, op, data).await,
144 UserOperation::FollowCommunity => {
145 do_websocket_operation::<FollowCommunity>(context, id, op, data).await
147 UserOperation::BlockCommunity => {
148 do_websocket_operation::<BlockCommunity>(context, id, op, data).await
150 UserOperation::BanFromCommunity => {
151 do_websocket_operation::<BanFromCommunity>(context, id, op, data).await
153 UserOperation::AddModToCommunity => {
154 do_websocket_operation::<AddModToCommunity>(context, id, op, data).await
158 UserOperation::LockPost => do_websocket_operation::<LockPost>(context, id, op, data).await,
159 UserOperation::StickyPost => do_websocket_operation::<StickyPost>(context, id, op, data).await,
160 UserOperation::CreatePostLike => {
161 do_websocket_operation::<CreatePostLike>(context, id, op, data).await
163 UserOperation::MarkPostAsRead => {
164 do_websocket_operation::<MarkPostAsRead>(context, id, op, data).await
166 UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
167 UserOperation::CreatePostReport => {
168 do_websocket_operation::<CreatePostReport>(context, id, op, data).await
170 UserOperation::ListPostReports => {
171 do_websocket_operation::<ListPostReports>(context, id, op, data).await
173 UserOperation::ResolvePostReport => {
174 do_websocket_operation::<ResolvePostReport>(context, id, op, data).await
176 UserOperation::GetSiteMetadata => {
177 do_websocket_operation::<GetSiteMetadata>(context, id, op, data).await
181 UserOperation::SaveComment => {
182 do_websocket_operation::<SaveComment>(context, id, op, data).await
184 UserOperation::CreateCommentLike => {
185 do_websocket_operation::<CreateCommentLike>(context, id, op, data).await
187 UserOperation::CreateCommentReport => {
188 do_websocket_operation::<CreateCommentReport>(context, id, op, data).await
190 UserOperation::ListCommentReports => {
191 do_websocket_operation::<ListCommentReports>(context, id, op, data).await
193 UserOperation::ResolveCommentReport => {
194 do_websocket_operation::<ResolveCommentReport>(context, id, op, data).await
199 async fn do_websocket_operation<'a, 'b, Data>(
200 context: LemmyContext,
204 ) -> Result<String, LemmyError>
206 for<'de> Data: Deserialize<'de> + 'a,
209 let parsed_data: Data = serde_json::from_str(data)?;
210 let res = parsed_data
211 .perform(&web::Data::new(context), Some(id))
213 serialize_websocket_message(&op, &res)
216 /// Converts the captcha to a base64 encoded wav audio file
217 pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String {
218 let letters = captcha.as_wav();
220 let mut concat_letters: Vec<u8> = Vec::new();
222 for letter in letters {
223 let bytes = letter.unwrap_or_default();
224 concat_letters.extend(bytes);
228 base64::encode(concat_letters)
231 /// Check size of report and remove whitespace
232 pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> Result<(), LemmyError> {
233 let slur_regex = &local_site_to_slur_regex(local_site);
235 check_slurs(reason, slur_regex)?;
236 if reason.is_empty() {
237 return Err(LemmyError::from_message("report_reason_required"));
239 if reason.chars().count() > 1000 {
240 return Err(LemmyError::from_message("report_too_long"));
247 use lemmy_api_common::utils::check_validator_time;
248 use lemmy_db_schema::{
251 local_user::{LocalUser, LocalUserInsertForm},
252 person::{Person, PersonInsertForm},
256 utils::build_db_pool_for_tests,
258 use lemmy_utils::{claims::Claims, settings::SETTINGS};
259 use serial_test::serial;
263 async fn test_should_not_validate_user_token_after_password_change() {
264 let pool = &build_db_pool_for_tests().await;
265 let secret = Secret::init(pool).await.unwrap();
266 let settings = &SETTINGS.to_owned();
268 let inserted_instance = Instance::create(pool, "my_domain.tld").await.unwrap();
270 let new_person = PersonInsertForm::builder()
271 .name("Gerry9812".into())
272 .public_key("pubkey".to_string())
273 .instance_id(inserted_instance.id)
276 let inserted_person = Person::create(pool, &new_person).await.unwrap();
278 let local_user_form = LocalUserInsertForm::builder()
279 .person_id(inserted_person.id)
280 .password_encrypted("123456".to_string())
283 let inserted_local_user = LocalUser::create(pool, &local_user_form).await.unwrap();
285 let jwt = Claims::jwt(
286 inserted_local_user.id.0,
291 let claims = Claims::decode(&jwt, &secret.jwt_secret).unwrap().claims;
292 let check = check_validator_time(&inserted_local_user.validator_time, &claims);
293 assert!(check.is_ok());
295 // The check should fail, since the validator time is now newer than the jwt issue time
296 let updated_local_user =
297 LocalUser::update_password(pool, inserted_local_user.id, "password111")
300 let check_after = check_validator_time(&updated_local_user.validator_time, &claims);
301 assert!(check_after.is_err());
303 let num_deleted = Person::delete(pool, inserted_person.id).await.unwrap();
304 assert_eq!(1, num_deleted);