use std::{ collections::HashMap, fs::{self, File}, sync::Arc, io::Read, }; use axum::{extract::Query, middleware::Next, response::Response, Extension}; use axum_macros::debug_handler; use chrono::{Datelike, TimeZone, Utc}; use hyper::Request; use ring::{rand::SystemRandom, signature::Ed25519KeyPair}; use tracing::debug; use uuid::Uuid; use std::io::Write; use crate::{ errors::{NoneResult, ServiceError, StringResult, TokenResult}, State, }; /** * Takes in a request to create a new token with a secret key that gets printed * to stdout and, if it matches, returns a valid PASETO token that can be used * for future authentication */ #[debug_handler] pub async fn begin( Query(params): Query>, Extension(state): Extension>, ) -> TokenResult { if let Some(k) = params.get("key") { if k == &state.gen_key { let dt = Utc::now(); let exp = Utc .ymd(dt.year() + 1, dt.month(), dt.day()) .and_hms(0, 0, 0); let kp = load_or_gen_keypair()?; let token = match paseto::tokens::PasetoBuilder::new() .set_ed25519_key(&kp) .set_issued_at(Some(dt)) .set_expiration(&exp) .set_issuer("solard") .set_audience("solard") .set_not_before(&Utc::now()) .build() { Ok(token) => token, Err(_) => { return Err(ServiceError::Generic(String::from( "could not generate paseto key", ))); } }; return Ok(token.to_string()); } else { return Err(ServiceError::NotAuthorized); } } else { return Err(ServiceError::Generic("No key supplied".to_string())); } } pub async fn requires_auth(req: Request, next: Next) -> Result { let auth_header = req .headers() .get(axum::http::header::AUTHORIZATION) .and_then(|h| h.to_str().ok()); match auth_header { Some(h) => { debug!("Header: {}", h); let kp = load_or_gen_keypair()?; debug!("KP: {:?}", kp); match paseto::tokens::validate_public_token(h, None, &paseto::tokens::PasetoPublicKey::ED25519KeyPair(&kp), &paseto::tokens::TimeBackend::Chrono) { Ok(_) => Ok(next.run(req).await), Err(_) => Err(ServiceError::NotAuthorized) } } None => Err(ServiceError::NotAuthorized), } } fn load_or_gen_keypair() -> Result { let kp: Ed25519KeyPair; let mut file = match File::open(".keypair") { Ok(f) => f, Err(_) => { debug!("File does not exist, creating at .keypair"); File::create(".keypair").unwrap() } }; if let Ok(c) = fs::read(".keypair") { if c.len() == 0 { debug!("No keypair found. Generating..."); let srand = SystemRandom::new(); let pkcs8 = Ed25519KeyPair::generate_pkcs8(&srand)?; fs::write(".keypair", pkcs8.as_ref()).unwrap(); debug!("Written keypair {:?} to .keypair", pkcs8.as_ref()); kp = Ed25519KeyPair::from_pkcs8(pkcs8.as_ref())?; } else { debug!("Found keypair file, contents: {:?}", c); kp = Ed25519KeyPair::from_pkcs8(&c)?; debug!("Loaded keypair from file"); } } else { debug!("Generating new keypair"); let srand = SystemRandom::new(); let pkcs8 = Ed25519KeyPair::generate_pkcs8(&srand)?; fs::write(".keypair", pkcs8.as_ref()).unwrap(); debug!("Written keypair {:?} to .keypair", pkcs8.as_ref()); kp = Ed25519KeyPair::from_pkcs8(pkcs8.as_ref())?; } Ok(kp) }