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

ambee/giterated

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

Add docs

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨51aad53

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