1 use actix_web::{web, web::Data};
3 use lemmy_api_common::{
31 MarkCommentReplyAsRead,
32 MarkPersonMentionAsRead,
33 PasswordChangeAfterReset,
50 CreatePrivateMessageReport,
51 ListPrivateMessageReports,
52 MarkPrivateMessageAsRead,
53 ResolvePrivateMessageReport,
56 ApproveRegistrationApplication,
58 GetUnreadRegistrationApplicationCount,
60 ListRegistrationApplications,
68 utils::local_site_to_slur_regex,
69 websocket::{CommunityJoin, ModJoin, PostJoin, UserJoin},
71 use lemmy_db_schema::source::local_site::LocalSite;
72 use lemmy_utils::{error::LemmyError, utils::check_slurs, ConnectionId};
73 use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
74 use serde::Deserialize;
83 mod private_message_report;
87 #[async_trait::async_trait(?Send)]
89 type Response: serde::ser::Serialize + Send;
93 context: &Data<LemmyContext>,
94 websocket_id: Option<ConnectionId>,
95 ) -> Result<Self::Response, LemmyError>;
98 pub async fn match_websocket_operation(
99 context: LemmyContext,
103 ) -> Result<String, LemmyError> {
106 UserOperation::Login => do_websocket_operation::<Login>(context, id, op, data).await,
107 UserOperation::GetCaptcha => do_websocket_operation::<GetCaptcha>(context, id, op, data).await,
108 UserOperation::GetReplies => do_websocket_operation::<GetReplies>(context, id, op, data).await,
109 UserOperation::AddAdmin => do_websocket_operation::<AddAdmin>(context, id, op, data).await,
110 UserOperation::GetUnreadRegistrationApplicationCount => {
111 do_websocket_operation::<GetUnreadRegistrationApplicationCount>(context, id, op, data).await
113 UserOperation::ListRegistrationApplications => {
114 do_websocket_operation::<ListRegistrationApplications>(context, id, op, data).await
116 UserOperation::ApproveRegistrationApplication => {
117 do_websocket_operation::<ApproveRegistrationApplication>(context, id, op, data).await
119 UserOperation::BanPerson => do_websocket_operation::<BanPerson>(context, id, op, data).await,
120 UserOperation::GetBannedPersons => {
121 do_websocket_operation::<GetBannedPersons>(context, id, op, data).await
123 UserOperation::BlockPerson => {
124 do_websocket_operation::<BlockPerson>(context, id, op, data).await
126 UserOperation::GetPersonMentions => {
127 do_websocket_operation::<GetPersonMentions>(context, id, op, data).await
129 UserOperation::MarkPersonMentionAsRead => {
130 do_websocket_operation::<MarkPersonMentionAsRead>(context, id, op, data).await
132 UserOperation::MarkCommentReplyAsRead => {
133 do_websocket_operation::<MarkCommentReplyAsRead>(context, id, op, data).await
135 UserOperation::MarkAllAsRead => {
136 do_websocket_operation::<MarkAllAsRead>(context, id, op, data).await
138 UserOperation::PasswordReset => {
139 do_websocket_operation::<PasswordReset>(context, id, op, data).await
141 UserOperation::PasswordChange => {
142 do_websocket_operation::<PasswordChangeAfterReset>(context, id, op, data).await
144 UserOperation::UserJoin => do_websocket_operation::<UserJoin>(context, id, op, data).await,
145 UserOperation::PostJoin => do_websocket_operation::<PostJoin>(context, id, op, data).await,
146 UserOperation::CommunityJoin => {
147 do_websocket_operation::<CommunityJoin>(context, id, op, data).await
149 UserOperation::ModJoin => do_websocket_operation::<ModJoin>(context, id, op, data).await,
150 UserOperation::SaveUserSettings => {
151 do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
153 UserOperation::ChangePassword => {
154 do_websocket_operation::<ChangePassword>(context, id, op, data).await
156 UserOperation::GetReportCount => {
157 do_websocket_operation::<GetReportCount>(context, id, op, data).await
159 UserOperation::GetUnreadCount => {
160 do_websocket_operation::<GetUnreadCount>(context, id, op, data).await
162 UserOperation::VerifyEmail => {
163 do_websocket_operation::<VerifyEmail>(context, id, op, data).await
166 // Private Message ops
167 UserOperation::MarkPrivateMessageAsRead => {
168 do_websocket_operation::<MarkPrivateMessageAsRead>(context, id, op, data).await
170 UserOperation::CreatePrivateMessageReport => {
171 do_websocket_operation::<CreatePrivateMessageReport>(context, id, op, data).await
173 UserOperation::ResolvePrivateMessageReport => {
174 do_websocket_operation::<ResolvePrivateMessageReport>(context, id, op, data).await
176 UserOperation::ListPrivateMessageReports => {
177 do_websocket_operation::<ListPrivateMessageReports>(context, id, op, data).await
181 UserOperation::GetModlog => do_websocket_operation::<GetModlog>(context, id, op, data).await,
182 UserOperation::PurgePerson => {
183 do_websocket_operation::<PurgePerson>(context, id, op, data).await
185 UserOperation::PurgeCommunity => {
186 do_websocket_operation::<PurgeCommunity>(context, id, op, data).await
188 UserOperation::PurgePost => do_websocket_operation::<PurgePost>(context, id, op, data).await,
189 UserOperation::PurgeComment => {
190 do_websocket_operation::<PurgeComment>(context, id, op, data).await
192 UserOperation::Search => do_websocket_operation::<Search>(context, id, op, data).await,
193 UserOperation::ResolveObject => {
194 do_websocket_operation::<ResolveObject>(context, id, op, data).await
196 UserOperation::TransferCommunity => {
197 do_websocket_operation::<TransferCommunity>(context, id, op, data).await
199 UserOperation::LeaveAdmin => do_websocket_operation::<LeaveAdmin>(context, id, op, data).await,
202 UserOperation::FollowCommunity => {
203 do_websocket_operation::<FollowCommunity>(context, id, op, data).await
205 UserOperation::BlockCommunity => {
206 do_websocket_operation::<BlockCommunity>(context, id, op, data).await
208 UserOperation::BanFromCommunity => {
209 do_websocket_operation::<BanFromCommunity>(context, id, op, data).await
211 UserOperation::AddModToCommunity => {
212 do_websocket_operation::<AddModToCommunity>(context, id, op, data).await
216 UserOperation::LockPost => do_websocket_operation::<LockPost>(context, id, op, data).await,
217 UserOperation::StickyPost => do_websocket_operation::<StickyPost>(context, id, op, data).await,
218 UserOperation::CreatePostLike => {
219 do_websocket_operation::<CreatePostLike>(context, id, op, data).await
221 UserOperation::MarkPostAsRead => {
222 do_websocket_operation::<MarkPostAsRead>(context, id, op, data).await
224 UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
225 UserOperation::CreatePostReport => {
226 do_websocket_operation::<CreatePostReport>(context, id, op, data).await
228 UserOperation::ListPostReports => {
229 do_websocket_operation::<ListPostReports>(context, id, op, data).await
231 UserOperation::ResolvePostReport => {
232 do_websocket_operation::<ResolvePostReport>(context, id, op, data).await
234 UserOperation::GetSiteMetadata => {
235 do_websocket_operation::<GetSiteMetadata>(context, id, op, data).await
239 UserOperation::SaveComment => {
240 do_websocket_operation::<SaveComment>(context, id, op, data).await
242 UserOperation::CreateCommentLike => {
243 do_websocket_operation::<CreateCommentLike>(context, id, op, data).await
245 UserOperation::CreateCommentReport => {
246 do_websocket_operation::<CreateCommentReport>(context, id, op, data).await
248 UserOperation::ListCommentReports => {
249 do_websocket_operation::<ListCommentReports>(context, id, op, data).await
251 UserOperation::ResolveCommentReport => {
252 do_websocket_operation::<ResolveCommentReport>(context, id, op, data).await
257 async fn do_websocket_operation<'a, 'b, Data>(
258 context: LemmyContext,
262 ) -> Result<String, LemmyError>
264 for<'de> Data: Deserialize<'de> + 'a,
267 let parsed_data: Data = serde_json::from_str(data)?;
268 let res = parsed_data
269 .perform(&web::Data::new(context), Some(id))
271 serialize_websocket_message(&op, &res)
274 /// Converts the captcha to a base64 encoded wav audio file
275 pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String {
276 let letters = captcha.as_wav();
278 let mut concat_letters: Vec<u8> = Vec::new();
280 for letter in letters {
281 let bytes = letter.unwrap_or_default();
282 concat_letters.extend(bytes);
286 base64::encode(concat_letters)
289 /// Check size of report and remove whitespace
290 pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> Result<(), LemmyError> {
291 let slur_regex = &local_site_to_slur_regex(local_site);
293 check_slurs(reason, slur_regex)?;
294 if reason.is_empty() {
295 return Err(LemmyError::from_message("report_reason_required"));
297 if reason.chars().count() > 1000 {
298 return Err(LemmyError::from_message("report_too_long"));
305 use lemmy_api_common::utils::check_validator_time;
306 use lemmy_db_schema::{
309 local_user::{LocalUser, LocalUserInsertForm},
310 person::{Person, PersonInsertForm},
314 utils::build_db_pool_for_tests,
316 use lemmy_utils::{claims::Claims, settings::SETTINGS};
317 use serial_test::serial;
321 async fn test_should_not_validate_user_token_after_password_change() {
322 let pool = &build_db_pool_for_tests().await;
323 let secret = Secret::init(pool).await.unwrap();
324 let settings = &SETTINGS.to_owned();
326 let inserted_instance = Instance::create(pool, "my_domain.tld").await.unwrap();
328 let new_person = PersonInsertForm::builder()
329 .name("Gerry9812".into())
330 .public_key("pubkey".to_string())
331 .instance_id(inserted_instance.id)
334 let inserted_person = Person::create(pool, &new_person).await.unwrap();
336 let local_user_form = LocalUserInsertForm::builder()
337 .person_id(inserted_person.id)
338 .password_encrypted("123456".to_string())
341 let inserted_local_user = LocalUser::create(pool, &local_user_form).await.unwrap();
343 let jwt = Claims::jwt(
344 inserted_local_user.id.0,
349 let claims = Claims::decode(&jwt, &secret.jwt_secret).unwrap().claims;
350 let check = check_validator_time(&inserted_local_user.validator_time, &claims);
351 assert!(check.is_ok());
353 // The check should fail, since the validator time is now newer than the jwt issue time
354 let updated_local_user =
355 LocalUser::update_password(pool, inserted_local_user.id, "password111")
358 let check_after = check_validator_time(&updated_local_user.validator_time, &claims);
359 assert!(check_after.is_err());
361 let num_deleted = Person::delete(pool, inserted_person.id).await.unwrap();
362 assert_eq!(1, num_deleted);