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

Showing ⁨⁨12⁩ changed files⁩ with ⁨⁨159⁩ insertions⁩ and ⁨⁨39⁩ deletions⁩

giterated-daemon/src/backend/user.rs

View file
@@ -5,7 +5,6 @@ use anyhow::Error;
5 5 use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, Key, KeyInit};
6 6 use argon2::{password_hash::SaltString, Argon2, PasswordHasher};
7 7 use base64::{engine::general_purpose::STANDARD, Engine as _};
8 use futures_util::StreamExt;
9 8 use giterated_models::{
10 9 messages::{
11 10 authentication::{

giterated-daemon/src/connection/authentication.rs

View file
@@ -1,5 +1,3 @@
1 use std::sync::Arc;
2
3 1 use anyhow::Error;
4 2 use thiserror::Error;
5 3 use tokio::{fs::File, io::AsyncReadExt};
@@ -7,7 +5,8 @@ use tokio::{fs::File, io::AsyncReadExt};
7 5 use crate::message::{AuthenticatedInstance, Message, MessageHandler, NetworkMessage, State};
8 6 use giterated_models::{
9 7 messages::authentication::{
10 AuthenticationTokenRequest, RegisterAccountRequest, TokenExtensionRequest, AuthenticationTokenResponse,
8 AuthenticationTokenRequest, AuthenticationTokenResponse, RegisterAccountRequest,
9 TokenExtensionRequest,
11 10 },
12 11 model::authenticated::InstanceAuthenticator,
13 12 };
@@ -20,21 +19,21 @@ pub async fn authentication_handle(
20 19 state: &ConnectionState,
21 20 ) -> Result<bool, Error> {
22 21 match message_type {
23 "&giterated_models::messages::authentication::RegisterAccountRequest" => {
22 "giterated_models::messages::authentication::RegisterAccountRequest" => {
24 23 register_account_request
25 24 .handle_message(&message, state)
26 25 .await?;
27 26
28 27 Ok(true)
29 28 }
30 "&giterated_models::messages::authentication::AuthenticationTokenRequest" => {
29 "giterated_models::messages::authentication::AuthenticationTokenRequest" => {
31 30 authentication_token_request
32 31 .handle_message(&message, state)
33 32 .await?;
34 33
35 34 Ok(true)
36 35 }
37 "&giterated_models::messages::authentication::TokenExtensionRequest" => {
36 "giterated_models::messages::authentication::TokenExtensionRequest" => {
38 37 token_extension_request
39 38 .handle_message(&message, state)
40 39 .await?;
@@ -83,14 +82,22 @@ async fn authentication_token_request(
83 82 let connection = connections.get_or_open(&request.instance).unwrap();
84 83
85 84 let private_key = {
86 let mut file = File::open(connection_state.config["giterated"]["keys"]["private"].as_str().unwrap()).await.unwrap();
85 let mut file = File::open(
86 connection_state.config["giterated"]["keys"]["private"]
87 .as_str()
88 .unwrap(),
89 )
90 .await
91 .unwrap();
87 92
88 93 let mut key = String::new();
89 94 file.read_to_string(&mut key).await.unwrap();
90
95
91 96 key
92 97 };
93 98
99 info!("Our private key: {}", private_key);
100
94 101 let authenticator = InstanceAuthenticator {
95 102 instance: connection_state.instance.clone(),
96 103 private_key,
@@ -99,10 +106,14 @@ async fn authentication_token_request(
99 106 let response = giterated_api::request::request_local(request)
100 107 .authenticate(authenticator)
101 108 .execute_expect::<AuthenticationTokenResponse>(&connection)
102 .await.unwrap();
109 .await
110 .unwrap();
103 111 drop(connection);
104 112
105 connection_state.send(response).await.map_err(|e| AuthenticationConnectionError::Sending(e))?;
113 connection_state
114 .send(response)
115 .await
116 .map_err(|e| AuthenticationConnectionError::Sending(e))?;
106 117
107 118 return Ok(());
108 119 }
@@ -159,12 +170,3 @@ pub enum AuthenticationConnectionError {
159 170 #[error("error issuing token")]
160 171 TokenIssuance(Error),
161 172 }
162
163 async fn private_key(path: &str) -> Vec<u8> {
164 let mut file = File::open(path).await.unwrap();
165
166 let mut key = vec![];
167 file.read_to_end(&mut key).await.unwrap();
168
169 key
170 }

giterated-daemon/src/connection/repository.rs

View file
@@ -17,34 +17,34 @@ pub async fn repository_handle(
17 17 state: &ConnectionState,
18 18 ) -> Result<bool, Error> {
19 19 match message_type {
20 "&giterated_models::messages::repository::RepositoryCreateRequest" => {
20 "giterated_models::messages::repository::RepositoryCreateRequest" => {
21 21 create_repository.handle_message(&message, state).await?;
22 22
23 23 Ok(true)
24 24 }
25 "&giterated_models::messages::repository::RepositoryFileInspectRequest" => {
25 "giterated_models::messages::repository::RepositoryFileInspectRequest" => {
26 26 repository_file_inspect
27 27 .handle_message(&message, state)
28 28 .await?;
29 29
30 30 Ok(true)
31 31 }
32 "&giterated_models::messages::repository::RepositoryInfoRequest" => {
32 "giterated_models::messages::repository::RepositoryInfoRequest" => {
33 33 repository_info.handle_message(&message, state).await?;
34 34
35 35 Ok(true)
36 36 }
37 "&giterated_models::messages::repository::RepositoryIssuesCountRequest" => {
37 "giterated_models::messages::repository::RepositoryIssuesCountRequest" => {
38 38 issues_count.handle_message(&message, state).await?;
39 39
40 40 Ok(true)
41 41 }
42 "&giterated_models::messages::repository::RepositoryIssueLabelsRequest" => {
42 "giterated_models::messages::repository::RepositoryIssueLabelsRequest" => {
43 43 issue_labels.handle_message(&message, state).await?;
44 44
45 45 Ok(true)
46 46 }
47 "&giterated_models::messages::repository::RepositoryIssuesRequest" => {
47 "giterated_models::messages::repository::RepositoryIssuesRequest" => {
48 48 issues.handle_message(&message, state).await?;
49 49
50 50 Ok(true)

giterated-daemon/src/connection/user.rs

View file
@@ -18,32 +18,32 @@ pub async fn user_handle(
18 18 state: &ConnectionState,
19 19 ) -> Result<bool, Error> {
20 20 match message_type {
21 "&giterated_models::messages::user::UserDisplayNameRequest" => {
21 "giterated_models::messages::user::UserDisplayNameRequest" => {
22 22 display_name.handle_message(&message, state).await?;
23 23
24 24 Ok(true)
25 25 }
26 "&giterated_models::messages::user::UserDisplayImageRequest" => {
26 "giterated_models::messages::user::UserDisplayImageRequest" => {
27 27 display_image.handle_message(&message, state).await?;
28 28
29 29 Ok(true)
30 30 }
31 "&giterated_models::messages::user::UserBioRequest" => {
31 "giterated_models::messages::user::UserBioRequest" => {
32 32 bio.handle_message(&message, state).await?;
33 33
34 34 Ok(true)
35 35 }
36 "&giterated_models::messages::user::UserRepositoriesRequest" => {
36 "giterated_models::messages::user::UserRepositoriesRequest" => {
37 37 repositories.handle_message(&message, state).await?;
38 38
39 39 Ok(true)
40 40 }
41 "&giterated_models::messages::user::UserSettingsRequest" => {
41 "giterated_models::messages::user::UserSettingsRequest" => {
42 42 user_settings.handle_message(&message, state).await?;
43 43
44 44 Ok(true)
45 45 }
46 "&giterated_models::messages::user::UserWriteSettingsRequest" => {
46 "giterated_models::messages::user::UserWriteSettingsRequest" => {
47 47 write_user_settings.handle_message(&message, state).await?;
48 48
49 49 Ok(true)

giterated-daemon/src/main.rs

View file
@@ -115,7 +115,7 @@ async fn main() -> Result<(), Error> {
115 115 token_granter.clone(),
116 116 settings.clone(),
117 117 address,
118 Instance::from_str("giterated.dev").unwrap(),
118 Instance::from_str(config["giterated"]["instance"].as_str().unwrap()).unwrap(),
119 119 instance_connections.clone(),
120 120 config.clone(),
121 121 )),

giterated-daemon/src/message.rs

View file
@@ -9,7 +9,7 @@ use giterated_models::model::{
9 9 };
10 10 use jsonwebtoken::{decode, Algorithm, DecodingKey, TokenData, Validation};
11 11 use rsa::{
12 pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey},
12 pkcs1::DecodeRsaPublicKey,
13 13 pss::{Signature, VerifyingKey},
14 14 sha2::Sha256,
15 15 signature::Verifier,
@@ -110,6 +110,8 @@ impl FromMessage<ConnectionState> for AuthenticatedInstance {
110 110 let message: AuthenticatedPayload =
111 111 serde_json::from_slice(&network_message).map_err(|e| Error::from(e))?;
112 112
113 info!("Authenticated payload: {:?}", message);
114
113 115 let (instance, signature) = message
114 116 .source
115 117 .iter()
@@ -128,6 +130,10 @@ impl FromMessage<ConnectionState> for AuthenticatedInstance {
128 130 // TODO: Instance authentication error
129 131 .ok_or_else(|| UserAuthenticationError::Missing)?;
130 132
133 info!("Instance: {}", instance.clone().to_string());
134
135 info!("Instance public key: {}", state.public_key(instance).await?);
136
131 137 let public_key = RsaPublicKey::from_pkcs1_pem(&state.public_key(instance).await?).unwrap();
132 138
133 139 let verifying_key: VerifyingKey<Sha256> = VerifyingKey::new(public_key);

giterated-models/src/messages/authentication.rs

View file
@@ -2,6 +2,8 @@ use serde::{Deserialize, Serialize};
2 2
3 3 use crate::model::{authenticated::UserAuthenticationToken, instance::Instance};
4 4
5 use super::MessageTarget;
6
5 7 /// An account registration request.
6 8 ///
7 9 /// # Authentication
@@ -37,6 +39,12 @@ pub struct AuthenticationTokenRequest {
37 39 pub password: String,
38 40 }
39 41
42 impl MessageTarget for AuthenticationTokenRequest {
43 fn target(&self) -> Option<Instance> {
44 Some(self.instance.clone())
45 }
46 }
47
40 48 #[derive(Clone, Debug, Serialize, Deserialize)]
41 49 pub struct AuthenticationTokenResponse {
42 50 pub token: UserAuthenticationToken,
@@ -57,6 +65,13 @@ pub struct TokenExtensionRequest {
57 65 pub token: UserAuthenticationToken,
58 66 }
59 67
68 impl MessageTarget for TokenExtensionRequest {
69 fn target(&self) -> Option<Instance> {
70 // todo!
71 None
72 }
73 }
74
60 75 #[derive(Clone, Debug, Serialize, Deserialize)]
61 76 pub struct TokenExtensionResponse {
62 77 pub new_token: Option<String>,

giterated-models/src/messages/discovery.rs

View file
@@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize};
3 3
4 4 use crate::model::discovery::DiscoveryItem;
5 5
6 use super::MessageTarget;
7
6 8 #[derive(Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize)]
7 9 pub struct DiscoveryOffer {
8 10 pub earliest: DateTime<Utc>,
@@ -15,6 +17,12 @@ pub struct DiscoveryRequest {
15 17 pub hashes: Vec<u128>,
16 18 }
17 19
20 impl MessageTarget for DiscoveryRequest {
21 fn target(&self) -> Option<crate::model::instance::Instance> {
22 None
23 }
24 }
25
18 26 #[derive(Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize)]
19 27 pub struct Discoveries {
20 28 pub discoveries: Vec<DiscoveryItem>,

giterated-models/src/messages/mod.rs

View file
@@ -1,7 +1,7 @@
1 1 use serde::{Deserialize, Serialize};
2 2 use std::fmt::Debug;
3 3
4 use crate::model::user::User;
4 use crate::model::{instance::Instance, user::User};
5 5
6 6 pub mod authentication;
7 7 pub mod discovery;
@@ -18,3 +18,9 @@ pub enum ErrorMessage {
18 18 #[error("internal error: shutdown")]
19 19 Shutdown,
20 20 }
21
22 pub trait MessageTarget {
23 fn target(&self) -> Option<Instance> {
24 None
25 }
26 }

giterated-models/src/messages/repository.rs

View file
@@ -3,6 +3,7 @@ use std::collections::HashMap;
3 3 use serde::de::DeserializeOwned;
4 4 use serde::{Deserialize, Serialize};
5 5
6 use crate::model::instance::Instance;
6 7 use crate::model::repository::RepositoryVisibility;
7 8 use crate::model::settings::Setting;
8 9 use crate::model::{
@@ -10,6 +11,8 @@ use crate::model::{
10 11 user::User,
11 12 };
12 13
14 use super::MessageTarget;
15
13 16 /// A request to create a repository.
14 17 ///
15 18 /// # Authentication
@@ -25,6 +28,7 @@ use crate::model::{
25 28 /// - Potential User permissions checks
26 29 #[derive(Clone, Debug, Serialize, Deserialize)]
27 30 pub struct RepositoryCreateRequest {
31 pub instance: Option<Instance>,
28 32 pub name: String,
29 33 pub description: Option<String>,
30 34 pub visibility: RepositoryVisibility,
@@ -32,6 +36,12 @@ pub struct RepositoryCreateRequest {
32 36 pub owner: User,
33 37 }
34 38
39 impl MessageTarget for RepositoryCreateRequest {
40 fn target(&self) -> Option<crate::model::instance::Instance> {
41 self.instance.clone()
42 }
43 }
44
35 45 #[derive(Clone, Debug, Serialize, Deserialize)]
36 46 pub struct RepositoryCreateResponse;
37 47
@@ -46,9 +56,16 @@ pub struct RepositoryCreateResponse;
46 56 /// - Potential User permissions checks
47 57 #[derive(Clone, Debug, Serialize, Deserialize)]
48 58 pub struct RepositoryFileInspectRequest {
59 pub repository: Repository,
49 60 pub path: RepositoryTreeEntry,
50 61 }
51 62
63 impl MessageTarget for RepositoryFileInspectRequest {
64 fn target(&self) -> Option<Instance> {
65 Some(self.repository.instance.clone())
66 }
67 }
68
52 69 #[derive(Clone, Debug, Serialize, Deserialize)]
53 70 pub enum RepositoryFileInspectionResponse {
54 71 File {
@@ -75,6 +92,8 @@ pub enum RepositoryFileInspectionResponse {
75 92 #[derive(Clone, Debug, Serialize, Deserialize)]
76 93 pub struct RepositoryIssuesCountRequest;
77 94
95 impl MessageTarget for RepositoryIssuesCountRequest {}
96
78 97 #[derive(Clone, Debug, Serialize, Deserialize)]
79 98 pub struct RepositoryIssuesCountResponse {
80 99 pub count: u64,
@@ -92,6 +111,8 @@ pub struct RepositoryIssuesCountResponse {
92 111 #[derive(Clone, Debug, Serialize, Deserialize)]
93 112 pub struct RepositoryIssueLabelsRequest;
94 113
114 impl MessageTarget for RepositoryIssueLabelsRequest {}
115
95 116 #[derive(Clone, Debug, Serialize, Deserialize)]
96 117 pub struct RepositoryIssueLabelsResponse {
97 118 pub labels: Vec<IssueLabel>,
@@ -115,6 +136,8 @@ pub struct IssueLabel {
115 136 #[derive(Clone, Debug, Serialize, Deserialize)]
116 137 pub struct RepositoryIssuesRequest;
117 138
139 impl MessageTarget for RepositoryIssuesRequest {}
140
118 141 #[derive(Clone, Debug, Serialize, Deserialize)]
119 142 pub struct RepositoryIssuesResponse {
120 143 pub issues: Vec<RepositoryIssue>,
@@ -149,11 +172,23 @@ pub struct RepositoryInfoRequest {
149 172 pub path: Option<String>,
150 173 }
151 174
175 impl MessageTarget for RepositoryInfoRequest {
176 fn target(&self) -> Option<Instance> {
177 Some(self.repository.instance.clone())
178 }
179 }
180
152 181 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
153 182 pub struct RepositorySettingsRequest {
154 183 pub repository: Repository,
155 184 }
156 185
186 impl MessageTarget for RepositorySettingsRequest {
187 fn target(&self) -> Option<Instance> {
188 Some(self.repository.instance.clone())
189 }
190 }
191
157 192 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Default, Deserialize)]
158 193 pub struct RepositorySettingsResponse {
159 194 pub settings: HashMap<String, serde_json::Value>,
@@ -177,6 +212,12 @@ pub struct RepositoryWriteSettingsRequest {
177 212 pub settings: Vec<(String, String)>,
178 213 }
179 214
215 impl MessageTarget for RepositoryWriteSettingsRequest {
216 fn target(&self) -> Option<Instance> {
217 Some(self.repository.instance.clone())
218 }
219 }
220
180 221 impl RepositoryWriteSettingsRequest {
181 222 pub fn new(repository: impl ToOwned<Owned = Repository>) -> Self {
182 223 Self {

giterated-models/src/messages/user.rs

View file
@@ -2,13 +2,23 @@ use std::collections::HashMap;
2 2
3 3 use serde::{de::DeserializeOwned, Deserialize, Serialize};
4 4
5 use crate::model::{repository::RepositorySummary, settings::Setting, user::User};
5 use crate::model::{
6 instance::Instance, repository::RepositorySummary, settings::Setting, user::User,
7 };
8
9 use super::MessageTarget;
6 10
7 11 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
8 12 pub struct UserDisplayNameRequest {
9 13 pub user: User,
10 14 }
11 15
16 impl MessageTarget for UserDisplayNameRequest {
17 fn target(&self) -> Option<Instance> {
18 Some(self.user.instance.clone())
19 }
20 }
21
12 22 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
13 23 pub struct UserDisplayNameResponse {
14 24 pub display_name: Option<String>,
@@ -19,6 +29,12 @@ pub struct UserDisplayImageRequest {
19 29 pub user: User,
20 30 }
21 31
32 impl MessageTarget for UserDisplayImageRequest {
33 fn target(&self) -> Option<Instance> {
34 Some(self.user.instance.clone())
35 }
36 }
37
22 38 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
23 39 pub struct UserDisplayImageResponse {
24 40 pub image_url: Option<String>,
@@ -29,6 +45,12 @@ pub struct UserBioRequest {
29 45 pub user: User,
30 46 }
31 47
48 impl MessageTarget for UserBioRequest {
49 fn target(&self) -> Option<Instance> {
50 Some(self.user.instance.clone())
51 }
52 }
53
32 54 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
33 55 pub struct UserBioResponse {
34 56 pub bio: Option<String>,
@@ -36,9 +58,16 @@ pub struct UserBioResponse {
36 58
37 59 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
38 60 pub struct UserRepositoriesRequest {
61 pub instance: Instance,
39 62 pub user: User,
40 63 }
41 64
65 impl MessageTarget for UserRepositoriesRequest {
66 fn target(&self) -> Option<Instance> {
67 Some(self.instance.clone())
68 }
69 }
70
42 71 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
43 72 pub struct UserRepositoriesResponse {
44 73 pub repositories: Vec<RepositorySummary>,
@@ -49,6 +78,12 @@ pub struct UserSettingsRequest {
49 78 pub user: User,
50 79 }
51 80
81 impl MessageTarget for UserSettingsRequest {
82 fn target(&self) -> Option<Instance> {
83 Some(self.user.instance.clone())
84 }
85 }
86
52 87 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Default, Deserialize)]
53 88 pub struct UserSettingsResponse {
54 89 pub settings: HashMap<String, serde_json::Value>,
@@ -72,6 +107,12 @@ pub struct UserWriteSettingsRequest {
72 107 pub settings: Vec<(String, String)>,
73 108 }
74 109
110 impl MessageTarget for UserWriteSettingsRequest {
111 fn target(&self) -> Option<Instance> {
112 Some(self.user.instance.clone())
113 }
114 }
115
75 116 impl UserWriteSettingsRequest {
76 117 pub fn new(user: impl ToOwned<Owned = User>) -> Self {
77 118 Self {

giterated-models/src/model/authenticated.rs

View file
@@ -10,6 +10,8 @@ use rsa::{
10 10 use serde::{Deserialize, Serialize};
11 11 use tracing::info;
12 12
13 use crate::messages::MessageTarget;
14
13 15 use super::{instance::Instance, user::User};
14 16
15 17 #[derive(Debug, Serialize, Deserialize)]
@@ -81,13 +83,13 @@ where
81 83 }
82 84 }
83 85
84 impl<T: Serialize + Debug> Authenticated<T> {
86 impl<T: Serialize + Debug + MessageTarget> Authenticated<T> {
85 87 pub fn new(message: T) -> Self {
86 88 Self {
87 89 source: vec![],
88 90 message_type: type_name::<T>().to_string(),
91 target_instance: message.target(),
89 92 message,
90 target_instance: None,
91 93 }
92 94 }
93 95
@@ -104,8 +106,8 @@ impl<T: Serialize + Debug> Authenticated<T> {
104 106 Self {
105 107 source: vec![],
106 108 message_type: type_name::<T>().to_string(),
109 target_instance: message.target(),
107 110 message,
108 target_instance: None,
109 111 }
110 112 }
111 113