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

ambee/giterated

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

woo

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨2d48bc0

⁨src/messages/mod.rs⁩ - ⁨7832⁩ bytes
Raw
1 use anyhow::Error;
2 use jsonwebtoken::{decode, Algorithm, DecodingKey, TokenData, Validation};
3 use rsa::{
4 pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey},
5 pss::{Signature, SigningKey, VerifyingKey},
6 sha2::Sha256,
7 signature::{RandomizedSigner, SignatureEncoding, Verifier},
8 RsaPrivateKey, RsaPublicKey,
9 };
10 use serde::{Deserialize, Serialize};
11 use std::fmt::Debug;
12
13 use crate::{
14 authentication::UserTokenMetadata,
15 handshake::HandshakeMessage,
16 model::{instance::Instance, user::User},
17 };
18
19 use self::{
20 authentication::AuthenticationMessage, discovery::DiscoveryMessage,
21 repository::RepositoryMessage,
22 };
23
24 pub mod authentication;
25 pub mod discovery;
26 pub mod issues;
27 pub mod repository;
28 pub mod user;
29
30 #[derive(Clone, Serialize, Deserialize)]
31 pub enum MessageKind {
32 Handshake(HandshakeMessage),
33 Repository(RepositoryMessage),
34 Authentication(AuthenticationMessage),
35 Discovery(DiscoveryMessage),
36 }
37
38 /// An authenticated message, where the instance is authenticating
39 /// a request it is making for itself.
40 #[derive(Serialize, Deserialize)]
41 pub struct InstanceAuthenticated<T: Serialize> {
42 message: T,
43 instance: Instance,
44 signature: Vec<u8>,
45 }
46
47 impl<T> PartialEq for InstanceAuthenticated<T>
48 where
49 T: PartialEq + Serialize,
50 {
51 fn eq(&self, other: &Self) -> bool {
52 self.message == other.message
53 && self.instance == other.instance
54 && self.signature == other.signature
55 }
56 }
57
58 impl<T> Eq for InstanceAuthenticated<T> where T: Eq + Serialize {}
59
60 impl<T> std::hash::Hash for InstanceAuthenticated<T>
61 where
62 T: std::hash::Hash + Serialize,
63 {
64 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
65 self.message.hash(state);
66 self.instance.hash(state);
67 self.signature.hash(state);
68 }
69 }
70
71 impl<T> Clone for InstanceAuthenticated<T>
72 where
73 T: Clone + Serialize,
74 {
75 fn clone(&self) -> Self {
76 Self {
77 message: self.message.clone(),
78 instance: self.instance.clone(),
79 signature: self.signature.clone(),
80 }
81 }
82 }
83
84 impl<T> Debug for InstanceAuthenticated<T>
85 where
86 T: Debug + Serialize,
87 {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 f.debug_struct("Authenticated")
90 .field("message", &self.message)
91 .field("instance", &self.instance)
92 .field("signature", &self.signature)
93 .finish()
94 }
95 }
96
97 impl<T: Serialize> InstanceAuthenticated<T> {
98 pub fn new(message: T, instance: Instance, private_key: String) -> Result<Self, Error> {
99 let mut rng = rand::thread_rng();
100
101 let private_key = RsaPrivateKey::from_pkcs1_pem(&private_key)?;
102 let signing_key = SigningKey::<Sha256>::new(private_key);
103
104 let message_json = serde_json::to_vec(&message)?;
105
106 let signature = signing_key.sign_with_rng(&mut rng, &message_json);
107
108 Ok(Self {
109 message,
110 instance,
111 signature: signature.to_vec(),
112 })
113 }
114
115 pub async fn inner(&self) -> &T {
116 &self.message
117 }
118
119 pub async fn validate(&self, instance: &Instance) -> Result<(), Error> {
120 let public_key = public_key(instance).await?;
121 let public_key = RsaPublicKey::from_pkcs1_pem(&public_key).unwrap();
122
123 let verifying_key: VerifyingKey<Sha256> = VerifyingKey::new(public_key);
124
125 let message_json = serde_json::to_vec(&self.message).unwrap();
126
127 verifying_key
128 .verify(
129 &message_json,
130 &Signature::try_from(self.signature.as_ref()).unwrap(),
131 )
132 .unwrap();
133
134 Ok(())
135 }
136 }
137
138 /// An authenticated message.
139 ///
140 /// Includes the message, with a digest generated with
141 /// our private key.
142 #[derive(Serialize, Deserialize)]
143 pub struct ValidatedUserAuthenticated<T: Serialize> {
144 #[serde(flatten)]
145 message: T,
146 pub(crate) user: User,
147 }
148
149 impl<T> Clone for ValidatedUserAuthenticated<T>
150 where
151 T: Clone + Serialize,
152 {
153 fn clone(&self) -> Self {
154 Self {
155 message: self.message.clone(),
156 user: self.user.clone(),
157 }
158 }
159 }
160
161 impl<T> Debug for ValidatedUserAuthenticated<T>
162 where
163 T: Debug + Serialize,
164 {
165 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166 f.debug_struct("Authenticated")
167 .field("message", &self.message)
168 .field("user", &self.user)
169 .finish()
170 }
171 }
172
173 impl<T: Serialize> ValidatedUserAuthenticated<T> {
174 pub async fn inner(&self) -> &T {
175 &self.message
176 }
177
178 pub async fn user(&self) -> &User {
179 &self.user
180 }
181 }
182
183 /// An unvalidated authenticated message.
184 ///
185 /// Includes the message, with a digest generated with
186 /// our private key.
187 #[derive(Serialize, Deserialize)]
188 pub struct UnvalidatedUserAuthenticated<T: Serialize> {
189 #[serde(flatten)]
190 message: T,
191 token: String,
192 digest: Vec<u8>,
193 }
194
195 impl<T> Clone for UnvalidatedUserAuthenticated<T>
196 where
197 T: Clone + Serialize,
198 {
199 fn clone(&self) -> Self {
200 Self {
201 message: self.message.clone(),
202 token: self.token.clone(),
203 digest: self.digest.clone(),
204 }
205 }
206 }
207
208 impl<T> Debug for UnvalidatedUserAuthenticated<T>
209 where
210 T: Debug + Serialize,
211 {
212 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213 f.debug_struct("Authenticated")
214 .field("message", &self.message)
215 .field("token", &self.token)
216 .field("digest", &self.digest)
217 .finish()
218 }
219 }
220
221 impl<T: Serialize> UnvalidatedUserAuthenticated<T> {
222 pub fn new(message: T, token: String, private_key: String) -> Result<Self, Error> {
223 let mut rng = rand::thread_rng();
224
225 let private_key = RsaPrivateKey::from_pkcs1_pem(&private_key)?;
226 let signing_key = SigningKey::<Sha256>::new(private_key);
227
228 let message_json = serde_json::to_vec(&message)?;
229
230 let signature = signing_key.sign_with_rng(&mut rng, &message_json);
231
232 Ok(Self {
233 message,
234 token,
235 digest: signature.to_vec(),
236 })
237 }
238
239 pub async fn inner(&self) -> &T {
240 &self.message
241 }
242
243 pub async fn validate(self) -> Result<ValidatedUserAuthenticated<T>, Error> {
244 let instance = {
245 let mut validation = Validation::new(Algorithm::RS256);
246 validation.insecure_disable_signature_validation();
247
248 let value: TokenData<UserTokenMetadata> =
249 decode(&self.token, &DecodingKey::from_secret(b"test"), &validation).unwrap();
250
251 value.claims.generated_for.clone()
252 };
253
254 let public_key_raw = public_key(&instance).await?;
255 let public_key = RsaPublicKey::from_pkcs1_pem(&public_key_raw).unwrap();
256
257 let verifying_key: VerifyingKey<Sha256> = VerifyingKey::new(public_key);
258
259 let message_json = serde_json::to_vec(&self.message).unwrap();
260
261 verifying_key
262 .verify(
263 &message_json,
264 &Signature::try_from(self.digest.as_ref()).unwrap(),
265 )
266 .unwrap();
267
268 let verification_key = DecodingKey::from_rsa_pem(public_key_raw.as_bytes()).unwrap();
269
270 let data: TokenData<UserTokenMetadata> = decode(
271 &self.token,
272 &verification_key,
273 &Validation::new(Algorithm::RS256),
274 )
275 .unwrap();
276
277 assert_eq!(data.claims.generated_for, instance);
278
279 Ok(ValidatedUserAuthenticated {
280 message: self.message,
281 user: data.claims.user,
282 })
283 }
284 }
285
286 async fn public_key(instance: &Instance) -> Result<String, Error> {
287 let key = reqwest::get(format!("https://{}/.giterated/pubkey.pem", instance.url))
288 .await?
289 .text()
290 .await?;
291
292 Ok(key)
293 }
294