use std::{error::Error, time::SystemTime}; use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, TokenData, Validation}; use serde::{Deserialize, Serialize}; use tokio::{fs::File, io::AsyncReadExt}; use toml::Table; use crate::{ messages::{ authentication::{ AuthenticationTokenRequest, AuthenticationTokenResponse, TokenExtensionRequest, TokenExtensionResponse, }, InstanceAuthenticated, }, model::{instance::Instance, user::User}, }; #[derive(Debug, Serialize, Deserialize)] struct UserTokenMetadata { user: User, generated_for: Instance, exp: u64, } pub struct AuthenticationTokenGranter { pub config: Table, } impl AuthenticationTokenGranter { pub async fn token_request( &mut self, raw_request: InstanceAuthenticated, ) -> Result> { let request = raw_request.inner().await; info!("Ensuring token request is from the same instance..."); raw_request .validate(&Instance { url: String::from("giterated.dev"), }) .await .unwrap(); let secret_key = self.config["authentication"]["secret_key"] .as_str() .unwrap(); let private_key = { let mut file = File::open(self.config["keys"]["private"].as_str().unwrap()) .await .unwrap(); let mut key = vec![]; file.read_to_end(&mut key).await.unwrap(); key }; if request.secret_key != secret_key { error!("Incorrect secret key!"); panic!() } let encoding_key = EncodingKey::from_rsa_pem(&private_key).unwrap(); let claims = UserTokenMetadata { user: User { username: String::from("ambee"), instance: Instance { url: String::from("giterated.dev"), }, }, generated_for: Instance { url: String::from("giterated.dev"), }, exp: (SystemTime::UNIX_EPOCH.elapsed().unwrap() + std::time::Duration::from_secs(24 * 60 * 60)) .as_secs(), }; let token = encode( &jsonwebtoken::Header::new(Algorithm::RS256), &claims, &encoding_key, ) .unwrap(); Ok(AuthenticationTokenResponse { token }) } pub async fn extension_request( &mut self, raw_request: InstanceAuthenticated, ) -> Result> { let request = raw_request.inner().await; // let server_public_key = { // let mut file = File::open(self.config["keys"]["public"].as_str().unwrap()) // .await // .unwrap(); // let mut key = String::default(); // file.read_to_string(&mut key).await.unwrap(); // key // }; let server_public_key = public_key(&Instance { url: String::from("giterated.dev"), }) .await .unwrap(); println!("Our Public Key:\n{}", server_public_key); let verification_key = DecodingKey::from_rsa_pem(server_public_key.as_bytes()).unwrap(); let data: TokenData = decode( &request.token, &verification_key, &Validation::new(Algorithm::RS256), ) .unwrap(); info!("Token Extension Request Token validated"); let secret_key = self.config["authentication"]["secret_key"] .as_str() .unwrap(); if request.secret_key != secret_key { error!("Incorrect secret key!"); panic!() } // Validate request raw_request .validate(&data.claims.generated_for) .await .unwrap(); info!("Validated request for key extension"); let private_key = { let mut file = File::open(self.config["keys"]["private"].as_str().unwrap()) .await .unwrap(); let mut key = vec![]; file.read_to_end(&mut key).await.unwrap(); key }; let encoding_key = EncodingKey::from_rsa_pem(&private_key).unwrap(); let claims = UserTokenMetadata { // TODO: Probably exploitable user: data.claims.user, generated_for: data.claims.generated_for, exp: (SystemTime::UNIX_EPOCH.elapsed().unwrap() + std::time::Duration::from_secs(24 * 60 * 60)) .as_secs(), }; let token = encode( &jsonwebtoken::Header::new(Algorithm::RS256), &claims, &encoding_key, ) .unwrap(); Ok(TokenExtensionResponse { new_token: Some(token), }) } } async fn public_key(instance: &Instance) -> Result> { let key = reqwest::get(format!("https://{}/.giterated/pubkey.pem", instance.url)) .await? .text() .await?; Ok(key) }