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

ambee/giterated

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

add discovery stub

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨cb91a68

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