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
use crate::prelude::*;
use bundles::{DigestWrite, Digester};
#[derive(Clone,Serialize,Deserialize)]
pub enum AssetUrlKey {
Dummy,
Y(AssetUrlKeyRaw),
}
#[derive(Error,Debug,Copy,Clone,Serialize)]
pub struct BadAssetUrlToken;
display_as_debug!{BadAssetUrlToken}
#[derive(Clone)]
pub struct AssetUrlToken(AssetUrlTokenRaw);
type AssetUrlKeyRaw = [u8; 32];
impl AssetUrlKey {
pub fn token<V>(&self, what: &str, v: V) -> AssetUrlToken
where V: Serialize {
let k = match self {
AssetUrlKey::Y(k) => k,
_ => panic!("dummy AssetUrlKey being used!"),
};
let mut dw = DigestWrite::sink();
write!(dw, "{}\0", what).unwrap();
dw.write_all(&k[..]).unwrap();
rmp_serde::encode::write(&mut dw, &v).expect("serialize failed!");
AssetUrlToken(dw.finish().0)
}
#[throws(BadAssetUrlToken)]
pub fn check<V>(&self, what: &str, v: &V, got: &AssetUrlToken)
-> Authorisation<V>
where V: Serialize {
let exp = self.token(what, v);
if ! bool::from(ConstantTimeEq::ct_eq(
&exp.0[..],
&got.0[..],
)) { throw!(BadAssetUrlToken) }
else { Authorisation::promise_for(v) }
}
}
impl Debug for AssetUrlKey {
#[throws(fmt::Error)]
fn fmt(&self, f: &mut Formatter) {
use AssetUrlKey::*;
match self {
Y(_) => write!(f, "AssetUrlKey::Y{{..}}")?,
Dummy => write!(f, "AssetUrlKey::Dummy")?,
}
}
}
impl Default for AssetUrlKey { fn default() -> Self { Self::Dummy } }
impl AssetUrlKey {
#[throws(IE)]
pub fn new_random() -> AssetUrlKey {
let mut buf: AssetUrlKeyRaw = default();
let mut rng: rand::rngs::ThreadRng = thread_rng();
rand::RngCore::try_fill_bytes(&mut rng, &mut buf)
.context("generate new AssetUrlKey")?;
AssetUrlKey::Y(buf)
}
}
type AssetUrlTokenRaw = digest::Output<Digester>;
impl Debug for AssetUrlToken {
#[throws(fmt::Error)]
fn fmt(&self, f: &mut Formatter) { write!(f, "AssetUrlToken{{..}}")?; }
}
impl Display for AssetUrlToken {
#[throws(fmt::Error)]
fn fmt(&self, f: &mut Formatter) {
f.write_str(&base64::encode_config(&self.0, base64::URL_SAFE_NO_PAD))?
}
}
impl FromStr for AssetUrlToken {
type Err = BadAssetUrlToken;
#[throws(BadAssetUrlToken)]
fn from_str(s: &str) -> Self {
let mut buf: AssetUrlTokenRaw = default();
let l = base64::decode_config_slice(
s.as_bytes(), base64::URL_SAFE_NO_PAD, &mut buf)
.map_err(|_| BadAssetUrlToken)?;
if l != buf.len() { throw!(BadAssetUrlToken) }
AssetUrlToken(buf)
}
}
hformat_as_display!{AssetUrlToken}