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

ambee/giterated

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

Major post-refactor cleanup

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨f90d7fb

Showing ⁨⁨21⁩ changed files⁩ with ⁨⁨165⁩ insertions⁩ and ⁨⁨1039⁩ deletions⁩

src/authentication.rs

View file
@@ -6,13 +6,7 @@ use tokio::{fs::File, io::AsyncReadExt};
6 6 use toml::Table;
7 7
8 8 use crate::{
9 messages::{
10 authentication::{
11 AuthenticationTokenRequest, AuthenticationTokenResponse, TokenExtensionRequest,
12 TokenExtensionResponse,
13 },
14 InstanceAuthenticated,
15 },
9 messages::authentication::{AuthenticationTokenResponse, TokenExtensionResponse},
16 10 model::{authenticated::UserAuthenticationToken, instance::Instance, user::User},
17 11 };
18 12
@@ -76,7 +70,7 @@ impl AuthenticationTokenGranter {
76 70 &mut self,
77 71 issued_for: impl ToOwned<Owned = Instance>,
78 72 username: String,
79 password: String,
73 _password: String,
80 74 ) -> Result<AuthenticationTokenResponse, Error> {
81 75 let private_key = {
82 76 let mut file = File::open(

src/backend/discovery.rs

View file
@@ -1,21 +1,9 @@
1 use std::{
2 collections::hash_map::DefaultHasher,
3 hash::{Hash, Hasher},
4 };
1 use std::hash::Hash;
5 2
6 use anyhow::Error;
7 use base64::{engine::general_purpose::STANDARD, Engine as _};
8 3 use chrono::{DateTime, Utc};
9 4 use serde::{Deserialize, Serialize};
10 5 use sqlx::PgPool;
11 6
12 use crate::{
13 messages::discovery::{DiscoveryMessage, DiscoveryMessageKind},
14 model::{discovery::DiscoveryItem, repository::Repository},
15 };
16
17 use super::DiscoveryBackend;
18
19 7 pub struct GiteratedDiscoveryProtocol {
20 8 pub pool: PgPool,
21 9 }
@@ -27,78 +15,6 @@ pub enum DiscoveryType {
27 15 Repository,
28 16 }
29 17
30 #[async_trait::async_trait]
31 impl DiscoveryBackend for GiteratedDiscoveryProtocol {
32 async fn try_handle(&mut self, request: &DiscoveryMessage) -> Result<bool, Error> {
33 if request
34 .message
35 .validate(&request.message.instance)
36 .await
37 .is_err()
38 {
39 return Ok(false);
40 }
41
42 let inner = request.message.inner().await.clone();
43
44 match inner {
45 DiscoveryMessageKind::Discoveries(mut discoveries) => {
46 let discoveries = discoveries.discoveries.drain(..).map(|discovery| {
47 let hash = {
48 let mut hasher = DefaultHasher::new();
49 discovery.hash(&mut hasher);
50 STANDARD.encode(hasher.finish().to_be_bytes())
51 };
52
53 let (discovery_type, discovery) = match discovery {
54 DiscoveryItem::Instance {
55 instance,
56 signature,
57 } => (DiscoveryType::Instance, instance.to_string()),
58 DiscoveryItem::Repository {
59 repository,
60 signature,
61 } => (DiscoveryType::Repository, repository.to_string()),
62 };
63
64 DiscoveriesRow {
65 discovery_hash: hash,
66 discovery_time: Utc::now(),
67 discovery_type,
68 discovery,
69 }
70 });
71
72 for row in discoveries {
73 let result = sqlx::query!(
74 r#"INSERT INTO discoveries VALUES ($1, $2, $3, $4)"#,
75 row.discovery_hash,
76 row.discovery_time.to_string(),
77 row.discovery_type as _,
78 row.discovery
79 )
80 .execute(&self.pool)
81 .await;
82
83 match result {
84 Ok(_) => {}
85 Err(err) => {
86 error!("Error inserting discovery. {:?}", err);
87 }
88 }
89 }
90 Ok(true)
91 }
92 DiscoveryMessageKind::Offer(offer) => Ok(true),
93 DiscoveryMessageKind::Request(request) => Ok(true),
94 }
95 }
96
97 async fn search(&mut self, _search: &str) -> Result<Vec<Repository>, Error> {
98 todo!()
99 }
100 }
101
102 18 #[derive(Debug, sqlx::FromRow, sqlx::Type)]
103 19 pub struct DiscoveriesRow {
104 20 discovery_hash: String,

src/backend/git.rs

View file
@@ -6,8 +6,6 @@ use sqlx::{Either, PgPool};
6 6 use std::path::{Path, PathBuf};
7 7 use thiserror::Error;
8 8
9 use crate::messages::ValidatedUserAuthenticated;
10
11 9 use crate::model::instance::Instance;
12 10 use crate::model::repository::{
13 11 Commit, Repository, RepositoryObjectType, RepositorySummary, RepositoryTreeEntry,
@@ -212,7 +210,7 @@ impl GitBackend {
212 210 impl RepositoryBackend for GitBackend {
213 211 async fn create_repository(
214 212 &mut self,
215 user: &User,
213 _user: &User,
216 214 request: &CreateRepositoryRequest,
217 215 ) -> Result<CreateRepositoryResponse, Error> {
218 216 // Check if repository already exists in the database
@@ -439,7 +437,7 @@ impl RepositoryBackend for GitBackend {
439 437
440 438 async fn repository_file_inspect(
441 439 &mut self,
442 requester: Option<&User>,
440 _requester: Option<&User>,
443 441 _request: &RepositoryFileInspectRequest,
444 442 ) -> Result<RepositoryFileInspectionResponse, Error> {
445 443 todo!()
@@ -480,21 +478,24 @@ impl RepositoryBackend for GitBackend {
480 478 impl IssuesBackend for GitBackend {
481 479 fn issues_count(
482 480 &mut self,
483 _request: &ValidatedUserAuthenticated<RepositoryIssuesCountRequest>,
481 _requester: Option<&User>,
482 _request: &RepositoryIssuesCountRequest,
484 483 ) -> Result<RepositoryIssuesCountResponse, Error> {
485 484 todo!()
486 485 }
487 486
488 487 fn issue_labels(
489 488 &mut self,
490 _request: &ValidatedUserAuthenticated<RepositoryIssueLabelsRequest>,
489 _requester: Option<&User>,
490 _request: &RepositoryIssueLabelsRequest,
491 491 ) -> Result<RepositoryIssueLabelsResponse, Error> {
492 492 todo!()
493 493 }
494 494
495 495 fn issues(
496 496 &mut self,
497 _request: &ValidatedUserAuthenticated<RepositoryIssuesRequest>,
497 _requester: Option<&User>,
498 _request: &RepositoryIssuesRequest,
498 499 ) -> Result<RepositoryIssuesResponse, Error> {
499 500 todo!()
500 501 }

src/backend/mod.rs

View file
@@ -12,7 +12,6 @@ use crate::{
12 12 AuthenticationTokenRequest, AuthenticationTokenResponse, RegisterAccountRequest,
13 13 RegisterAccountResponse,
14 14 },
15 discovery::DiscoveryMessage,
16 15 repository::{
17 16 CreateRepositoryRequest, CreateRepositoryResponse, RepositoryFileInspectRequest,
18 17 RepositoryFileInspectionResponse, RepositoryInfoRequest, RepositoryIssueLabelsRequest,
@@ -23,10 +22,9 @@ use crate::{
23 22 UserBioRequest, UserBioResponse, UserDisplayImageRequest, UserDisplayImageResponse,
24 23 UserDisplayNameRequest, UserDisplayNameResponse,
25 24 },
26 ValidatedUserAuthenticated,
27 25 },
28 26 model::{
29 repository::{Repository, RepositorySummary, RepositoryView},
27 repository::{RepositorySummary, RepositoryView},
30 28 user::User,
31 29 },
32 30 };
@@ -55,15 +53,18 @@ pub trait RepositoryBackend: IssuesBackend {
55 53 pub trait IssuesBackend {
56 54 fn issues_count(
57 55 &mut self,
58 request: &ValidatedUserAuthenticated<RepositoryIssuesCountRequest>,
56 requester: Option<&User>,
57 request: &RepositoryIssuesCountRequest,
59 58 ) -> Result<RepositoryIssuesCountResponse, Error>;
60 59 fn issue_labels(
61 60 &mut self,
62 request: &ValidatedUserAuthenticated<RepositoryIssueLabelsRequest>,
61 requester: Option<&User>,
62 request: &RepositoryIssueLabelsRequest,
63 63 ) -> Result<RepositoryIssueLabelsResponse, Error>;
64 64 fn issues(
65 65 &mut self,
66 request: &ValidatedUserAuthenticated<RepositoryIssuesRequest>,
66 requester: Option<&User>,
67 request: &RepositoryIssuesRequest,
67 68 ) -> Result<RepositoryIssuesResponse, Error>;
68 69 }
69 70
@@ -95,9 +96,3 @@ pub trait UserBackend: AuthBackend {
95 96 async fn bio(&mut self, request: UserBioRequest) -> Result<UserBioResponse, Error>;
96 97 async fn exists(&mut self, user: &User) -> Result<bool, Error>;
97 98 }
98
99 #[async_trait::async_trait]
100 pub trait DiscoveryBackend {
101 async fn try_handle(&mut self, request: &DiscoveryMessage) -> Result<bool, Error>;
102 async fn search(&mut self, search: &str) -> Result<Vec<Repository>, Error>;
103 }

src/backend/user.rs

View file
@@ -203,6 +203,7 @@ impl AuthBackend for UserAuth {
203 203 }
204 204 }
205 205
206 #[allow(unused)]
206 207 #[derive(Debug, sqlx::FromRow)]
207 208 struct UserRow {
208 209 pub username: String,

src/connection.rs

View file
@@ -4,47 +4,16 @@ pub mod repository;
4 4 pub mod user;
5 5 pub mod wrapper;
6 6
7 use std::{any::type_name, collections::HashMap, net::SocketAddr, str::FromStr, sync::Arc};
7 use std::{any::type_name, collections::HashMap};
8 8
9 9 use anyhow::Error;
10 use futures_util::{stream::StreamExt, SinkExt};
11 use semver::Version;
12 10 use serde::{de::DeserializeOwned, Serialize};
13 use tokio::{
14 net::TcpStream,
15 sync::{
16 broadcast::{Receiver, Sender},
17 Mutex,
18 },
19 task::JoinHandle,
20 };
21 use tokio_tungstenite::{tungstenite::Message, WebSocketStream};
11 use tokio::{net::TcpStream, task::JoinHandle};
12 use tokio_tungstenite::WebSocketStream;
22 13
23 14 use crate::{
24 authentication::AuthenticationTokenGranter,
25 backend::{DiscoveryBackend, RepositoryBackend, UserBackend},
26 handshake::{HandshakeFinalize, HandshakeMessage, HandshakeResponse},
27 listener::Listeners,
28 messages::{
29 authentication::{
30 AuthenticationMessage, AuthenticationRequest, AuthenticationResponse,
31 TokenExtensionResponse,
32 },
33 repository::{
34 RepositoryMessage, RepositoryMessageKind, RepositoryRequest, RepositoryResponse,
35 },
36 user::{
37 UserMessage, UserMessageKind, UserMessageRequest, UserMessageResponse,
38 UserRepositoriesResponse,
39 },
40 ErrorMessage, MessageKind,
41 },
42 model::{
43 instance::{Instance, InstanceMeta},
44 repository::Repository,
45 user::User,
46 },
47 validate_version, version,
15 messages::ErrorMessage,
16 model::instance::{Instance, InstanceMeta},
48 17 };
49 18
50 19 #[derive(Debug, thiserror::Error)]
@@ -63,7 +32,6 @@ pub struct RawConnection {
63 32
64 33 pub struct InstanceConnection {
65 34 pub instance: InstanceMeta,
66 pub sender: Sender<MessageKind>,
67 35 pub task: JoinHandle<()>,
68 36 }
69 37
@@ -78,212 +46,6 @@ pub struct Connections {
78 46 pub instance_connections: HashMap<Instance, InstanceConnection>,
79 47 }
80 48
81 pub async fn connection_worker(
82 mut socket: &mut WebSocketStream<TcpStream>,
83 handshaked: &mut bool,
84 listeners: &Arc<Mutex<Listeners>>,
85 connections: &Arc<Mutex<Connections>>,
86 backend: &Arc<Mutex<dyn RepositoryBackend + Send>>,
87 user_backend: &Arc<Mutex<dyn UserBackend + Send>>,
88 auth_granter: &Arc<Mutex<AuthenticationTokenGranter>>,
89 discovery_backend: &Arc<Mutex<dyn DiscoveryBackend + Send>>,
90 addr: &SocketAddr,
91 ) -> Result<(), ConnectionError> {
92 let this_instance = Instance {
93 url: String::from("giterated.dev"),
94 };
95
96 let message = socket
97 .next()
98 .await
99 .ok_or_else(|| ConnectionError::Shutdown)?
100 .map_err(|e| Error::from(e))?;
101
102 let payload = match message {
103 Message::Text(text) => text.into_bytes(),
104 Message::Binary(bytes) => bytes,
105 Message::Ping(_) => return Ok(()),
106 Message::Pong(_) => return Ok(()),
107 Message::Close(_) => {
108 info!("Closing connection with {}.", addr);
109
110 return Err(ConnectionError::Shutdown);
111 }
112 _ => unreachable!(),
113 };
114
115 let message = serde_json::from_slice::<MessageKind>(&payload).map_err(|e| Error::from(e))?;
116
117 if let MessageKind::Handshake(handshake) = message {
118 match handshake {
119 HandshakeMessage::Initiate(request) => {
120 unimplemented!()
121 }
122 HandshakeMessage::Response(response) => {
123 unimplemented!()
124 }
125 HandshakeMessage::Finalize(response) => {
126 unimplemented!()
127 }
128 }
129 }
130
131 if !*handshaked {
132 return Ok(());
133 }
134
135 if let MessageKind::Repository(repository) = &message {
136 if repository.target.instance != this_instance {
137 info!("Forwarding command to {}", repository.target.instance.url);
138 // We need to send this command to a different instance
139
140 let mut listener = send_and_get_listener(message, &listeners, &connections).await;
141
142 // Wait for response
143 while let Ok(message) = listener.recv().await {
144 if let MessageKind::Repository(RepositoryMessage {
145 command: RepositoryMessageKind::Response(_),
146 ..
147 }) = message
148 {
149 let _result = send(&mut socket, message).await;
150 }
151 }
152
153 return Ok(());
154 } else {
155 // This message is targeting this instance
156 match &repository.command {
157 RepositoryMessageKind::Request(request) => match request.clone() {
158 RepositoryRequest::CreateRepository(request) => {
159 unimplemented!();
160 }
161 RepositoryRequest::RepositoryFileInspect(request) => {
162 unimplemented!()
163 }
164 RepositoryRequest::RepositoryInfo(request) => {
165 unimplemented!()
166 }
167 RepositoryRequest::IssuesCount(request) => {
168 unimplemented!()
169 }
170 RepositoryRequest::IssueLabels(request) => {
171 unimplemented!()
172 }
173 RepositoryRequest::Issues(request) => {
174 unimplemented!();
175 }
176 },
177 RepositoryMessageKind::Response(_response) => {
178 unreachable!()
179 }
180 }
181 }
182 }
183
184 if let MessageKind::Authentication(authentication) = &message {
185 match authentication {
186 AuthenticationMessage::Request(request) => match request {
187 AuthenticationRequest::AuthenticationToken(token) => {
188 unimplemented!()
189 }
190 AuthenticationRequest::TokenExtension(request) => {
191 unimplemented!()
192 }
193 AuthenticationRequest::RegisterAccount(request) => {
194 unimplemented!()
195 }
196 },
197 AuthenticationMessage::Response(_) => unreachable!(),
198 }
199 }
200
201 if let MessageKind::Discovery(message) = &message {
202 let mut backend = discovery_backend.lock().await;
203 backend.try_handle(message).await?;
204
205 return Ok(());
206 }
207
208 if let MessageKind::User(message) = &message {
209 match &message.message {
210 UserMessageKind::Request(request) => match request {
211 UserMessageRequest::DisplayName(request) => {
212 unimplemented!()
213 }
214 UserMessageRequest::DisplayImage(request) => {
215 unimplemented!()
216 }
217 UserMessageRequest::Bio(request) => {
218 unimplemented!()
219 }
220 UserMessageRequest::Repositories(request) => {
221 unimplemented!()
222 }
223 },
224 UserMessageKind::Response(_) => unreachable!(),
225 }
226 }
227
228 Ok(())
229 }
230
231 async fn send_and_get_listener(
232 message: MessageKind,
233 listeners: &Arc<Mutex<Listeners>>,
234 connections: &Arc<Mutex<Connections>>,
235 ) -> Receiver<MessageKind> {
236 let (instance, user, repository): (Option<Instance>, Option<User>, Option<Repository>) =
237 match &message {
238 MessageKind::Handshake(_) => {
239 todo!()
240 }
241 MessageKind::Repository(repository) => (None, None, Some(repository.target.clone())),
242 MessageKind::Authentication(_) => todo!(),
243 MessageKind::Discovery(_) => todo!(),
244 MessageKind::User(user) => todo!(),
245 MessageKind::Error(_) => todo!(),
246 };
247
248 let target = match (&instance, &user, &repository) {
249 (Some(instance), _, _) => instance.clone(),
250 (_, Some(user), _) => user.instance.clone(),
251 (_, _, Some(repository)) => repository.instance.clone(),
252 _ => unreachable!(),
253 };
254
255 let mut listeners = listeners.lock().await;
256 let listener = listeners.add(instance, user, repository);
257 drop(listeners);
258
259 let connections = connections.lock().await;
260
261 if let Some(connection) = connections.instance_connections.get(&target) {
262 if let Err(_) = connection.sender.send(message) {
263 error!("Error sending message.");
264 }
265 } else {
266 error!("Unable to message {}, this is a bug.", target.url);
267
268 panic!();
269 }
270
271 drop(connections);
272
273 listener
274 }
275
276 async fn send<T: Serialize>(
277 socket: &mut WebSocketStream<TcpStream>,
278 message: T,
279 ) -> Result<(), Error> {
280 socket
281 .send(Message::Binary(serde_json::to_vec(&message)?))
282 .await?;
283
284 Ok(())
285 }
286
287 49 #[derive(Debug, thiserror::Error)]
288 50 #[error("handler did not handle")]
289 51 pub struct HandlerUnhandled;

src/connection/authentication.rs

View file
@@ -1,12 +1,11 @@
1 1 use anyhow::Error;
2 2 use thiserror::Error;
3 3
4 use crate::messages::authentication::{AuthenticationMessage, AuthenticationResponse};
5 use crate::model::authenticated::MessageHandler;
6 use crate::{
7 messages::{authentication::AuthenticationRequest, MessageKind},
8 model::authenticated::{AuthenticatedInstance, NetworkMessage, State},
4 use crate::messages::authentication::{
5 AuthenticationTokenRequest, RegisterAccountRequest, TokenExtensionRequest,
9 6 };
7 use crate::model::authenticated::{AuthenticatedInstance, NetworkMessage, State};
8 use crate::model::authenticated::{Message, MessageHandler};
10 9
11 10 use super::wrapper::ConnectionState;
12 11 use super::HandlerUnhandled;
@@ -15,42 +14,34 @@ pub async fn authentication_handle(
15 14 message: &NetworkMessage,
16 15 state: &ConnectionState,
17 16 ) -> Result<(), Error> {
18 let message_kind: MessageKind = serde_json::from_slice(&message.0).unwrap();
19
20 match message_kind {
21 MessageKind::Authentication(AuthenticationMessage::Request(request)) => match request {
22 AuthenticationRequest::RegisterAccount(_) => {
23 register_account_request
24 .handle_message(message, state)
25 .await
26 }
27 AuthenticationRequest::AuthenticationToken(_) => {
28 authentication_token_request
29 .handle_message(message, state)
30 .await
31 }
32 AuthenticationRequest::TokenExtension(_) => {
33 token_extension_request.handle_message(message, state).await
34 }
35 },
36 _ => Err(Error::from(HandlerUnhandled)),
17 if register_account_request
18 .handle_message(&message, state)
19 .await
20 .is_ok()
21 {
22 Ok(())
23 } else if authentication_token_request
24 .handle_message(&message, state)
25 .await
26 .is_ok()
27 {
28 Ok(())
29 } else if token_extension_request
30 .handle_message(&message, state)
31 .await
32 .is_ok()
33 {
34 Ok(())
35 } else {
36 Err(Error::from(HandlerUnhandled))
37 37 }
38 38 }
39 39
40 40 async fn register_account_request(
41 41 State(connection_state): State<ConnectionState>,
42 request: MessageKind,
42 Message(request): Message<RegisterAccountRequest>,
43 43 instance: AuthenticatedInstance,
44 44 ) -> Result<(), AuthenticationConnectionError> {
45 let request = if let MessageKind::Authentication(AuthenticationMessage::Request(
46 AuthenticationRequest::RegisterAccount(request),
47 )) = request
48 {
49 request
50 } else {
51 return Err(AuthenticationConnectionError::InvalidRequest);
52 };
53
54 45 if *instance.inner() != connection_state.instance {
55 46 return Err(AuthenticationConnectionError::SameInstance);
56 47 }
@@ -64,9 +55,7 @@ async fn register_account_request(
64 55 drop(user_backend);
65 56
66 57 connection_state
67 .send(MessageKind::Authentication(
68 AuthenticationMessage::Response(AuthenticationResponse::RegisterAccount(response)),
69 ))
58 .send(response)
70 59 .await
71 60 .map_err(|e| AuthenticationConnectionError::Sending(e))?;
72 61
@@ -75,18 +64,9 @@ async fn register_account_request(
75 64
76 65 async fn authentication_token_request(
77 66 State(connection_state): State<ConnectionState>,
78 request: MessageKind,
67 Message(request): Message<AuthenticationTokenRequest>,
79 68 instance: AuthenticatedInstance,
80 69 ) -> Result<(), AuthenticationConnectionError> {
81 let request = if let MessageKind::Authentication(AuthenticationMessage::Request(
82 AuthenticationRequest::AuthenticationToken(request),
83 )) = request
84 {
85 request
86 } else {
87 return Err(AuthenticationConnectionError::InvalidRequest);
88 };
89
90 70 let issued_for = instance.inner().clone();
91 71
92 72 let mut token_granter = connection_state.auth_granter.lock().await;
@@ -97,9 +77,7 @@ async fn authentication_token_request(
97 77 .map_err(|e| AuthenticationConnectionError::TokenIssuance(e))?;
98 78
99 79 connection_state
100 .send(MessageKind::Authentication(
101 AuthenticationMessage::Response(AuthenticationResponse::AuthenticationToken(response)),
102 ))
80 .send(response)
103 81 .await
104 82 .map_err(|e| AuthenticationConnectionError::Sending(e))?;
105 83
@@ -108,18 +86,9 @@ async fn authentication_token_request(
108 86
109 87 async fn token_extension_request(
110 88 State(connection_state): State<ConnectionState>,
111 request: MessageKind,
89 Message(request): Message<TokenExtensionRequest>,
112 90 instance: AuthenticatedInstance,
113 91 ) -> Result<(), AuthenticationConnectionError> {
114 let request = if let MessageKind::Authentication(AuthenticationMessage::Request(
115 AuthenticationRequest::TokenExtension(request),
116 )) = request
117 {
118 request
119 } else {
120 return Err(AuthenticationConnectionError::InvalidRequest);
121 };
122
123 92 let issued_for = instance.inner().clone();
124 93
125 94 let mut token_granter = connection_state.auth_granter.lock().await;
@@ -130,21 +99,13 @@ async fn token_extension_request(
130 99 .map_err(|e| AuthenticationConnectionError::TokenIssuance(e))?;
131 100
132 101 connection_state
133 .send(MessageKind::Authentication(
134 AuthenticationMessage::Response(AuthenticationResponse::TokenExtension(response)),
135 ))
102 .send(response)
136 103 .await
137 104 .map_err(|e| AuthenticationConnectionError::Sending(e))?;
138 105
139 106 Ok(())
140 107 }
141 108
142 async fn verify(state: ConnectionState) {
143 register_account_request
144 .handle_message(&NetworkMessage(vec![]), &state)
145 .await;
146 }
147
148 109 #[derive(Debug, Error)]
149 110 pub enum AuthenticationConnectionError {
150 111 #[error("the request was invalid")]

src/connection/handshake.rs

View file
@@ -2,7 +2,6 @@ use std::{str::FromStr, sync::atomic::Ordering};
2 2
3 3 use anyhow::Error;
4 4 use semver::Version;
5 use thiserror::Error;
6 5
7 6 use crate::model::authenticated::MessageHandler;
8 7 use crate::{

src/connection/repository.rs

View file
@@ -4,7 +4,6 @@ use crate::{
4 4 messages::repository::{
5 5 CreateRepositoryRequest, RepositoryFileInspectRequest, RepositoryInfoRequest,
6 6 RepositoryIssueLabelsRequest, RepositoryIssuesCountRequest, RepositoryIssuesRequest,
7 RepositoryRequest,
8 7 },
9 8 model::authenticated::{AuthenticatedUser, Message, MessageHandler, NetworkMessage, State},
10 9 };
@@ -100,25 +99,25 @@ async fn repository_info(
100 99 }
101 100
102 101 async fn issues_count(
103 Message(request): Message<RepositoryIssuesCountRequest>,
104 State(connection_state): State<ConnectionState>,
105 user: Option<AuthenticatedUser>,
102 Message(_request): Message<RepositoryIssuesCountRequest>,
103 State(_connection_state): State<ConnectionState>,
104 _user: Option<AuthenticatedUser>,
106 105 ) -> Result<(), RepositoryError> {
107 106 unimplemented!();
108 107 }
109 108
110 109 async fn issue_labels(
111 Message(request): Message<RepositoryIssueLabelsRequest>,
112 State(connection_state): State<ConnectionState>,
113 user: Option<AuthenticatedUser>,
110 Message(_request): Message<RepositoryIssueLabelsRequest>,
111 State(_connection_state): State<ConnectionState>,
112 _user: Option<AuthenticatedUser>,
114 113 ) -> Result<(), RepositoryError> {
115 114 unimplemented!();
116 115 }
117 116
118 117 async fn issues(
119 Message(request): Message<RepositoryIssuesRequest>,
120 State(connection_state): State<ConnectionState>,
121 user: Option<AuthenticatedUser>,
118 Message(_request): Message<RepositoryIssuesRequest>,
119 State(_connection_state): State<ConnectionState>,
120 _user: Option<AuthenticatedUser>,
122 121 ) -> Result<(), RepositoryError> {
123 122 unimplemented!();
124 123 }

src/connection/user.rs

View file
@@ -17,6 +17,8 @@ pub async fn user_handle(message: &NetworkMessage, state: &ConnectionState) -> R
17 17 Ok(())
18 18 } else if bio.handle_message(&message, state).await.is_ok() {
19 19 Ok(())
20 } else if repositories.handle_message(&message, state).await.is_ok() {
21 Ok(())
20 22 } else {
21 23 Err(Error::from(HandlerUnhandled))
22 24 }

src/connection/wrapper.rs

View file
@@ -14,36 +14,30 @@ use tokio_tungstenite::{tungstenite::Message, WebSocketStream};
14 14
15 15 use crate::{
16 16 authentication::AuthenticationTokenGranter,
17 backend::{DiscoveryBackend, RepositoryBackend, UserBackend},
18 connection::ConnectionError,
19 listener::Listeners,
17 backend::{RepositoryBackend, UserBackend},
20 18 model::{authenticated::NetworkMessage, instance::Instance},
21 19 };
22 20
23 21 use super::{
24 authentication::authentication_handle, connection_worker, handshake::handshake_handle,
22 authentication::authentication_handle, handshake::handshake_handle,
25 23 repository::repository_handle, user::user_handle, Connections,
26 24 };
27 25
28 26 pub async fn connection_wrapper(
29 mut socket: WebSocketStream<TcpStream>,
30 listeners: Arc<Mutex<Listeners>>,
27 socket: WebSocketStream<TcpStream>,
31 28 connections: Arc<Mutex<Connections>>,
32 29 repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>,
33 30 user_backend: Arc<Mutex<dyn UserBackend + Send>>,
34 31 auth_granter: Arc<Mutex<AuthenticationTokenGranter>>,
35 discovery_backend: Arc<Mutex<dyn DiscoveryBackend + Send>>,
36 32 addr: SocketAddr,
37 33 instance: impl ToOwned<Owned = Instance>,
38 34 ) {
39 let mut connection_state = ConnectionState {
35 let connection_state = ConnectionState {
40 36 socket: Arc::new(Mutex::new(socket)),
41 listeners,
42 37 connections,
43 38 repository_backend,
44 39 user_backend,
45 40 auth_granter,
46 discovery_backend,
47 41 addr,
48 42 instance: instance.to_owned(),
49 43 handshaked: Arc::new(AtomicBool::new(false)),
@@ -62,7 +56,7 @@ pub async fn connection_wrapper(
62 56 Message::Binary(payload) => payload,
63 57 Message::Ping(_) => {
64 58 let mut socket = connection_state.socket.lock().await;
65 socket.send(Message::Pong(vec![])).await;
59 let _ = socket.send(Message::Pong(vec![])).await;
66 60 drop(socket);
67 61 continue;
68 62 }
@@ -105,12 +99,10 @@ pub async fn connection_wrapper(
105 99 #[derive(Clone)]
106 100 pub struct ConnectionState {
107 101 socket: Arc<Mutex<WebSocketStream<TcpStream>>>,
108 pub listeners: Arc<Mutex<Listeners>>,
109 102 pub connections: Arc<Mutex<Connections>>,
110 103 pub repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>,
111 104 pub user_backend: Arc<Mutex<dyn UserBackend + Send>>,
112 105 pub auth_granter: Arc<Mutex<AuthenticationTokenGranter>>,
113 pub discovery_backend: Arc<Mutex<dyn DiscoveryBackend + Send>>,
114 106 pub addr: SocketAddr,
115 107 pub instance: Instance,
116 108 pub handshaked: Arc<AtomicBool>,

src/lib.rs

View file
@@ -6,7 +6,6 @@ pub mod authentication;
6 6 pub mod backend;
7 7 pub mod connection;
8 8 pub mod handshake;
9 pub mod listener;
10 9 pub mod messages;
11 10 pub mod model;
12 11

src/main.rs

View file
@@ -2,15 +2,10 @@ use anyhow::Error;
2 2 use connection::{Connections, RawConnection};
3 3 use giterated_daemon::{
4 4 authentication::AuthenticationTokenGranter,
5 backend::{
6 discovery::GiteratedDiscoveryProtocol, git::GitBackend, user::UserAuth, DiscoveryBackend,
7 RepositoryBackend, UserBackend,
8 },
5 backend::{git::GitBackend, user::UserAuth, RepositoryBackend, UserBackend},
9 6 connection::{self, wrapper::connection_wrapper},
10 listener,
11 7 model::instance::Instance,
12 8 };
13 use listener::Listeners;
14 9 use sqlx::{postgres::PgConnectOptions, ConnectOptions, PgPool};
15 10 use std::{net::SocketAddr, str::FromStr, sync::Arc};
16 11 use tokio::{
@@ -30,7 +25,6 @@ async fn main() -> Result<(), Error> {
30 25 tracing_subscriber::fmt::init();
31 26 let mut listener = TcpListener::bind("0.0.0.0:7270").await?;
32 27 let connections: Arc<Mutex<Connections>> = Arc::default();
33 let listeners: Arc<Mutex<Listeners>> = Arc::default();
34 28 let config: Table = {
35 29 let mut file = File::open("Giterated.toml").await?;
36 30 let mut text = String::new();
@@ -72,11 +66,6 @@ async fn main() -> Result<(), Error> {
72 66 token_granter.clone(),
73 67 )));
74 68
75 let discovery_backend: Arc<Mutex<dyn DiscoveryBackend + Send>> =
76 Arc::new(Mutex::new(GiteratedDiscoveryProtocol {
77 pool: db_pool.clone(),
78 }));
79
80 69 info!("Connected");
81 70
82 71 loop {
@@ -111,12 +100,10 @@ async fn main() -> Result<(), Error> {
111 100 let connection = RawConnection {
112 101 task: tokio::spawn(connection_wrapper(
113 102 connection,
114 listeners.clone(),
115 103 connections.clone(),
116 104 repository_backend.clone(),
117 105 user_backend.clone(),
118 106 token_granter.clone(),
119 discovery_backend.clone(),
120 107 address,
121 108 Instance::from_str("giterated.dev").unwrap(),
122 109 )),

src/messages/authentication.rs

View file
@@ -2,61 +2,11 @@ use serde::{Deserialize, Serialize};
2 2
3 3 use crate::model::authenticated::UserAuthenticationToken;
4 4
5 use super::InstanceAuthenticated;
6
7 /// An authentication message.
5 /// An account registration request.
8 6 ///
9 /// View request documentation, authentication, and authorization
10 /// details in the associated type, [`AuthenticationRequest`].
11 #[derive(Clone, Serialize, Deserialize)]
12 pub enum AuthenticationMessage {
13 Request(AuthenticationRequest),
14 Response(AuthenticationResponse),
15 }
16
17 #[derive(Clone, Serialize, Deserialize)]
18 pub enum AuthenticationRequest {
19 /// An account registration request.
20 ///
21 /// # Authentication
22 /// - Instance Authentication
23 /// - **ONLY ACCEPTED WHEN SAME-INSTANCE**
24 RegisterAccount(RegisterAccountRequest),
25
26 /// An authentication token request.
27 ///
28 /// AKA Login Request
29 ///
30 /// # Authentication
31 /// - Instance Authentication
32 /// - Identifies the Instance to issue the token for
33 /// # Authorization
34 /// - Credentials ([`crate::backend::AuthBackend`]-based)
35 /// - Identifies the User account to issue a token for
36 /// - Decrypts user private key to issue to
37 AuthenticationToken(AuthenticationTokenRequest),
38
39 /// An authentication token extension request.
40 ///
41 /// # Authentication
42 /// - Instance Authentication
43 /// - Identifies the Instance to issue the token for
44 /// - User Authentication
45 /// - Authenticates the validity of the token
46 /// # Authorization
47 /// - Token-based
48 /// - Validates authorization using token's authenticity
49 TokenExtension(TokenExtensionRequest),
50 }
51
52 #[derive(Clone, Serialize, Deserialize)]
53 pub enum AuthenticationResponse {
54 RegisterAccount(RegisterAccountResponse),
55 AuthenticationToken(AuthenticationTokenResponse),
56 TokenExtension(TokenExtensionResponse),
57 }
58
59 /// See [`AuthenticationRequest::RegisterAccount`]'s documentation.
7 /// # Authentication
8 /// - Instance Authentication
9 /// - **ONLY ACCEPTED WHEN SAME-INSTANCE**
60 10 #[derive(Clone, Serialize, Deserialize)]
61 11 pub struct RegisterAccountRequest {
62 12 pub username: String,
@@ -69,7 +19,17 @@ pub struct RegisterAccountResponse {
69 19 pub token: String,
70 20 }
71 21
72 /// See [`AuthenticationRequest::AuthenticationToken`]'s documentation.
22 /// An authentication token request.
23 ///
24 /// AKA Login Request
25 ///
26 /// # Authentication
27 /// - Instance Authentication
28 /// - Identifies the Instance to issue the token for
29 /// # Authorization
30 /// - Credentials ([`crate::backend::AuthBackend`]-based)
31 /// - Identifies the User account to issue a token for
32 /// - Decrypts user private key to issue to
73 33 #[derive(Clone, Serialize, Deserialize)]
74 34 pub struct AuthenticationTokenRequest {
75 35 pub username: String,
@@ -81,7 +41,16 @@ pub struct AuthenticationTokenResponse {
81 41 pub token: String,
82 42 }
83 43
84 /// See [`AuthenticationRequest::TokenExtension`]'s documentation.
44 /// An authentication token extension request.
45 ///
46 /// # Authentication
47 /// - Instance Authentication
48 /// - Identifies the Instance to issue the token for
49 /// - User Authentication
50 /// - Authenticates the validity of the token
51 /// # Authorization
52 /// - Token-based
53 /// - Validates authorization using token's authenticity
85 54 #[derive(Clone, Serialize, Deserialize)]
86 55 pub struct TokenExtensionRequest {
87 56 pub token: UserAuthenticationToken,

src/messages/discovery.rs

View file
@@ -3,20 +3,6 @@ use serde::{Deserialize, Serialize};
3 3
4 4 use crate::model::discovery::DiscoveryItem;
5 5
6 use super::InstanceAuthenticated;
7
8 #[derive(Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize)]
9 pub struct DiscoveryMessage {
10 pub message: InstanceAuthenticated<DiscoveryMessageKind>,
11 }
12
13 #[derive(Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize)]
14 pub enum DiscoveryMessageKind {
15 Offer(DiscoveryOffer),
16 Request(DiscoveryRequest),
17 Discoveries(Discoveries),
18 }
19
20 6 #[derive(Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize)]
21 7 pub struct DiscoveryOffer {
22 8 pub earliest: DateTime<Utc>,

src/messages/mod.rs

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

src/messages/repository.rs

View file
@@ -2,112 +2,23 @@ use serde::{Deserialize, Serialize};
2 2
3 3 use crate::model::repository::RepositoryVisibility;
4 4 use crate::model::{
5 repository::{Commit, Repository, RepositoryTreeEntry, RepositoryView},
5 repository::{Commit, Repository, RepositoryTreeEntry},
6 6 user::User,
7 7 };
8 8
9 use super::UnvalidatedUserAuthenticated;
10
11 /// A repository message.
9 /// A request to create a repository.
12 10 ///
13 /// View request documentation, authentication, and authorization
14 /// details in the associated type, [`RepositoryRequest`].
15 #[derive(Clone, Serialize, Deserialize)]
16 pub struct RepositoryMessage {
17 pub target: Repository,
18 pub command: RepositoryMessageKind,
19 }
20
21 #[derive(Clone, Serialize, Deserialize)]
22 pub enum RepositoryMessageKind {
23 Request(RepositoryRequest),
24 Response(RepositoryResponse),
25 }
26
27 #[derive(Clone, Serialize, Deserialize)]
28 pub enum RepositoryRequest {
29 /// A request to create a repository.
30 ///
31 /// # Authentication
32 /// - Instance Authentication
33 /// - Used to validate User token `issued_for`
34 /// - User Authentication
35 /// - Used to source owning user
36 /// - Used to authorize user token against user's instance
37 /// # Authorization
38 /// - Instance Authorization
39 /// - Used to authorize action using User token requiring a correct `issued_for` and valid issuance from user's instance
40 /// - User Authorization
41 /// - Potential User permissions checks
42 CreateRepository(UnvalidatedUserAuthenticated<CreateRepositoryRequest>),
43
44 /// A request to inspect the tree of a repository.
45 ///
46 /// # Authentication
47 /// - Instance Authentication
48 /// - Validate request against the `issued_for` public key
49 /// - Validate User token against the user's instance's public key
50 /// # Authorization
51 /// - User Authorization
52 /// - Potential User permissions checks
53 RepositoryFileInspect(UnvalidatedUserAuthenticated<RepositoryFileInspectRequest>),
54
55 /// A request to get a repository's information.
56 ///
57 /// # Authentication
58 /// - Instance Authentication
59 /// - Validate request against the `issued_for` public key
60 /// - Validate User token against the user's instance's public key
61 /// # Authorization
62 /// - User Authorization
63 /// - Potential User permissions checks
64 RepositoryInfo(UnvalidatedUserAuthenticated<RepositoryInfoRequest>),
65
66 /// A request to get a repository's issues count.
67 ///
68 /// # Authentication
69 /// - Instance Authentication
70 /// - Validate request against the `issued_for` public key
71 /// - Validate User token against the user's instance's public key
72 /// # Authorization
73 /// - User Authorization
74 /// - Potential User permissions checks
75 IssuesCount(UnvalidatedUserAuthenticated<RepositoryIssuesCountRequest>),
76
77 /// A request to get a repository's issue labels.
78 ///
79 /// # Authentication
80 /// - Instance Authentication
81 /// - Validate request against the `issued_for` public key
82 /// - Validate User token against the user's instance's public key
83 /// # Authorization
84 /// - User Authorization
85 /// - Potential User permissions checks
86 IssueLabels(UnvalidatedUserAuthenticated<RepositoryIssueLabelsRequest>),
87
88 /// A request to get a repository's issues.
89 ///
90 /// # Authentication
91 /// - Instance Authentication
92 /// - Validate request against the `issued_for` public key
93 /// - Validate User token against the user's instance's public key
94 /// # Authorization
95 /// - User Authorization
96 /// - Potential User permissions checks
97 Issues(UnvalidatedUserAuthenticated<RepositoryIssuesRequest>),
98 }
99
100 #[derive(Clone, Serialize, Deserialize)]
101 pub enum RepositoryResponse {
102 CreateRepository(CreateRepositoryResponse),
103 RepositoryFileInspection(RepositoryFileInspectionResponse),
104 RepositoryInfo(RepositoryView),
105 IssuesCount(RepositoryIssuesCountResponse),
106 IssueLabels(RepositoryIssueLabelsResponse),
107 Issues(RepositoryIssuesResponse),
108 }
109
110 /// See [`RepositoryRequest::CreateRepository`]'s documentation.
11 /// # Authentication
12 /// - Instance Authentication
13 /// - Used to validate User token `issued_for`
14 /// - User Authentication
15 /// - Used to source owning user
16 /// - Used to authorize user token against user's instance
17 /// # Authorization
18 /// - Instance Authorization
19 /// - Used to authorize action using User token requiring a correct `issued_for` and valid issuance from user's instance
20 /// - User Authorization
21 /// - Potential User permissions checks
111 22 #[derive(Clone, Serialize, Deserialize)]
112 23 pub struct CreateRepositoryRequest {
113 24 pub name: String,
@@ -123,7 +34,15 @@ pub enum CreateRepositoryResponse {
123 34 Failed,
124 35 }
125 36
126 /// See [`RepositoryRequest::RepositoryFileInspect`]'s documentation.
37 /// A request to inspect the tree of a repository.
38 ///
39 /// # Authentication
40 /// - Instance Authentication
41 /// - Validate request against the `issued_for` public key
42 /// - Validate User token against the user's instance's public key
43 /// # Authorization
44 /// - User Authorization
45 /// - Potential User permissions checks
127 46 #[derive(Clone, Serialize, Deserialize)]
128 47 pub struct RepositoryFileInspectRequest {
129 48 pub path: RepositoryTreeEntry,
@@ -143,7 +62,15 @@ pub enum RepositoryFileInspectionResponse {
143 62 },
144 63 }
145 64
146 /// See [`RepositoryRequest::IssuesCount`]'s documentation.
65 /// A request to get a repository's information.
66 ///
67 /// # Authentication
68 /// - Instance Authentication
69 /// - Validate request against the `issued_for` public key
70 /// - Validate User token against the user's instance's public key
71 /// # Authorization
72 /// - User Authorization
73 /// - Potential User permissions checks
147 74 #[derive(Clone, Serialize, Deserialize)]
148 75 pub struct RepositoryIssuesCountRequest;
149 76
@@ -152,7 +79,15 @@ pub struct RepositoryIssuesCountResponse {
152 79 pub count: u64,
153 80 }
154 81
155 /// See [`RepositoryRequest::IssueLabels`]'s documentation.
82 /// A request to get a repository's issues count.
83 ///
84 /// # Authentication
85 /// - Instance Authentication
86 /// - Validate request against the `issued_for` public key
87 /// - Validate User token against the user's instance's public key
88 /// # Authorization
89 /// - User Authorization
90 /// - Potential User permissions checks
156 91 #[derive(Clone, Serialize, Deserialize)]
157 92 pub struct RepositoryIssueLabelsRequest;
158 93
@@ -167,7 +102,15 @@ pub struct IssueLabel {
167 102 pub color: String,
168 103 }
169 104
170 /// See [`RepositoryRequest::Issues`]'s documentation.
105 /// A request to get a repository's issue labels.
106 ///
107 /// # Authentication
108 /// - Instance Authentication
109 /// - Validate request against the `issued_for` public key
110 /// - Validate User token against the user's instance's public key
111 /// # Authorization
112 /// - User Authorization
113 /// - Potential User permissions checks
171 114 #[derive(Clone, Serialize, Deserialize)]
172 115 pub struct RepositoryIssuesRequest;
173 116
@@ -176,6 +119,15 @@ pub struct RepositoryIssuesResponse {
176 119 pub issues: Vec<RepositoryIssue>,
177 120 }
178 121
122 /// A request to get a repository's issues.
123 ///
124 /// # Authentication
125 /// - Instance Authentication
126 /// - Validate request against the `issued_for` public key
127 /// - Validate User token against the user's instance's public key
128 /// # Authorization
129 /// - User Authorization
130 /// - Potential User permissions checks
179 131 #[derive(Clone, Serialize, Deserialize)]
180 132 pub struct RepositoryIssue {
181 133 pub author: User,

src/messages/user.rs

View file
@@ -1,38 +1,6 @@
1 1 use serde::{Deserialize, Serialize};
2 2
3 use crate::model::{
4 instance::Instance,
5 repository::{Repository, RepositorySummary},
6 user::User,
7 };
8
9 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
10 pub struct UserMessage {
11 pub instance: Instance,
12 pub message: UserMessageKind,
13 }
14
15 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16 pub enum UserMessageKind {
17 Request(UserMessageRequest),
18 Response(UserMessageResponse),
19 }
20
21 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
22 pub enum UserMessageRequest {
23 DisplayName(UserDisplayNameRequest),
24 DisplayImage(UserDisplayImageRequest),
25 Bio(UserBioRequest),
26 Repositories(UserRepositoriesRequest),
27 }
28
29 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
30 pub enum UserMessageResponse {
31 DisplayName(UserDisplayNameResponse),
32 DisplayImage(UserDisplayImageResponse),
33 Bio(UserBioResponse),
34 Repositories(UserRepositoriesResponse),
35 }
3 use crate::model::{repository::RepositorySummary, user::User};
36 4
37 5 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
38 6 pub struct UserDisplayNameRequest {

src/model/authenticated.rs

View file
@@ -1,14 +1,12 @@
1 use std::{any::type_name, ops::Deref, pin::Pin, str::FromStr};
1 use std::{any::type_name, collections::HashMap, ops::Deref};
2 2
3 3 use anyhow::Error;
4 use futures_util::{future::BoxFuture, Future, FutureExt};
4 use futures_util::Future;
5 5 use jsonwebtoken::{decode, Algorithm, DecodingKey, TokenData, Validation};
6 use rsa::{pkcs1::DecodeRsaPublicKey, RsaPublicKey};
7 6 use serde::{de::DeserializeOwned, Deserialize, Serialize};
7 use serde_json::Value;
8 8
9 use crate::{
10 authentication::UserTokenMetadata, connection::wrapper::ConnectionState, messages::MessageKind,
11 };
9 use crate::{authentication::UserTokenMetadata, connection::wrapper::ConnectionState};
12 10
13 11 use super::{instance::Instance, user::User};
14 12
@@ -88,7 +86,7 @@ pub struct UserAuthenticator {
88 86 }
89 87
90 88 impl AuthenticationSourceProvider for UserAuthenticator {
91 fn authenticate(self, payload: &Vec<u8>) -> AuthenticationSource {
89 fn authenticate(self, _payload: &Vec<u8>) -> AuthenticationSource {
92 90 AuthenticationSource::User {
93 91 user: self.user,
94 92 token: self.token,
@@ -103,7 +101,7 @@ pub struct InstanceAuthenticator<'a> {
103 101 }
104 102
105 103 impl AuthenticationSourceProvider for InstanceAuthenticator<'_> {
106 fn authenticate(self, payload: &Vec<u8>) -> AuthenticationSource {
104 fn authenticate(self, _payload: &Vec<u8>) -> AuthenticationSource {
107 105 todo!()
108 106 }
109 107 }
@@ -188,7 +186,7 @@ impl FromMessage<ConnectionState> for AuthenticatedUser {
188 186 network_message: &NetworkMessage,
189 187 state: &ConnectionState,
190 188 ) -> Result<Self, Error> {
191 let message: Authenticated<MessageKind> =
189 let message: Authenticated<HashMap<String, Value>> =
192 190 serde_json::from_slice(&network_message).map_err(|e| Error::from(e))?;
193 191
194 192 let (auth_user, auth_token) = message
@@ -230,18 +228,8 @@ impl FromMessage<ConnectionState> for AuthenticatedUser {
230 228 #[async_trait::async_trait]
231 229 impl FromMessage<ConnectionState> for AuthenticatedInstance {
232 230 async fn from_message(
233 message: &NetworkMessage,
234 state: &ConnectionState,
235 ) -> Result<Self, Error> {
236 todo!()
237 }
238 }
239
240 #[async_trait::async_trait]
241 impl FromMessage<ConnectionState> for MessageKind {
242 async fn from_message(
243 message: &NetworkMessage,
244 state: &ConnectionState,
231 _message: &NetworkMessage,
232 _state: &ConnectionState,
245 233 ) -> Result<Self, Error> {
246 234 todo!()
247 235 }