corund_lib/
token.rs

1use crate::ryz::err::res;
2use crate::ryz::res::Res;
3use crate::ryz::time::{utc, Time};
4use hmac::{Hmac, Mac};
5use jwt::VerifyWithKey;
6use jwt::{SignWithKey, ToBase64};
7use serde::Deserialize;
8use serde::Serialize;
9use sha2::Sha256;
10
11#[derive(Serialize, Deserialize, Debug)]
12pub struct UserTokenPayload {
13    pub user_id: i32,
14    /// When the token was created.
15    ///
16    /// We store this field instead of `exp` to allow receiver to freely
17    /// interpret using known exp delta.
18    pub created: Time,
19}
20
21impl Expire for UserTokenPayload {
22    fn get_created(&self) -> Res<Time> {
23        Ok(*&self.created)
24    }
25}
26
27pub trait Expire {
28    fn get_created(&self) -> Res<Time>;
29
30    /// Checks if for the given delta the object is considered as expired.
31    ///
32    /// Returns exp time with relation to the given delta.
33    fn check_exp(&self, delta: Time) -> Res<Time> {
34        let created = *&self.get_created().unwrap();
35        let exp = created + delta;
36        if exp < utc() {
37            return res("exp_err", "expired token");
38        }
39        Ok(exp)
40    }
41}
42
43pub fn new_token(
44    payload: &(impl ToBase64 + Expire + Serialize),
45    secret: &[u8],
46) -> Res<String> {
47    let encoded_secret: Hmac<Sha256> =
48        Hmac::new_from_slice(secret.into()).unwrap();
49    Ok(payload.sign_with_key(&encoded_secret).unwrap())
50}
51
52pub fn verify_token<T>(token: &String, secret: &[u8]) -> Res<T>
53where
54    T: ToBase64 + Expire + for<'a> Deserialize<'a>,
55{
56    let encoded_secret: Hmac<Sha256> = Hmac::new_from_slice(secret).unwrap();
57    let payload: T = token.verify_with_key(&encoded_secret).unwrap();
58    payload.check_exp(Time::from(60 * 60 * 24 * 365))?;
59    Ok(payload)
60}
61
62pub fn new_rt(user_id: i32) -> Res<String> {
63    let payload = UserTokenPayload {
64        user_id: user_id,
65        created: utc(),
66    };
67    new_token(&payload, b"weloveauth")
68}
69
70pub fn new_at(user_id: i32) -> Res<String> {
71    let payload = UserTokenPayload {
72        user_id: user_id,
73        created: utc(),
74    };
75    new_token(&payload, b"helloworld")
76}
77
78pub fn verify_rt(rt: &String) -> Res<UserTokenPayload> {
79    verify_token(rt, b"weloveauth")
80}