summaryrefslogtreecommitdiffstats
path: root/src/user/login.rs
blob: 67d4c2424306cf795afb6427d77936cfad7d8625 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use actix::{Actor, Handler, Message, SyncContext};
use argonautica::{input::SecretKey, Verifier};
use diesel::MysqlConnection;
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};

use crate::error::ServiceError;
use crate::model::DbExecutor;
use crate::model::User;
use crate::schema::passwords::{columns as password_columns, dsl::passwords};
use crate::schema::users::{columns as user_columns, dsl::users};

pub struct HashVerifyExecutor(pub Verifier<'static>);

impl Actor for HashVerifyExecutor {
    type Context = SyncContext<Self>;
}

pub struct HashVerifyRequest {
    hash: String,
    password: String,
    secret: String,
}

impl HashVerifyRequest {
    pub fn new(hash: String, password: String, secret: String) -> Self {
        Self {
            hash,
            password,
            secret,
        }
    }
}

impl Message for HashVerifyRequest {
    type Result = Result<bool, ServiceError>;
}

impl Handler<HashVerifyRequest> for HashVerifyExecutor {
    type Result = Result<bool, ServiceError>;

    fn handle(&mut self, req: HashVerifyRequest, _: &mut Self::Context) -> Self::Result {
        let secret = SecretKey::from_base64_encoded(req.secret)?;
        Ok(self
            .0
            .with_hash(req.hash)
            .with_password(req.password)
            .with_secret_key(secret)
            .verify()?)
    }
}

pub struct LoginRequest(pub String);

impl Message for LoginRequest {
    type Result = Result<(User, String), ServiceError>;
}

impl Handler<LoginRequest> for DbExecutor {
    type Result = Result<(User, String), ServiceError>;

    fn handle(&mut self, login: LoginRequest, _: &mut Self::Context) -> Self::Result {
        let conn: &MysqlConnection = &self.0.get().unwrap();

        let user = users
            .filter(user_columns::name.eq(login.0))
            .first::<User>(conn)
            .map_err(|_| ServiceError::NotFound)?;

        let hash = passwords
            .filter(password_columns::id.eq(user.id))
            .select(password_columns::hash)
            .first::<String>(conn)
            .map_err(|_| ServiceError::NotFound)?;

        Ok((user, hash))
    }
}