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