use std::{collections::HashMap, fs::{self, File}};
use axum::{extract::Query, Extension};
use axum_macros::debug_handler;
use chrono::{Utc, TimeZone, Datelike};
use ring::{rand::SystemRandom, signature::Ed25519KeyPair};
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<HashMap<String, String>>, Extension(state): Extension<State>) -> 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()));
}
}
fn load_or_gen_keypair() -> Result<Ed25519KeyPair, ServiceError> {
let kp: Ed25519KeyPair;
if let Ok(c) = fs::read_to_string(".keypair") {
kp = Ed25519KeyPair::from_pkcs8(&hex::decode(c)?)?;
} else {
let srand = SystemRandom::new();
let pkcs8 = Ed25519KeyPair::generate_pkcs8(&srand)?;
let mut file = File::open(".keypair").unwrap();
file.write(pkcs8.as_ref());
kp = Ed25519KeyPair::from_pkcs8(pkcs8.as_ref())?;
}
Ok(kp)
}