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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use crate::{Extractor, Error, http::{Request, Response}, additional::Additional};
use std::collections::HashMap;
use cookie::Cookie;
use std::sync::Arc;
use ring::hmac::{self, Key};
pub struct Session {
values: HashMap<String, String>,
changed: bool,
secret: Arc<Key>
}
impl Session {
fn new(secret: Arc<Key>) -> Session {
Session{
values: HashMap::new(),
changed: false,
secret
}
}
}
impl Session {
pub fn set<A: Into<String>, B: Into<String>>(&mut self, key: A, value: B) {
self.changed = true;
self.values.insert(key.into(), value.into());
}
pub fn get<T: AsRef<str>>(&self, key: T) -> Option<&String> {
self.values.get(key.as_ref())
}
pub fn clear(&mut self) {
self.changed = true;
self.values.clear();
}
pub fn apply(self, mut req: Response) -> Response {
if self.changed {
let content = serde_json::to_string(&self.values).unwrap();
let signature = base64::encode(hmac::sign(&self.secret, content.as_bytes()).as_ref());
let cookie = Cookie::new("cataclysm-session", format!("{}{}", signature, content));
req.headers.insert("Set-Cookie".to_string(), format!("{}", cookie.encoded()));
req
} else {
req
}
}
}
impl<T: Sync> Extractor<T> for Session {
fn extract(req: &Request, additional: Arc<Additional<T>>) -> Result<Self, Error> {
if let Some(cookie_string) = req.headers.get("Cookie") {
match Cookie::parse_encoded(cookie_string) {
Ok(cookie) => {
let value = cookie.value();
if value.len() < 44 {
Ok(Session::new(additional.secret.clone()))
} else {
let signature = value.get(0..44).unwrap();
let content = value.get(44..value.len()).unwrap();
match serde_json::from_str(content) {
Ok(values) => {
match base64::decode(signature) {
Ok(tag) => {
match hmac::verify(&additional.secret, content.as_bytes(), &tag) {
Ok(_) => Ok(Session{
values,
changed: false,
secret: additional.secret.clone()
}),
Err(_) => Ok(Session::new(additional.secret.clone()))
}
},
Err(_) => Ok(Session::new(additional.secret.clone()))
}
},
Err(_) => Ok(Session::new(additional.secret.clone()))
}
}
},
Err(_e) => Ok(Session::new(additional.secret.clone()))
}
} else {
return Ok(Session::new(additional.secret.clone()))
}
}
}