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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
use evmap;
use std::sync::{Arc, Mutex, MutexGuard};
use evmap::{WriteHandle, ReadHandle};
use std::time;
use std::str;
use std::hash;
use random;
use random::Source;
// cookie is a 64-byte printable-characters-only array
pub struct CookieKey([u8; 64]);
impl PartialEq for CookieKey {
fn eq(&self, other: &CookieKey) -> bool {
self.0[..] == other.0[..]
}
}
impl Eq for CookieKey {}
impl hash::Hash for CookieKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
for i in self.0.iter() {
state.write_u8(*i)
}
}
}
impl Clone for CookieKey {
fn clone(&self) -> CookieKey {
CookieKey(self.0)
}
}
impl ToString for CookieKey {
fn to_string(&self) -> String {
unsafe { str::from_utf8_unchecked(&self.0).to_string() }
}
}
pub struct CookieStore {
pub reader: ReadHandle<CookieKey, u64>,
pub writer: Arc<Mutex<WriteHandle<CookieKey, u64>>>,
}
pub fn to_cookie(data: &str) -> Option<CookieKey> {
if data.len() == 64 {
let mut cookie_key: [u8; 64] = [0; 64];
cookie_key.copy_from_slice(data.as_bytes());
Some(CookieKey(cookie_key))
} else {
None
}
}
static HEXTABLE: [u8; 16] = [b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9',
b'A', b'B', b'C', b'D', b'E', b'F'];
impl Clone for CookieStore {
fn clone(&self) -> Self {
CookieStore {
reader: self.reader.clone(),
writer: self.writer.clone(),
}
}
}
impl CookieStore {
pub fn new() -> CookieStore {
let (r, w) = evmap::new::<CookieKey, u64>();
CookieStore {
reader: r,
writer: Arc::new(Mutex::new(w)),
}
}
pub fn create_authenticated_cookie(&self) -> CookieKey {
let mut r = random::default();
let mut key = [0; 64];
for it in key.iter_mut() {
let random: u8 = r.read();
let value = HEXTABLE[(random & 0x0f) as usize];
*it = value;
}
let timeout = time::SystemTime::now() + time::Duration::from_secs(60 * 60 * 24); // 1 day
let timeout = timeout.duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_secs();
{
let mut writer = self.write_handle();
writer.insert(CookieKey(key), timeout);
warn!("Insert: {}", CookieKey(key).to_string());
writer.refresh();
}
CookieKey(key)
}
fn write_handle(&self) -> MutexGuard<WriteHandle<CookieKey, u64>> {
self.writer.lock().unwrap()
}
fn now_unix_epoch() -> u64 {
time::SystemTime::now()
.duration_since(time::SystemTime::UNIX_EPOCH).unwrap().as_secs()
}
/// true -> cookie is valid until time
/// false -> cookie is outdated
pub fn is_cookie_authenticated(&self, key: &CookieKey) -> bool {
let reader = &self.reader;
let value = reader.get_and(key, |v| v[0]);
warn!("Reading {} -> {:?}", key.to_string(), value);
if value.is_none() {
false
} else if value.unwrap() < Self::now_unix_epoch() {
// outdated, remove from map
let mut writer = self.write_handle();
writer.empty(key.clone());
// but no refresh - it's not urgent
false
} else {
true
}
}
pub fn clean_outdated_cookies(&self) {
// unimplemented!()
}
}
|