use std::{fmt, str};
use crate::model::id::UserId;
pub fn validate(token: impl AsRef<str>) -> Result<(), InvalidToken> {
parse(token).map(|_| ()).ok_or(InvalidToken)
}
#[derive(Debug)]
pub struct InvalidToken;
impl std::error::Error for InvalidToken {}
impl fmt::Display for InvalidToken {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("The provided token was invalid")
}
}
pub fn parse(token: impl AsRef<str>) -> Option<(UserId, i64)> {
let mut parts = token.as_ref().trim_start_matches("Bot ").split('.');
let user_id = base64::decode_config(parts.next()?, base64::URL_SAFE).ok()?;
let user_id = UserId(str::from_utf8(&user_id).ok()?.parse().ok()?);
let timestamp = parts.next()?;
if timestamp.len() < 6 {
return None;
}
let timestamp_bytes = base64::decode_config(timestamp, base64::URL_SAFE).ok()?;
let mut timestamp = 0;
for byte in timestamp_bytes {
timestamp *= 256;
timestamp += byte as i64;
}
if timestamp < 1_293_840_000 {
timestamp += 1_293_840_000;
}
base64::decode_config(parts.next()?, base64::URL_SAFE).ok()?;
Some((user_id, timestamp))
}