1
0
Fork 0
mirror of https://gitlab.com/hagrid-keyserver/hagrid.git synced 2023-02-13 20:55:02 -05:00
hagrid-keyserver--hagrid/src/tokens.rs

137 lines
3.8 KiB
Rust
Raw Permalink Normal View History

2019-04-02 08:54:40 -04:00
use sealed_state::SealedState;
use serde_json;
use serde::{Serialize,de::DeserializeOwned};
2019-04-05 11:07:40 -04:00
use Result;
2019-04-02 08:54:40 -04:00
pub trait StatelessSerializable : Serialize + DeserializeOwned {
}
2019-04-02 08:54:40 -04:00
pub struct Service {
sealed_state: SealedState,
validity: u64,
}
#[derive(Serialize,Deserialize)]
struct Token {
#[serde(rename = "c")]
creation: u64,
#[serde(rename = "p")]
payload: String,
2019-04-02 08:54:40 -04:00
}
impl Service {
pub fn init(secret: &str, validity: u64) -> Self {
let sealed_state = SealedState::new(secret);
Service { sealed_state, validity }
}
2019-05-20 17:17:50 -04:00
pub fn create(&self, payload_content: &impl StatelessSerializable) -> String {
let payload = serde_json::to_string(payload_content).unwrap();
2019-04-02 08:54:40 -04:00
let creation = current_time();
let token = Token { creation, payload };
2019-04-02 08:54:40 -04:00
let token_serialized = serde_json::to_string(&token).unwrap();
let token_sealed = self.sealed_state.seal(&token_serialized);
base64::encode_config(&token_sealed, base64::URL_SAFE_NO_PAD)
}
pub fn check<T>(&self, token_encoded: &str) -> Result<T>
where T: StatelessSerializable {
2019-04-05 11:07:40 -04:00
let token_sealed = base64::decode_config(&token_encoded, base64::URL_SAFE_NO_PAD)
.map_err(|_| failure::err_msg("invalid b64"))?;
let token_str = self.sealed_state.unseal(token_sealed)
.map_err(|_| failure::err_msg("failed to validate"))?;
2019-04-02 08:54:40 -04:00
let token: Token = serde_json::from_str(&token_str)
2019-04-05 11:07:40 -04:00
.map_err(|_| failure::err_msg("failed to deserialize"))?;
2019-04-02 08:54:40 -04:00
let elapsed = current_time() - token.creation;
if elapsed > self.validity {
2019-04-05 11:07:40 -04:00
Err(failure::err_msg("Token has expired!"))?;
2019-04-02 08:54:40 -04:00
}
let payload: T = serde_json::from_str(&token.payload)
.map_err(|_| failure::err_msg("failed to deserialize payload"))?;
Ok(payload)
2019-04-02 08:54:40 -04:00
}
}
#[cfg(not(test))]
fn current_time() -> u64 {
2019-04-16 09:51:13 -04:00
use std::time::SystemTime;
2019-04-02 08:54:40 -04:00
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs()
}
#[cfg(test)]
fn current_time() -> u64 {
12345678
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug,Serialize,Deserialize,Clone,PartialEq)]
struct TestStruct1 {
payload: String,
}
impl StatelessSerializable for TestStruct1 {
}
#[derive(Debug,Serialize,Deserialize,Clone,PartialEq)]
struct TestStruct2 {
something: String,
}
impl StatelessSerializable for TestStruct2 {
}
2019-04-02 08:54:40 -04:00
#[test]
fn test_create_check() {
let payload = TestStruct1 { payload: "hello".to_owned() };
2019-04-02 08:54:40 -04:00
let mt = Service::init("secret", 60);
2019-05-20 17:17:50 -04:00
let token = mt.create(&payload);
2019-04-02 08:54:40 -04:00
// println!("{}", &token);
// assert!(false);
let check_result = mt.check(&token);
assert_eq!(payload, check_result.unwrap());
2019-04-02 08:54:40 -04:00
}
#[test]
fn test_ok() {
let payload = TestStruct1 { payload: "hello".to_owned() };
let token = "rwM_S9gZaRQaf6DLvmWtZSipQhH_G5ronSIJv2FrMdwGBPSYYQ-1jaP58dTHU5WuC14vb8jxmz2Xf_b3pqzpCGTEJj9drm4t";
2019-04-02 08:54:40 -04:00
let mt = Service::init("secret", 60);
let check_result = mt.check(token);
assert_eq!(payload, check_result.unwrap());
}
#[test]
fn test_bad_type() {
let payload = TestStruct1 { payload: "hello".to_owned() };
let mt = Service::init("secret", 60);
2019-05-20 17:17:50 -04:00
let token = mt.create(&payload);
let check_result = mt.check::<TestStruct2>(&token);
assert!(check_result.is_err());
2019-04-02 08:54:40 -04:00
}
#[test]
fn test_expired() {
// {"c":12345078,"f":"D4AB192964F76A7F8F8A9B357BD18320DEADFA11"}
2019-04-02 10:06:42 -04:00
let token = "tqDOpM5mdNSTCDzyyy6El_Chpj1k-ozzw4AHy-3KJhxkXs8A17GJYVq7CHbgsYMc7n5irdzOJ-IvForV_HiVSnZYpnS_BiORWN6FISVmnwlMxDBIGUqa1XDiBLD7UW8";
2019-04-02 08:54:40 -04:00
let mt = Service::init("secret", 60);
let check_result = mt.check::<TestStruct1>(token);
2019-04-02 08:54:40 -04:00
2019-04-16 09:51:13 -04:00
assert!(check_result.is_err());
2019-04-02 08:54:40 -04:00
}
}