1 use actix_web::{web, web::Data};
3 use lemmy_api_common::{comment::*, community::*, person::*, post::*, site::*, websocket::*};
4 use lemmy_utils::{error::LemmyError, ConnectionId};
5 use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
6 use serde::Deserialize;
18 #[async_trait::async_trait(?Send)]
20 type Response: serde::ser::Serialize + Send;
24 context: &Data<LemmyContext>,
25 websocket_id: Option<ConnectionId>,
26 ) -> Result<Self::Response, LemmyError>;
29 pub async fn match_websocket_operation(
30 context: LemmyContext,
34 ) -> Result<String, LemmyError> {
37 UserOperation::Login => do_websocket_operation::<Login>(context, id, op, data).await,
38 UserOperation::GetCaptcha => do_websocket_operation::<GetCaptcha>(context, id, op, data).await,
39 UserOperation::GetReplies => do_websocket_operation::<GetReplies>(context, id, op, data).await,
40 UserOperation::AddAdmin => do_websocket_operation::<AddAdmin>(context, id, op, data).await,
41 UserOperation::GetUnreadRegistrationApplicationCount => {
42 do_websocket_operation::<GetUnreadRegistrationApplicationCount>(context, id, op, data).await
44 UserOperation::ListRegistrationApplications => {
45 do_websocket_operation::<ListRegistrationApplications>(context, id, op, data).await
47 UserOperation::ApproveRegistrationApplication => {
48 do_websocket_operation::<ApproveRegistrationApplication>(context, id, op, data).await
50 UserOperation::BanPerson => do_websocket_operation::<BanPerson>(context, id, op, data).await,
51 UserOperation::GetBannedPersons => {
52 do_websocket_operation::<GetBannedPersons>(context, id, op, data).await
54 UserOperation::BlockPerson => {
55 do_websocket_operation::<BlockPerson>(context, id, op, data).await
57 UserOperation::GetPersonMentions => {
58 do_websocket_operation::<GetPersonMentions>(context, id, op, data).await
60 UserOperation::MarkPersonMentionAsRead => {
61 do_websocket_operation::<MarkPersonMentionAsRead>(context, id, op, data).await
63 UserOperation::MarkAllAsRead => {
64 do_websocket_operation::<MarkAllAsRead>(context, id, op, data).await
66 UserOperation::PasswordReset => {
67 do_websocket_operation::<PasswordReset>(context, id, op, data).await
69 UserOperation::PasswordChange => {
70 do_websocket_operation::<PasswordChangeAfterReset>(context, id, op, data).await
72 UserOperation::UserJoin => do_websocket_operation::<UserJoin>(context, id, op, data).await,
73 UserOperation::PostJoin => do_websocket_operation::<PostJoin>(context, id, op, data).await,
74 UserOperation::CommunityJoin => {
75 do_websocket_operation::<CommunityJoin>(context, id, op, data).await
77 UserOperation::ModJoin => do_websocket_operation::<ModJoin>(context, id, op, data).await,
78 UserOperation::SaveUserSettings => {
79 do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
81 UserOperation::ChangePassword => {
82 do_websocket_operation::<ChangePassword>(context, id, op, data).await
84 UserOperation::GetReportCount => {
85 do_websocket_operation::<GetReportCount>(context, id, op, data).await
87 UserOperation::GetUnreadCount => {
88 do_websocket_operation::<GetUnreadCount>(context, id, op, data).await
90 UserOperation::VerifyEmail => {
91 do_websocket_operation::<VerifyEmail>(context, id, op, data).await
94 // Private Message ops
95 UserOperation::MarkPrivateMessageAsRead => {
96 do_websocket_operation::<MarkPrivateMessageAsRead>(context, id, op, data).await
100 UserOperation::GetModlog => do_websocket_operation::<GetModlog>(context, id, op, data).await,
101 UserOperation::GetSiteConfig => {
102 do_websocket_operation::<GetSiteConfig>(context, id, op, data).await
104 UserOperation::SaveSiteConfig => {
105 do_websocket_operation::<SaveSiteConfig>(context, id, op, data).await
107 UserOperation::PurgePerson => {
108 do_websocket_operation::<PurgePerson>(context, id, op, data).await
110 UserOperation::PurgeCommunity => {
111 do_websocket_operation::<PurgeCommunity>(context, id, op, data).await
113 UserOperation::PurgePost => do_websocket_operation::<PurgePost>(context, id, op, data).await,
114 UserOperation::PurgeComment => {
115 do_websocket_operation::<PurgeComment>(context, id, op, data).await
117 UserOperation::Search => do_websocket_operation::<Search>(context, id, op, data).await,
118 UserOperation::ResolveObject => {
119 do_websocket_operation::<ResolveObject>(context, id, op, data).await
121 UserOperation::TransferCommunity => {
122 do_websocket_operation::<TransferCommunity>(context, id, op, data).await
124 UserOperation::LeaveAdmin => do_websocket_operation::<LeaveAdmin>(context, id, op, data).await,
127 UserOperation::FollowCommunity => {
128 do_websocket_operation::<FollowCommunity>(context, id, op, data).await
130 UserOperation::BlockCommunity => {
131 do_websocket_operation::<BlockCommunity>(context, id, op, data).await
133 UserOperation::BanFromCommunity => {
134 do_websocket_operation::<BanFromCommunity>(context, id, op, data).await
136 UserOperation::AddModToCommunity => {
137 do_websocket_operation::<AddModToCommunity>(context, id, op, data).await
141 UserOperation::LockPost => do_websocket_operation::<LockPost>(context, id, op, data).await,
142 UserOperation::StickyPost => do_websocket_operation::<StickyPost>(context, id, op, data).await,
143 UserOperation::CreatePostLike => {
144 do_websocket_operation::<CreatePostLike>(context, id, op, data).await
146 UserOperation::MarkPostAsRead => {
147 do_websocket_operation::<MarkPostAsRead>(context, id, op, data).await
149 UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
150 UserOperation::CreatePostReport => {
151 do_websocket_operation::<CreatePostReport>(context, id, op, data).await
153 UserOperation::ListPostReports => {
154 do_websocket_operation::<ListPostReports>(context, id, op, data).await
156 UserOperation::ResolvePostReport => {
157 do_websocket_operation::<ResolvePostReport>(context, id, op, data).await
159 UserOperation::GetSiteMetadata => {
160 do_websocket_operation::<GetSiteMetadata>(context, id, op, data).await
164 UserOperation::MarkCommentAsRead => {
165 do_websocket_operation::<MarkCommentAsRead>(context, id, op, data).await
167 UserOperation::SaveComment => {
168 do_websocket_operation::<SaveComment>(context, id, op, data).await
170 UserOperation::CreateCommentLike => {
171 do_websocket_operation::<CreateCommentLike>(context, id, op, data).await
173 UserOperation::CreateCommentReport => {
174 do_websocket_operation::<CreateCommentReport>(context, id, op, data).await
176 UserOperation::ListCommentReports => {
177 do_websocket_operation::<ListCommentReports>(context, id, op, data).await
179 UserOperation::ResolveCommentReport => {
180 do_websocket_operation::<ResolveCommentReport>(context, id, op, data).await
185 async fn do_websocket_operation<'a, 'b, Data>(
186 context: LemmyContext,
190 ) -> Result<String, LemmyError>
192 for<'de> Data: Deserialize<'de> + 'a,
195 let parsed_data: Data = serde_json::from_str(data)?;
196 let res = parsed_data
197 .perform(&web::Data::new(context), Some(id))
199 serialize_websocket_message(&op, &res)
202 /// Converts the captcha to a base64 encoded wav audio file
203 pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String {
204 let letters = captcha.as_wav();
206 let mut concat_letters: Vec<u8> = Vec::new();
208 for letter in letters {
209 let bytes = letter.unwrap_or_default();
210 concat_letters.extend(bytes);
214 base64::encode(concat_letters)
219 use lemmy_api_common::utils::check_validator_time;
220 use lemmy_db_schema::{
222 local_user::{LocalUser, LocalUserForm},
223 person::{Person, PersonForm},
227 utils::establish_unpooled_connection,
229 use lemmy_utils::{claims::Claims, settings::structs::Settings};
232 fn test_should_not_validate_user_token_after_password_change() {
233 let conn = establish_unpooled_connection();
234 let secret = Secret::init(&conn).unwrap();
235 let settings = Settings::init().unwrap();
237 let new_person = PersonForm {
238 name: "Gerry9812".into(),
239 ..PersonForm::default()
242 let inserted_person = Person::create(&conn, &new_person).unwrap();
244 let local_user_form = LocalUserForm {
245 person_id: Some(inserted_person.id),
246 password_encrypted: Some("123456".to_string()),
247 ..LocalUserForm::default()
250 let inserted_local_user = LocalUser::create(&conn, &local_user_form).unwrap();
252 let jwt = Claims::jwt(
253 inserted_local_user.id.0,
258 let claims = Claims::decode(&jwt, &secret.jwt_secret).unwrap().claims;
259 let check = check_validator_time(&inserted_local_user.validator_time, &claims);
260 assert!(check.is_ok());
262 // The check should fail, since the validator time is now newer than the jwt issue time
263 let updated_local_user =
264 LocalUser::update_password(&conn, inserted_local_user.id, "password111").unwrap();
265 let check_after = check_validator_time(&updated_local_user.validator_time, &claims);
266 assert!(check_after.is_err());
268 let num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
269 assert_eq!(1, num_deleted);