1use chrono::Utc;
2use dryoc::constants::{
3 CRYPTO_SIGN_PUBLICKEYBYTES,
4 CRYPTO_SIGN_SECRETKEYBYTES
5};
6use dryoc::sign::SigningKeyPair;
7use base64::{Engine as _, engine::general_purpose};
8
9use crate::error::NcryptfError as Error;
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Token {
15 pub access_token: String,
16 pub refresh_token: String,
17 pub ikm: Vec<u8>,
18 pub signature: Vec<u8>,
19 pub expires_at: i64,
20}
21
22impl Token {
23 pub fn new(lifetime: i64) -> Token {
25 let now = Utc::now().timestamp();
26 let expires_at: i64;
27 if lifetime >= 0 {
28 expires_at = now + lifetime;
29 } else {
30 expires_at = now;
31 }
32
33 return Self {
34 access_token: general_purpose::URL_SAFE.encode(crate::util::randombytes_buf(48)),
35 refresh_token: general_purpose::URL_SAFE.encode(crate::util::randombytes_buf(64)),
36 ikm: crate::util::randombytes_buf(32),
37 signature: crate::util::randombytes_buf(64),
38 expires_at: expires_at,
39 };
40 }
41
42 pub fn from(
44 access_token: String,
45 refresh_token: String,
46 ikm: Vec<u8>,
47 signature: Vec<u8>,
48 expires_at: i64,
49 ) -> Result<Token, Error> {
50 if ikm.len() != 32 {
51 return Err(Error::InvalidArgument(format!(
52 "Initial key material should be {} bytes",
53 32
54 )));
55 }
56
57 if signature.len() != 64 {
58 return Err(Error::InvalidArgument(format!(
59 "Signature secret key should be {} bytes",
60 64
61 )));
62 }
63
64 return Ok(Self {
65 access_token,
66 refresh_token,
67 ikm,
68 signature,
69 expires_at,
70 });
71 }
72
73 pub fn from_json(json: serde_json::Value) -> Result<Self, Error> {
75 if json.get("access_token").is_none()
76 || json.get("refresh_token").is_none()
77 || json.get("ikm").is_none()
78 || json.get("signing").is_none()
79 || json.get("expires_at").is_none()
80 {
81 return Err(Error::InvalidArgument(format!(
82 "The provided JSON object is not valid for tokenization."
83 )));
84 }
85
86 return match Token::from(
87 json.get("access_token").unwrap().to_string(),
88 json.get("refresh_token").unwrap().to_string(),
89 general_purpose::STANDARD.decode(json.get("ikm").unwrap().as_str().unwrap()).unwrap(),
90 general_purpose::STANDARD.decode(json.get("signing").unwrap().as_str().unwrap()).unwrap(),
91 json.get("expires_at").unwrap().as_i64().unwrap(),
92 ) {
93 Ok(token) => return Ok(token),
94 Err(_error) => Err(_error),
95 };
96 }
97
98 pub fn is_expired(&self) -> bool {
101 let now = Utc::now().timestamp();
102 return now > self.expires_at;
103 }
104
105 pub fn get_signature_public_key(&self) -> Result<Vec<u8>, Error> {
107 if self.signature.len() != CRYPTO_SIGN_SECRETKEYBYTES {
108 return Err(Error::TokenSignatureSize(format!(
109 "Signature secret key should be {} bytes",
110 CRYPTO_SIGN_SECRETKEYBYTES
111 )));
112 }
113
114 let mut secret_key_bytes = [0u8; CRYPTO_SIGN_SECRETKEYBYTES];
116 secret_key_bytes.copy_from_slice(&self.signature);
117
118 let keypair: SigningKeyPair<[u8; CRYPTO_SIGN_PUBLICKEYBYTES], [u8; CRYPTO_SIGN_SECRETKEYBYTES]> = SigningKeyPair::from_secret_key(secret_key_bytes);
119
120 return Ok(keypair.public_key.to_vec());
121 }
122}