]> Untitled Git - lemmy.git/blob - crates/api/src/lib.rs
Merge pull request #2593 from LemmyNet/refactor-notifications
[lemmy.git] / crates / api / src / lib.rs
1 use actix_web::web::Data;
2 use captcha::Captcha;
3 use lemmy_api_common::{context::LemmyContext, utils::local_site_to_slur_regex};
4 use lemmy_db_schema::source::local_site::LocalSite;
5 use lemmy_utils::{error::LemmyError, utils::check_slurs, ConnectionId};
6
7 mod comment;
8 mod comment_report;
9 mod community;
10 mod local_user;
11 mod post;
12 mod post_report;
13 mod private_message;
14 mod private_message_report;
15 mod site;
16 mod websocket;
17
18 #[async_trait::async_trait(?Send)]
19 pub trait Perform {
20   type Response: serde::ser::Serialize + Send;
21
22   async fn perform(
23     &self,
24     context: &Data<LemmyContext>,
25     websocket_id: Option<ConnectionId>,
26   ) -> Result<Self::Response, LemmyError>;
27 }
28
29 /// Converts the captcha to a base64 encoded wav audio file
30 pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String {
31   let letters = captcha.as_wav();
32
33   let mut concat_letters: Vec<u8> = Vec::new();
34
35   for letter in letters {
36     let bytes = letter.unwrap_or_default();
37     concat_letters.extend(bytes);
38   }
39
40   // Convert to base64
41   base64::encode(concat_letters)
42 }
43
44 /// Check size of report and remove whitespace
45 pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> Result<(), LemmyError> {
46   let slur_regex = &local_site_to_slur_regex(local_site);
47
48   check_slurs(reason, slur_regex)?;
49   if reason.is_empty() {
50     return Err(LemmyError::from_message("report_reason_required"));
51   }
52   if reason.chars().count() > 1000 {
53     return Err(LemmyError::from_message("report_too_long"));
54   }
55   Ok(())
56 }
57
58 #[cfg(test)]
59 mod tests {
60   use lemmy_api_common::utils::check_validator_time;
61   use lemmy_db_schema::{
62     source::{
63       instance::Instance,
64       local_user::{LocalUser, LocalUserInsertForm},
65       person::{Person, PersonInsertForm},
66       secret::Secret,
67     },
68     traits::Crud,
69     utils::build_db_pool_for_tests,
70   };
71   use lemmy_utils::{claims::Claims, settings::SETTINGS};
72   use serial_test::serial;
73
74   #[tokio::test]
75   #[serial]
76   async fn test_should_not_validate_user_token_after_password_change() {
77     let pool = &build_db_pool_for_tests().await;
78     let secret = Secret::init(pool).await.unwrap();
79     let settings = &SETTINGS.to_owned();
80
81     let inserted_instance = Instance::create(pool, "my_domain.tld").await.unwrap();
82
83     let new_person = PersonInsertForm::builder()
84       .name("Gerry9812".into())
85       .public_key("pubkey".to_string())
86       .instance_id(inserted_instance.id)
87       .build();
88
89     let inserted_person = Person::create(pool, &new_person).await.unwrap();
90
91     let local_user_form = LocalUserInsertForm::builder()
92       .person_id(inserted_person.id)
93       .password_encrypted("123456".to_string())
94       .build();
95
96     let inserted_local_user = LocalUser::create(pool, &local_user_form).await.unwrap();
97
98     let jwt = Claims::jwt(
99       inserted_local_user.id.0,
100       &secret.jwt_secret,
101       &settings.hostname,
102     )
103     .unwrap();
104     let claims = Claims::decode(&jwt, &secret.jwt_secret).unwrap().claims;
105     let check = check_validator_time(&inserted_local_user.validator_time, &claims);
106     assert!(check.is_ok());
107
108     // The check should fail, since the validator time is now newer than the jwt issue time
109     let updated_local_user =
110       LocalUser::update_password(pool, inserted_local_user.id, "password111")
111         .await
112         .unwrap();
113     let check_after = check_validator_time(&updated_local_user.validator_time, &claims);
114     assert!(check_after.is_err());
115
116     let num_deleted = Person::delete(pool, inserted_person.id).await.unwrap();
117     assert_eq!(1, num_deleted);
118   }
119 }