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
use std::fmt; fn parse_hex(hex: impl AsRef<str>) -> Option<Vec<u8>> { let hex = hex.as_ref().as_bytes(); if hex.len() % 2 != 0 { return None; } hex.chunks_exact(2) .map(|byte| { let (a, b) = match byte { &[a, b] => (a, b), _ => unreachable!(), }; let a = match a { b'0'..=b'9' => a - b'0', b'A'..=b'F' => a - b'A' + 10, b'a'..=b'f' => a - b'a' + 10, _ => return None, }; let b = match b { b'0'..=b'9' => b - b'0', b'A'..=b'F' => b - b'A' + 10, b'a'..=b'f' => b - b'a' + 10, _ => return None, }; Some(a << 4 | b) }) .collect::<Option<Vec<_>>>() } #[derive(Clone)] pub struct Application { public_key: ring::signature::UnparsedPublicKey<Vec<u8>>, } impl Application { pub fn from_public_key(public_key: impl AsRef<str>) -> crate::Result<Self> { let public_key = parse_hex(public_key).ok_or(crate::Error::KeyFormat)?; let public_key = ring::signature::UnparsedPublicKey::new(&ring::signature::ED25519, public_key); Ok(Self { public_key }) } pub fn verify(&self, body: &[u8], timestamp: &str, signature: &str) -> crate::Result<()> { let timestamp = timestamp.as_bytes().to_vec(); let signature = parse_hex(signature); let signature = if let Some(v) = signature { v } else { return Err(crate::Error::SignatureFormat); }; let mut message = timestamp; message.extend_from_slice(body); self.public_key .verify(&message, &signature) .map_err(|_| crate::Error::Verification) } } impl fmt::Debug for Application { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Application") .field("public_key", &format_args!("(...)")) .finish() } } #[derive(Debug)] #[non_exhaustive] pub enum Error { KeyFormat, SignatureFormat, Verification, } impl Error { pub fn http_status(&self) -> u16 { match self { Error::KeyFormat | Error::SignatureFormat => 400, Error::Verification => 401, } } } impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::KeyFormat => f.write_str("invalid public key format"), Error::SignatureFormat => f.write_str("invalid signature format"), Error::Verification => f.write_str("verification failed"), } } } pub type Result<T> = std::result::Result<T, Error>;