use std::{any::type_name, fmt::Debug, ops::Deref}; use rsa::{ pkcs1::DecodeRsaPrivateKey, pss::SigningKey, sha2::Sha256, signature::{RandomizedSigner, SignatureEncoding}, RsaPrivateKey, }; use serde::{Deserialize, Serialize}; use tracing::info; use super::{instance::Instance, user::User}; #[derive(Debug, Serialize, Deserialize)] pub struct UserTokenMetadata { pub user: User, pub generated_for: Instance, pub exp: u64, } #[derive(Debug)] pub struct Authenticated { pub target_instance: Option, pub source: Vec>, pub message_type: String, pub message: T, } #[derive(Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct AuthenticatedPayload { pub target_instance: Option, pub source: Vec, pub message_type: String, pub payload: Vec, } impl From> for AuthenticatedPayload { fn from(mut value: Authenticated) -> Self { let payload = bincode::serialize(&value.message).unwrap(); AuthenticatedPayload { target_instance: value.target_instance, source: value .source .drain(..) .map(|provider| provider.as_ref().authenticate(&payload)) .collect::>(), message_type: value.message_type, payload, } } } pub trait AuthenticationSourceProvider: Debug { fn authenticate(&self, payload: &Vec) -> AuthenticationSource; } pub trait AuthenticationSourceProviders: Debug { fn authenticate_all(&self, payload: &Vec) -> Vec; } impl AuthenticationSourceProviders for A where A: AuthenticationSourceProvider, { fn authenticate_all(&self, payload: &Vec) -> Vec { vec![self.authenticate(payload)] } } impl AuthenticationSourceProviders for (A, B) where A: AuthenticationSourceProvider, B: AuthenticationSourceProvider, { fn authenticate_all(&self, payload: &Vec) -> Vec { let (first, second) = self; vec![first.authenticate(payload), second.authenticate(payload)] } } impl Authenticated { pub fn new(message: T) -> Self { Self { source: vec![], message_type: type_name::().to_string(), message, target_instance: None, } } pub fn new_for(instance: impl ToOwned, message: T) -> Self { Self { source: vec![], message_type: type_name::().to_string(), message, target_instance: Some(instance.to_owned()), } } pub fn new_empty(message: T) -> Self { Self { source: vec![], message_type: type_name::().to_string(), message, target_instance: None, } } pub fn append_authentication(&mut self, authentication: P) { let message_payload = serde_json::to_vec(&self.message).unwrap(); info!( "Verifying payload: {}", std::str::from_utf8(&message_payload).unwrap() ); self.source.push(Box::new(authentication) as Box); } pub fn into_payload(self) -> AuthenticatedPayload { self.into() } } mod verified {} #[derive(Clone, Debug)] pub struct UserAuthenticator { pub user: User, pub token: UserAuthenticationToken, } impl AuthenticationSourceProvider for UserAuthenticator { fn authenticate(&self, _payload: &Vec) -> AuthenticationSource { AuthenticationSource::User { user: self.user.clone(), token: self.token.clone(), } } } #[derive(Debug, Clone)] pub struct InstanceAuthenticator<'a> { pub instance: Instance, pub private_key: &'a str, } impl AuthenticationSourceProvider for InstanceAuthenticator<'_> { fn authenticate(&self, payload: &Vec) -> AuthenticationSource { let mut rng = rand::thread_rng(); let private_key = RsaPrivateKey::from_pkcs1_pem(self.private_key).unwrap(); let signing_key = SigningKey::::new(private_key); let signature = signing_key.sign_with_rng(&mut rng, &payload); AuthenticationSource::Instance { instance: self.instance.clone(), // TODO: Actually parse signature from private key signature: InstanceSignature(signature.to_bytes().into_vec()), } } } #[repr(transparent)] #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct UserAuthenticationToken(String); impl From for UserAuthenticationToken { fn from(value: String) -> Self { Self(value) } } impl ToString for UserAuthenticationToken { fn to_string(&self) -> String { self.0.clone() } } impl AsRef for UserAuthenticationToken { fn as_ref(&self) -> &str { &self.0 } } #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct InstanceSignature(Vec); impl AsRef<[u8]> for InstanceSignature { fn as_ref(&self) -> &[u8] { &self.0 } } #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] pub enum AuthenticationSource { User { user: User, token: UserAuthenticationToken, }, Instance { instance: Instance, signature: InstanceSignature, }, }