web_toolkit/
encrypt.rs

1pub mod hasher {
2    use std::io::{Error, ErrorKind};
3    use argon2::{
4        password_hash::{
5            rand_core::OsRng,
6            PasswordHash, PasswordHasher, PasswordVerifier, SaltString
7        },
8        Argon2
9    };
10
11    pub fn hash(passwd:&str) -> Result<String, Error> {
12        let salt:SaltString = SaltString::generate(&mut OsRng);
13        let argon:Argon2 = Argon2::default();
14        match argon.hash_password(passwd.as_bytes(), &salt) {
15            Ok(pass) => Ok(pass.to_string()),
16            Err(e) => Err(Error::new(ErrorKind::Other, e.to_string()))
17        }
18    }
19
20    pub fn verify(plain:&str, hashed: &str) -> Result<bool, std::io::Error> {
21        let argon:Argon2 = Argon2::default();
22        match PasswordHash::new(hashed) {
23            Ok(ph) => {
24                Ok(argon.verify_password(plain.as_bytes(), &ph).is_ok())
25            },
26            Err(e) => Err(Error::new(ErrorKind::Other, e.to_string()))
27        }
28    }
29    
30}
31
32pub mod jwt {
33
34    const PRIVATE:&str = "private_key.pem";
35    const PUBLIC:&str = "public_key.pem";
36    
37    use std::{result::Result::Ok, str::FromStr, fmt::Display, collections::HashSet};
38    use openssl::pkey::{PKey, Private};
39    use std::{io::{Error, ErrorKind}, fs, path::Path};
40    use jwt_simple::{prelude::{Ed25519KeyPair,Claims, VerificationOptions, Ed25519PublicKey, NoCustomClaims, EdDSAPublicKeyLike, Duration, EdDSAKeyPairLike, JWTClaims}};
41
42    pub struct SignOptions<'a, T:ToString> {
43        pub issuer: Option<&'a str>,
44        pub expiry: Option<Duration>,
45        pub audience: Option<T>
46    }
47
48    #[derive(Default)]
49    pub struct VerifyOptions {
50        pub valid_audiences: Option<HashSet<String>>,
51        pub valid_issuers: Option<HashSet<String>>,
52        pub valid_after_expiry: Option<Duration>
53    }
54
55    impl<'a, T:ToString+Copy> SignOptions<'a, T> {
56        fn get_claim(&self) -> JWTClaims<NoCustomClaims> {
57            let mut claim = Claims::create(match self.expiry {
58                Some(exp) => exp,
59                None => std::time::Duration::MAX.into()
60            });
61
62            claim = match self.audience {
63                Some(audience) => claim.with_audience(audience),
64                None => claim,
65            };
66
67            match self.issuer {
68                Some(iss) => claim.with_issuer(iss),
69                None => claim
70            }
71        }
72    }
73
74    pub fn generate_key_pair_if_absent() -> Result<(), Error> {
75
76        let priv_key:PKey<Private> = match fs::read(PRIVATE) {
77            Ok(key_in_bytes) => match PKey::private_key_from_pem(key_in_bytes.as_slice()){
78                Ok(k) => k,
79                Err(_) => match PKey::generate_ed25519() {
80                    Ok(vv) => vv,
81                    Err(e) => {
82                        return Err(Error::new(ErrorKind::Other, e.to_string()));    
83                    }
84                },
85            },
86            Err(_) => match PKey::generate_ed25519() {
87                Ok(val) => val,
88                Err(e) => {
89                    return Err(Error::new(ErrorKind::Other, e.to_string()));    
90                }
91            }
92        };
93
94        match priv_key.private_key_to_pem_pkcs8() {
95            Ok(str) => {
96                match fs::write(PRIVATE, str) {
97                    Ok(_) => {},
98                    Err(e) => {
99                        return Err(Error::new(ErrorKind::Other, e.to_string()));    
100                    }
101                }
102            },
103            Err(e) => {
104                return Err(Error::new(ErrorKind::Other, e.to_string()));    
105            }
106        };
107
108        match priv_key.public_key_to_pem() {
109            Ok(str) => {
110                match fs::write(PUBLIC, str) {
111                    Ok(_) => {},
112                    Err(e) => {
113                        return Err(Error::new(ErrorKind::Other, e.to_string()));    
114                    }
115                }
116            },
117            Err(e) => {
118                return Err(Error::new(ErrorKind::Other, e.to_string()));    
119            }
120        };
121
122        Ok(())
123
124    }
125
126
127    pub fn get_keys_as_str() -> Result<(String,String), Error> {
128        let pub_bytes = match fs::read(Path::new("public_key.pem")) {
129            Ok(bts) => bts,
130            Err(e) => {return Err(Error::new(ErrorKind::Other, e.to_string()));}
131        };
132
133        let priv_bytes = match fs::read(Path::new("private_key.pem")) {
134            Ok(bts) => bts,
135            Err(e) => {return Err(Error::new(ErrorKind::Other, e.to_string()));}
136        };
137
138        Ok((String::from_utf8(priv_bytes).unwrap(),String::from_utf8(pub_bytes).unwrap()))
139    }
140
141    pub fn sign<T:ToString+Copy>(pem_str:&str, options:SignOptions<T>) -> Result<String, Error> {
142        let key_pair = match Ed25519KeyPair::from_pem(pem_str) {
143            Ok(pair) => pair,
144            Err(e) => {
145                return Err(Error::new(ErrorKind::Other, e.to_string()))
146            }
147        };
148
149        let claim = options.get_claim();
150
151        match key_pair.sign(claim) {
152            Ok(token) => Ok(token),
153            Err(e) => Err(Error::new(ErrorKind::Other, e.to_string()))
154        }
155    }
156
157    pub fn verify<T>(token:&str, pub_pem_str:&str, options:VerifyOptions) -> Result<T, Error>
158    where 
159    <T as FromStr>::Err:Display,
160    T:FromStr
161    {
162        let opts:VerificationOptions = VerificationOptions { accept_future:false, time_tolerance: options.valid_after_expiry, allowed_issuers: options.valid_issuers, allowed_audiences: options.valid_audiences, ..Default::default() };
163        let pub_key = match Ed25519PublicKey::from_pem(pub_pem_str) {
164            Ok(key) => key,
165            Err(e) => {return Err(Error::new(ErrorKind::Other, e.to_string()))}
166        };
167        match pub_key.verify_token::<NoCustomClaims>(token, Some(opts)) {
168            Ok(clm) => {
169                let aud = match clm.audiences {
170                    Some(adienc) => adienc,
171                    None => {return Err(Error::new(ErrorKind::Other, "Empty audience"))}
172                };
173                match aud.into_string() {
174                    Ok(au_clm) => match T::from_str(&au_clm) {
175                        Ok(id) => Ok(id),
176                        Err(e) => Err(Error::new(ErrorKind::Other, e.to_string()))
177                    },
178                    Err(e) => Err(Error::new(ErrorKind::Other, e.to_string()))
179                }
180            },
181            Err(e) => Err(Error::new(ErrorKind::Other, e.to_string()))
182        }
183    }
184}