1use crate::{recover_pubkey, sign_message, verify_message};
2
3use anyhow::{anyhow, Result};
4use base64::{decode_config, encode_config, URL_SAFE};
5use secp256k1::{PublicKey, SecretKey};
6use std::convert::TryInto;
7
8#[derive(Debug)]
9pub struct Token(u32, Option<[u8; 65]>);
10
11fn now() -> u32 {
12 use std::time::{SystemTime, UNIX_EPOCH};
13 let start = SystemTime::now();
14 let since_the_epoch = start
15 .duration_since(UNIX_EPOCH)
16 .expect("Time went backwards");
17 since_the_epoch.as_secs() as u32
18}
19
20pub fn u32_to_bytes(input: u32) -> [u8; 4] {
21 input.to_be_bytes()
22}
23pub fn bytes_to_u32(bytes: [u8; 4]) -> u32 {
24 u32::from_be_bytes(bytes)
25}
26
27pub fn base64_encode(input: &[u8]) -> String {
28 encode_config(input, URL_SAFE)
29}
30pub fn base64_decode(input: &str) -> Result<Vec<u8>> {
31 let r = decode_config(input, URL_SAFE)?;
32 Ok(r)
33}
34
35impl Token {
36 pub fn new() -> Self {
38 Self(now(), None)
39 }
40 pub fn set_sig(&mut self, sig: [u8; 65]) {
41 self.1 = Some(sig)
42 }
43 pub fn from_base64(s: &str) -> Result<Self> {
44 let bytes = base64_decode(s)?;
45 if bytes.len() != 69 {
46 return Err(anyhow!("wrong length".to_string()));
47 }
48 let ts: [u8; 4] = bytes[..4].try_into()?;
49 let sig: [u8; 65] = bytes[4..].try_into()?;
50 Ok(Self(bytes_to_u32(ts), Some(sig)))
51 }
52 pub fn expected_len(&self) -> usize {
53 69
54 }
55 pub fn sign(&self, secret_key: &SecretKey) -> Result<Vec<u8>> {
57 let mut ts = u32_to_bytes(self.0).to_vec();
58 let sig = sign_message(&ts, secret_key)?;
59 ts.extend(sig);
60 assert_eq!(ts.len(), self.expected_len());
61 Ok(ts)
62 }
63 pub fn sign_to_base64(&self, secret_key: &SecretKey) -> Result<String> {
65 let s = self.sign(secret_key)?;
66 Ok(base64_encode(&s))
67 }
68 pub fn verify(&self, public_key: &PublicKey) -> Result<()> {
70 if let None = self.1 {
71 return Err(anyhow!("no sig".to_string()));
72 }
73 let msg = u32_to_bytes(self.0);
74 verify_message(&msg.to_vec(), &self.1.unwrap(), public_key)
75 }
76 pub fn recover(&self) -> Result<PublicKey> {
78 if let None = self.1 {
79 return Err(anyhow!("no sig".to_string()));
80 }
81 let msg = u32_to_bytes(self.0);
82 recover_pubkey(&msg.to_vec(), &self.1.unwrap())
83 }
84 pub fn recover_within(&self, secs: u32) -> Result<PublicKey> {
86 if let None = self.1 {
87 return Err(anyhow!("no sig".to_string()));
88 }
89 if self.0 < now() - secs {
90 return Err(anyhow!("expired".to_string()));
91 }
92 let msg = u32_to_bytes(self.0);
93 recover_pubkey(&msg.to_vec(), &self.1.unwrap())
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use crate::token::*;
100 use secp256k1::{PublicKey, Secp256k1, SecretKey};
101
102 fn secret_key() -> SecretKey {
103 SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order")
104 }
105
106 fn a_token() -> String {
107 "YvM0wyAZBWdHaVsS4sqy-ub3X0JRx7zVTY9O6aL0q_CIV9zOKykO_grPE4DSelinHNX9pTFZ3wEoLhg5QT7EVZpOlj0x".to_string()
108 }
109
110 #[test]
111 fn test_token() {
112 let sk = secret_key();
113 let mut t = Token::new();
114 let res = t.sign(&sk).expect("couldnt make token");
115 println!("===> {}", base64_encode(&res));
116 let secp = Secp256k1::new();
117 let public_key = PublicKey::from_secret_key(&secp, &sk);
118 let sig: [u8; 65] = res[4..].try_into().expect("wrong sig length");
119 t.set_sig(sig);
120 t.verify(&public_key).expect("couldnt verify");
121 }
122
123 #[test]
124 fn test_decode() {
125 let sk = secret_key();
126 let secp = Secp256k1::new();
127 let public_key = PublicKey::from_secret_key(&secp, &sk);
128 let t = Token::from_base64(&a_token()).expect("couldnt parse base64");
129 t.verify(&public_key).expect("failed to verify");
130 }
131
132 #[test]
133 fn test_recover() {
134 let sk = secret_key();
135 let secp = Secp256k1::new();
136 let public_key = PublicKey::from_secret_key(&secp, &sk);
137 let t = Token::from_base64(&a_token()).expect("couldnt parse base64");
138 let pk2 = t.recover().expect("failed to verify");
139 assert_eq!(public_key, pk2);
140 }
141 #[test]
142 fn test_recover_within() {
143 let sk = secret_key();
144 let t1 = Token::new();
145 let res = t1.sign(&sk).expect("couldnt make token");
146 let token = base64_encode(&res);
147 let secp = Secp256k1::new();
148 let public_key = PublicKey::from_secret_key(&secp, &sk);
149 let t = Token::from_base64(&token).expect("couldnt parse base64");
150 let pk2 = t.recover_within(10).expect("failed to verify");
151 assert_eq!(public_key, pk2);
152 }
153
154 #[test]
155 fn test_check_timestamp() {
156 let sk = secret_key();
157 let t1 = Token::new();
158 let token = t1.sign_to_base64(&sk).expect("couldnt make token");
159 let t = Token::from_base64(&token).expect("couldnt parse base64");
161 std::thread::sleep(std::time::Duration::from_secs(2));
162 if t.recover_within(1).is_ok() {
163 panic!("should have expired")
164 }
165 }
166
167 #[test]
168 fn test_tribe() {
169 let pk = hex::decode("02290714deafd0cb33d2be3b634fc977a98a9c9fa1dd6c53cf17d99b350c08c67b")
170 .expect("hex fail");
171 let pubkey = PublicKey::from_slice(&pk[..]).expect("couldnt extract pubkey");
172 let tribe = "XuOp5B9kC3CcL52svtl_LJJJFbV1OTgnq7thtOjdKJMnOuETIw_hlLkVfonozVIwz5wADlya_i946GiKFZAgMto0cDuk";
173 let token = Token::from_base64(tribe).expect("couldnt parse base64");
174 token.verify(&pubkey).expect("nope verify");
175 let pk2 = token.recover().expect("recover failed");
176 assert_eq!(pubkey, pk2);
177 }
178}