]> Untitled Git - lemmy.git/blob - server/lemmy_db/src/password_reset_request.rs
Merge remote-tracking branch 'weblate/main' into main
[lemmy.git] / server / lemmy_db / src / password_reset_request.rs
1 use crate::{
2   schema::{password_reset_request, password_reset_request::dsl::*},
3   Crud,
4 };
5 use diesel::{dsl::*, result::Error, *};
6 use sha2::{Digest, Sha256};
7
8 #[derive(Queryable, Identifiable, PartialEq, Debug)]
9 #[table_name = "password_reset_request"]
10 pub struct PasswordResetRequest {
11   pub id: i32,
12   pub user_id: i32,
13   pub token_encrypted: String,
14   pub published: chrono::NaiveDateTime,
15 }
16
17 #[derive(Insertable, AsChangeset, Clone)]
18 #[table_name = "password_reset_request"]
19 pub struct PasswordResetRequestForm {
20   pub user_id: i32,
21   pub token_encrypted: String,
22 }
23
24 impl Crud<PasswordResetRequestForm> for PasswordResetRequest {
25   fn read(conn: &PgConnection, password_reset_request_id: i32) -> Result<Self, Error> {
26     use crate::schema::password_reset_request::dsl::*;
27     password_reset_request
28       .find(password_reset_request_id)
29       .first::<Self>(conn)
30   }
31   fn delete(conn: &PgConnection, password_reset_request_id: i32) -> Result<usize, Error> {
32     diesel::delete(password_reset_request.find(password_reset_request_id)).execute(conn)
33   }
34   fn create(conn: &PgConnection, form: &PasswordResetRequestForm) -> Result<Self, Error> {
35     insert_into(password_reset_request)
36       .values(form)
37       .get_result::<Self>(conn)
38   }
39   fn update(
40     conn: &PgConnection,
41     password_reset_request_id: i32,
42     form: &PasswordResetRequestForm,
43   ) -> Result<Self, Error> {
44     diesel::update(password_reset_request.find(password_reset_request_id))
45       .set(form)
46       .get_result::<Self>(conn)
47   }
48 }
49
50 impl PasswordResetRequest {
51   pub fn create_token(conn: &PgConnection, from_user_id: i32, token: &str) -> Result<Self, Error> {
52     let mut hasher = Sha256::new();
53     hasher.update(token);
54     let token_hash: String = PasswordResetRequest::bytes_to_hex(hasher.finalize().to_vec());
55
56     let form = PasswordResetRequestForm {
57       user_id: from_user_id,
58       token_encrypted: token_hash,
59     };
60
61     Self::create(&conn, &form)
62   }
63   pub fn read_from_token(conn: &PgConnection, token: &str) -> Result<Self, Error> {
64     let mut hasher = Sha256::new();
65     hasher.update(token);
66     let token_hash: String = PasswordResetRequest::bytes_to_hex(hasher.finalize().to_vec());
67     password_reset_request
68       .filter(token_encrypted.eq(token_hash))
69       .filter(published.gt(now - 1.days()))
70       .first::<Self>(conn)
71   }
72
73   fn bytes_to_hex(bytes: Vec<u8>) -> String {
74     let mut str = String::new();
75     for byte in bytes {
76       str = format!("{}{:02x}", str, byte);
77     }
78     str
79   }
80 }
81
82 #[cfg(test)]
83 mod tests {
84   use super::{super::user::*, *};
85   use crate::{tests::establish_unpooled_connection, ListingType, SortType};
86
87   #[test]
88   fn test_crud() {
89     let conn = establish_unpooled_connection();
90
91     let new_user = UserForm {
92       name: "thommy prw".into(),
93       preferred_username: None,
94       password_encrypted: "nope".into(),
95       email: None,
96       matrix_user_id: None,
97       avatar: None,
98       banner: None,
99       admin: false,
100       banned: false,
101       updated: None,
102       show_nsfw: false,
103       theme: "darkly".into(),
104       default_sort_type: SortType::Hot as i16,
105       default_listing_type: ListingType::Subscribed as i16,
106       lang: "browser".into(),
107       show_avatars: true,
108       send_notifications_to_email: false,
109       actor_id: "changeme_8292378".into(),
110       bio: None,
111       local: true,
112       private_key: None,
113       public_key: None,
114       last_refreshed_at: None,
115     };
116
117     let inserted_user = User_::create(&conn, &new_user).unwrap();
118
119     let token = "nope";
120     let token_encrypted_ = "ca3704aa0b06f5954c79ee837faa152d84d6b2d42838f0637a15eda8337dbdce";
121
122     let inserted_password_reset_request =
123       PasswordResetRequest::create_token(&conn, inserted_user.id, token).unwrap();
124
125     let expected_password_reset_request = PasswordResetRequest {
126       id: inserted_password_reset_request.id,
127       user_id: inserted_user.id,
128       token_encrypted: token_encrypted_.to_string(),
129       published: inserted_password_reset_request.published,
130     };
131
132     let read_password_reset_request = PasswordResetRequest::read_from_token(&conn, token).unwrap();
133     let num_deleted = User_::delete(&conn, inserted_user.id).unwrap();
134
135     assert_eq!(expected_password_reset_request, read_password_reset_request);
136     assert_eq!(
137       expected_password_reset_request,
138       inserted_password_reset_request
139     );
140     assert_eq!(1, num_deleted);
141   }
142 }