use anyhow::Error; use giterated_models::{ messages::authentication::{AuthenticationTokenResponse, TokenExtensionResponse}, model::{ authenticated::{UserAuthenticationToken, UserTokenMetadata}, instance::Instance, user::User, }, }; use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, TokenData, Validation}; use std::time::SystemTime; use tokio::{fs::File, io::AsyncReadExt}; use toml::Table; pub struct AuthenticationTokenGranter { pub config: Table, pub instance: Instance, } impl AuthenticationTokenGranter { async fn private_key(&self) -> Vec { let _secret_key = self.config["authentication"]["secret_key"] .as_str() .unwrap(); let mut file = File::open( self.config["giterated"]["keys"]["private"] .as_str() .unwrap(), ) .await .unwrap(); let mut key = vec![]; file.read_to_end(&mut key).await.unwrap(); key } pub(crate) async fn create_token_for( &mut self, user: &User, generated_for: &Instance, ) -> String { let private_key = self.private_key().await; let encoding_key = EncodingKey::from_rsa_pem(&private_key).unwrap(); let claims = UserTokenMetadata { user: user.clone(), generated_for: generated_for.clone(), exp: (SystemTime::UNIX_EPOCH.elapsed().unwrap() + std::time::Duration::from_secs(24 * 60 * 60)) .as_secs(), }; encode( &jsonwebtoken::Header::new(Algorithm::RS256), &claims, &encoding_key, ) .unwrap() } pub async fn token_request( &mut self, issued_for: impl ToOwned, username: String, _password: String, ) -> Result { let private_key = { let mut file = File::open( self.config["giterated"]["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 { user: User { username, instance: self.instance.clone(), }, generated_for: issued_for.to_owned(), 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: UserAuthenticationToken::from(token), }) } pub async fn extension_request( &mut self, issued_for: &Instance, token: UserAuthenticationToken, ) -> Result { let server_public_key = public_key(&self.instance).await.unwrap(); let verification_key = DecodingKey::from_rsa_pem(server_public_key.as_bytes()).unwrap(); let data: TokenData = decode( token.as_ref(), &verification_key, &Validation::new(Algorithm::RS256), ) .unwrap(); if data.claims.generated_for != *issued_for { panic!() } info!("Token Extension Request Token validated"); let private_key = { let mut file = File::open( self.config["giterated"]["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: issued_for.clone(), 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) }