JavaScript is disabled, refresh for a better experience. ambee/giterated

ambee/giterated

Git repository hosting, collaboration, and discovery for the Fediverse.

Automatically populate the target instance field from the request using MessageTarget trait

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨37da513

⁨giterated-models/src/model/authenticated.rs⁩ - ⁨5746⁩ bytes
Raw
1 use std::{any::type_name, fmt::Debug};
2
3 use rsa::{
4 pkcs1::DecodeRsaPrivateKey,
5 pss::SigningKey,
6 sha2::Sha256,
7 signature::{RandomizedSigner, SignatureEncoding},
8 RsaPrivateKey,
9 };
10 use serde::{Deserialize, Serialize};
11 use tracing::info;
12
13 use crate::messages::MessageTarget;
14
15 use super::{instance::Instance, user::User};
16
17 #[derive(Debug, Serialize, Deserialize)]
18 pub struct UserTokenMetadata {
19 pub user: User,
20 pub generated_for: Instance,
21 pub exp: u64,
22 }
23
24 #[derive(Debug)]
25 pub struct Authenticated<T: Serialize> {
26 pub target_instance: Option<Instance>,
27 pub source: Vec<Box<dyn AuthenticationSourceProvider + Send + Sync>>,
28 pub message_type: String,
29 pub message: T,
30 }
31
32 #[derive(Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
33 pub struct AuthenticatedPayload {
34 pub target_instance: Option<Instance>,
35 pub source: Vec<AuthenticationSource>,
36 pub message_type: String,
37 pub payload: Vec<u8>,
38 }
39
40 impl<T: Serialize> From<Authenticated<T>> for AuthenticatedPayload {
41 fn from(mut value: Authenticated<T>) -> Self {
42 let payload = bincode::serialize(&value.message).unwrap();
43
44 AuthenticatedPayload {
45 target_instance: value.target_instance,
46 source: value
47 .source
48 .drain(..)
49 .map(|provider| provider.as_ref().authenticate(&payload))
50 .collect::<Vec<_>>(),
51 message_type: value.message_type,
52 payload,
53 }
54 }
55 }
56
57 pub trait AuthenticationSourceProvider: Debug {
58 fn authenticate(&self, payload: &Vec<u8>) -> AuthenticationSource;
59 }
60
61 pub trait AuthenticationSourceProviders: Debug {
62 fn authenticate_all(&self, payload: &Vec<u8>) -> Vec<AuthenticationSource>;
63 }
64
65 impl<A> AuthenticationSourceProviders for A
66 where
67 A: AuthenticationSourceProvider,
68 {
69 fn authenticate_all(&self, payload: &Vec<u8>) -> Vec<AuthenticationSource> {
70 vec![self.authenticate(payload)]
71 }
72 }
73
74 impl<A, B> AuthenticationSourceProviders for (A, B)
75 where
76 A: AuthenticationSourceProvider,
77 B: AuthenticationSourceProvider,
78 {
79 fn authenticate_all(&self, payload: &Vec<u8>) -> Vec<AuthenticationSource> {
80 let (first, second) = self;
81
82 vec![first.authenticate(payload), second.authenticate(payload)]
83 }
84 }
85
86 impl<T: Serialize + Debug + MessageTarget> Authenticated<T> {
87 pub fn new(message: T) -> Self {
88 Self {
89 source: vec![],
90 message_type: type_name::<T>().to_string(),
91 target_instance: message.target(),
92 message,
93 }
94 }
95
96 pub fn new_for(instance: impl ToOwned<Owned = Instance>, message: T) -> Self {
97 Self {
98 source: vec![],
99 message_type: type_name::<T>().to_string(),
100 message,
101 target_instance: Some(instance.to_owned()),
102 }
103 }
104
105 pub fn new_empty(message: T) -> Self {
106 Self {
107 source: vec![],
108 message_type: type_name::<T>().to_string(),
109 target_instance: message.target(),
110 message,
111 }
112 }
113
114 pub fn append_authentication<P: AuthenticationSourceProvider + 'static + Send + Sync>(
115 &mut self,
116 authentication: P,
117 ) {
118 let message_payload = serde_json::to_vec(&self.message).unwrap();
119
120 info!(
121 "Verifying payload: {}",
122 std::str::from_utf8(&message_payload).unwrap()
123 );
124
125 self.source
126 .push(Box::new(authentication) as Box<dyn AuthenticationSourceProvider + Send + Sync>);
127 }
128
129 pub fn into_payload(self) -> AuthenticatedPayload {
130 self.into()
131 }
132 }
133
134 mod verified {}
135
136 #[derive(Clone, Debug)]
137 pub struct UserAuthenticator {
138 pub user: User,
139 pub token: UserAuthenticationToken,
140 }
141
142 impl AuthenticationSourceProvider for UserAuthenticator {
143 fn authenticate(&self, _payload: &Vec<u8>) -> AuthenticationSource {
144 AuthenticationSource::User {
145 user: self.user.clone(),
146 token: self.token.clone(),
147 }
148 }
149 }
150
151 #[derive(Debug, Clone)]
152 pub struct InstanceAuthenticator {
153 pub instance: Instance,
154 pub private_key: String,
155 }
156
157 impl AuthenticationSourceProvider for InstanceAuthenticator {
158 fn authenticate(&self, payload: &Vec<u8>) -> AuthenticationSource {
159 let mut rng = rand::thread_rng();
160
161 let private_key = RsaPrivateKey::from_pkcs1_pem(&self.private_key).unwrap();
162 let signing_key = SigningKey::<Sha256>::new(private_key);
163 let signature = signing_key.sign_with_rng(&mut rng, &payload);
164
165 AuthenticationSource::Instance {
166 instance: self.instance.clone(),
167 // TODO: Actually parse signature from private key
168 signature: InstanceSignature(signature.to_bytes().into_vec()),
169 }
170 }
171 }
172
173 #[repr(transparent)]
174 #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
175 pub struct UserAuthenticationToken(String);
176
177 impl From<String> for UserAuthenticationToken {
178 fn from(value: String) -> Self {
179 Self(value)
180 }
181 }
182
183 impl ToString for UserAuthenticationToken {
184 fn to_string(&self) -> String {
185 self.0.clone()
186 }
187 }
188
189 impl AsRef<str> for UserAuthenticationToken {
190 fn as_ref(&self) -> &str {
191 &self.0
192 }
193 }
194
195 #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
196 pub struct InstanceSignature(Vec<u8>);
197
198 impl AsRef<[u8]> for InstanceSignature {
199 fn as_ref(&self) -> &[u8] {
200 &self.0
201 }
202 }
203
204 #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
205 pub enum AuthenticationSource {
206 User {
207 user: User,
208 token: UserAuthenticationToken,
209 },
210 Instance {
211 instance: Instance,
212 signature: InstanceSignature,
213 },
214 }
215