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

ambee/giterated-api

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

Many things

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨d782588

Showing ⁨⁨8⁩ changed files⁩ with ⁨⁨539⁩ insertions⁩ and ⁨⁨91⁩ deletions⁩

Cargo.toml

View file
@@ -16,4 +16,7 @@ serde = { version = "1", features = ["derive"]}
16 16 serde_json = "1.0"
17 17 tracing-subscriber = "0.3"
18 18 rand = "*"
19 jsonwebtoken = { version = "*", features = ["use_pem"]}
19 \ No newline at end of file
19 jsonwebtoken = { version = "*", features = ["use_pem"]}
20 chrono = { version = "0.4", features = [ "serde", "std" ] }
21 reqwest = { version = "0.11" }
22 anyhow = "*"
22 \ No newline at end of file

src/example_keys/giterated.key

View file
@@ -0,0 +1,51 @@
1 -----BEGIN RSA PRIVATE KEY-----
2 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
51 -----END RSA PRIVATE KEY-----
51 \ No newline at end of file

src/example_keys/giterated.key.pub

View file
@@ -0,0 +1,13 @@
1 -----BEGIN RSA PUBLIC KEY-----
2 MIICCgKCAgEArGLMTdU15wfXOX3SwbQTZnAEvMfWK7JBH3t0ZHYcnQRJQt2/OAvH
3 9h8WwQAjXcoS9wEvFfEJA2OWdzHWJSSnDD8M5eI2F8+cZeQ5bBk6YGxyYkVopkV/
4 RxoitlFFXeSTksQO7VVG9qiw5lcsW+WRw9LJHSyviV8AXZY0GK3RHZwsQnEYIfmi
5 waW1+gUEi2ztoBTQjJXH/MkXdYOXqINzVPta/cfw7lOJHOh1X4WSkKErfCR0GW4P
6 hAdj3hQFHknta9Fm2SBmgEZt6P/RSprUuKuX7Ufr8mb5Vqv7HwCKapsFym7Dgvbe
7 y3M8nCdpWc3w1B/X4vW0cePZg6XX3VAXmMgB6o9WW23IwAaWMWGe1v/oXOUj7y2+
8 BIzCTUbYdDruVZ9szpNvq9ddGqTGhpivKnpyAANe5e4ggppV4zZC4yKmVqDQO2MJ
9 h+Qr0mIkbOFFbytvAzIlKBWL+zeMtloOjvIU5F6AoWCr3W0EoJy4oDR0ZVtovcqE
10 TPtYuoFJ1Y5qlAIiC/J1TfKIRhB09WiuSzG5enEOH8thojulS46kIgJqKLMOvBi3
11 JUf5EHqEXGjIILcb9plAI6D3pHV4rUNIv3KY0ci2PqMfmHjE3v/ELlu4YKKqfhn/
12 fDMuYphZ41Ga0eaKRhV4ClwFWeI0hOVXhk6C01UZZct2ZbvayraTZCECAwEAAQ==
13 -----END RSA PUBLIC KEY-----

src/lib.rs

View file
@@ -1,14 +1,25 @@
1 use std::convert::Infallible;
2 use std::str::FromStr;
1 3 use std::{error::Error, net::SocketAddr};
2 4
3 5 use futures_util::{SinkExt, StreamExt};
6 use giterated_daemon::messages::authentication::{RegisterAccountRequest, RegisterAccountResponse};
7 use giterated_daemon::messages::UnvalidatedUserAuthenticated;
8 use giterated_daemon::model::repository::RepositoryVisibility;
9 use giterated_daemon::model::user::User;
10 use giterated_daemon::{version, validate_version};
4 11 use giterated_daemon::{
5 12 handshake::{HandshakeFinalize, HandshakeMessage, InitiateHandshake},
6 13 messages::{
14 authentication::{
15 AuthenticationMessage, AuthenticationRequest, AuthenticationResponse,
16 AuthenticationTokenRequest, TokenExtensionRequest,
17 },
7 18 repository::{
8 19 CreateRepositoryRequest, RepositoryInfoRequest, RepositoryMessage,
9 20 RepositoryMessageKind, RepositoryRequest, RepositoryResponse,
10 21 },
11 MessageKind,
22 InstanceAuthenticated, MessageKind,
12 23 },
13 24 model::{
14 25 instance::Instance,
@@ -24,38 +35,224 @@ type Socket = WebSocketStream<MaybeTlsStream<TcpStream>>;
24 35 #[macro_use]
25 36 extern crate tracing;
26 37
27 pub struct GiteratedApi;
38 pub struct GiteratedApiBuilder {
39 our_instance: Instance,
40 our_private_key: Option<String>,
41 our_public_key: Option<String>,
42 target_instance: Option<Instance>,
43 }
44
45 pub trait AsInstance {
46 type Error: Error + Send + Sync + 'static;
47
48 fn into_instance(self) -> Result<Instance, Self::Error>;
49 }
50
51 impl AsInstance for &str {
52 type Error = <Instance as FromStr>::Err;
53
54 fn into_instance(self) -> Result<Instance, Self::Error> {
55 Instance::from_str(self)
56 }
57 }
58
59 impl AsInstance for Instance {
60 type Error = Infallible;
61
62 fn into_instance(self) -> Result<Instance, Self::Error> {
63 Ok(self)
64 }
65 }
66
67 impl GiteratedApiBuilder {
68 pub fn from_local(instance: impl AsInstance) -> Result<Self, anyhow::Error> {
69 Ok(Self {
70 our_instance: instance.into_instance()?,
71 our_private_key: None,
72 our_public_key: None,
73 target_instance: None,
74 })
75 }
76
77 pub fn from_local_for_other(
78 instance: impl AsInstance,
79 other: impl AsInstance,
80 ) -> Result<Self, anyhow::Error> {
81 Ok(Self {
82 our_instance: instance.into_instance()?,
83 our_private_key: None,
84 our_public_key: None,
85 target_instance: Some(other.into_instance()?),
86 })
87 }
88
89 pub fn private_key(&mut self, key: impl ToString) -> &mut Self {
90 self.our_private_key = Some(key.to_string());
91
92 self
93 }
94
95 pub fn public_key(&mut self, key: impl ToString) -> &mut Self {
96 self.our_public_key = Some(key.to_string());
97
98 self
99 }
100
101 pub async fn build(&mut self) -> Result<GiteratedApi, anyhow::Error> {
102 Ok(GiteratedApi::new(
103 self.our_instance.clone(),
104 self.our_private_key.clone().unwrap(),
105 self.our_public_key.clone().unwrap(),
106 self.target_instance.clone(),
107 )
108 .await?)
109 }
110 }
111
112 pub struct GiteratedApi {
113 pub connection: Socket,
114 pub our_instance: Instance,
115 pub our_private_key: String,
116 pub our_public_key: String,
117 pub target_instance: Option<Instance>,
118 pub target_public_key: Option<String>,
119 }
28 120
29 121 impl GiteratedApi {
122 pub async fn new(
123 local_instance: Instance,
124 private_key: String,
125 public_key: String,
126 target_instance: Option<Instance>,
127 ) -> Result<Self, anyhow::Error> {
128 let connection = Self::connect_to(
129 target_instance
130 .clone()
131 .unwrap_or_else(|| local_instance.clone()),
132 )
133 .await?;
134
135 let mut api = GiteratedApi {
136 connection,
137 our_instance: local_instance,
138 our_private_key: private_key,
139 our_public_key: public_key,
140 target_instance,
141 target_public_key: None,
142 };
143
144 // Handle handshake
145 api.handle_handshake().await?;
146
147 Ok(api)
148 }
149
150 pub async fn public_key(&mut self) -> String {
151 if let Some(public_key) = &self.target_public_key {
152 public_key.clone()
153 } else {
154 let key = reqwest::get(format!(
155 "https://{}/.giterated/pubkey.pem",
156 self.target_instance
157 .as_ref()
158 .unwrap_or_else(|| &self.our_instance)
159 .url
160 ))
161 .await
162 .unwrap()
163 .text()
164 .await
165 .unwrap();
166
167 self.target_public_key = Some(key.clone());
168
169 key
170 }
171 }
172
173 /// Register on an [`Instance`].
174 ///
175 /// # Authorization
176 /// - Must be made by the same instance its being sent to
177 pub async fn register(
178 &mut self,
179 username: String,
180 email: Option<String>,
181 password: String,
182 ) -> Result<RegisterAccountResponse, Box<dyn Error>> {
183 let message = InstanceAuthenticated::new(
184 RegisterAccountRequest {
185 username,
186 email,
187 password,
188 },
189 self.our_instance.clone(),
190 self.our_private_key.clone(),
191 )
192 .unwrap();
193
194 self.send_message(&MessageKind::Authentication(
195 AuthenticationMessage::Request(AuthenticationRequest::RegisterAccount(message)),
196 ))
197 .await?;
198
199 while let Ok(payload) = self.next_payload().await {
200 if let Ok(MessageKind::Authentication(AuthenticationMessage::Response(
201 AuthenticationResponse::RegisterAccount(response),
202 ))) = serde_json::from_slice(&payload)
203 {
204 return Ok(response);
205 }
206 }
207
208 unreachable!()
209 }
210
211 /// Create repository on the target instance.
30 212 pub async fn create_repository(
31 target: Instance,
32 request: CreateRepositoryRequest,
213 &mut self,
214 user_token: String,
215 name: String,
216 description: Option<String>,
217 visibility: RepositoryVisibility,
218 default_branch: String,
219 owner: User,
33 220 ) -> Result<bool, Box<dyn Error>> {
34 let mut socket = Self::connect_to(&target.url).await?;
35 let target = Repository {
36 name: request.name.clone(),
37 instance: target,
221 let target_respository = Repository {
222 owner: owner.clone(),
223 name: name.clone(),
224 instance: self
225 .target_instance
226 .as_ref()
227 .unwrap_or(&self.our_instance)
228 .clone(),
38 229 };
39 230
40 Self::send_message(
41 &MessageKind::Repository(RepositoryMessage {
42 target,
43 command: RepositoryMessageKind::Request(RepositoryRequest::CreateRepository(
44 request,
45 )),
46 }),
47 &mut socket,
48 )
231 let request = CreateRepositoryRequest {
232 name,
233 description,
234 visibility,
235 default_branch,
236 owner,
237 };
238
239 let message =
240 UnvalidatedUserAuthenticated::new(request, user_token, self.our_private_key.clone())
241 .unwrap();
242
243 self.send_message(&MessageKind::Repository(RepositoryMessage {
244 target: target_respository,
245 command: RepositoryMessageKind::Request(RepositoryRequest::CreateRepository(message)),
246 }))
49 247 .await?;
50 248
51 while let Ok(payload) = Self::next_payload(&mut socket).await {
249 while let Ok(payload) = self.next_payload().await {
52 250 if let Ok(MessageKind::Repository(RepositoryMessage {
53 251 command:
54 252 RepositoryMessageKind::Response(RepositoryResponse::CreateRepository(_response)),
55 253 ..
56 254 })) = serde_json::from_slice(&payload)
57 255 {
58 socket.close(None).await?;
59 256 return Ok(true);
60 257 }
61 258 }
@@ -63,23 +260,32 @@ impl GiteratedApi {
63 260 unreachable!()
64 261 }
65 262
66 pub async fn repository_info(repository: Repository) -> Result<RepositoryView, Box<dyn Error>> {
67 let mut socket = Self::connect_to(&repository.instance.url).await?;
68
69 Self::send_message(
70 &MessageKind::Repository(RepositoryMessage {
71 target: repository.clone(),
72 command: RepositoryMessageKind::Request(RepositoryRequest::RepositoryInfo(
73 RepositoryInfoRequest,
74 )),
75 }),
76 &mut socket,
263 pub async fn repository_info(
264 &mut self,
265 token: &str,
266 repository: Repository,
267 ) -> Result<RepositoryView, Box<dyn Error>> {
268 let message = UnvalidatedUserAuthenticated::new(
269 RepositoryInfoRequest {
270 repository: repository.clone(),
271 extra_metadata: true,
272 rev: None,
273 path: None,
274 },
275 token.to_string(),
276 self.our_private_key.clone(),
77 277 )
278 .unwrap();
279
280 self.send_message(&MessageKind::Repository(RepositoryMessage {
281 target: repository.clone(),
282 command: RepositoryMessageKind::Request(RepositoryRequest::RepositoryInfo(message)),
283 }))
78 284 .await?;
79 285
80 286 loop {
81 287 // while let Ok(payload) = Self::next_payload(&mut socket).await {
82 let payload = match Self::next_payload(&mut socket).await {
288 let payload = match self.next_payload().await {
83 289 Ok(payload) => payload,
84 290 Err(err) => {
85 291 error!("Error while fetching next payload: {:?}", err);
@@ -93,37 +299,116 @@ impl GiteratedApi {
93 299 ..
94 300 })) = serde_json::from_slice(&payload)
95 301 {
96 socket.close(None).await?;
97 302 return Ok(response);
98 303 }
99 304 }
305 }
100 306
101 unreachable!()
307 /// Requests an authentication token for the given login.
308 ///
309 /// # Authorization
310 /// This request can only be sent to the same instance from which
311 /// it is issued.
312 pub async fn authentication_token(
313 &mut self,
314 secret_key: String,
315 username: String,
316 password: String,
317 ) -> Result<String, Box<dyn Error>> {
318 let request = InstanceAuthenticated::new(
319 AuthenticationTokenRequest {
320 secret_key,
321 username,
322 password,
323 },
324 self.our_instance.clone(),
325 include_str!("example_keys/giterated.key").to_string(),
326 )
327 .unwrap();
328
329 self.send_message(&MessageKind::Authentication(
330 AuthenticationMessage::Request(AuthenticationRequest::AuthenticationToken(request)),
331 ))
332 .await?;
333
334 loop {
335 // while let Ok(payload) = Self::next_payload(&mut socket).await {
336 let payload = match self.next_payload().await {
337 Ok(payload) => payload,
338 Err(err) => {
339 error!("Error while fetching next payload: {:?}", err);
340 continue;
341 }
342 };
343
344 if let Ok(MessageKind::Authentication(AuthenticationMessage::Response(
345 AuthenticationResponse::AuthenticationToken(response),
346 ))) = serde_json::from_slice(&payload)
347 {
348 return Ok(response.token);
349 }
350 }
102 351 }
103 352
104 async fn connect_to(url: impl ToString) -> Result<Socket, Box<dyn Error>> {
105 let url = url.to_string();
106 let (mut websocket, _response) = connect_async(&format!("ws://{}/.giterated/daemon", url)).await?;
107 Self::handle_handshake(&mut websocket).await?;
353 /// Requests a new token for the given login.
354 ///
355 /// # Authorization
356 /// This request can only be sent to the same instance from which
357 /// it is issued.
358 pub async fn extend_token(
359 &mut self,
360 secret_key: String,
361 token: String,
362 ) -> Result<Option<String>, Box<dyn Error>> {
363 let request = InstanceAuthenticated::new(
364 TokenExtensionRequest { secret_key, token },
365 self.our_instance.clone(),
366 self.our_private_key.clone(),
367 )
368 .unwrap();
369
370 self.send_message(&MessageKind::Authentication(
371 AuthenticationMessage::Request(AuthenticationRequest::TokenExtension(request)),
372 ))
373 .await?;
374
375 while let Ok(payload) = self.next_payload().await {
376 if let Ok(MessageKind::Authentication(AuthenticationMessage::Response(
377 AuthenticationResponse::TokenExtension(response),
378 ))) = serde_json::from_slice(&payload)
379 {
380 return Ok(response.new_token);
381 }
382 }
383
384 todo!()
385 }
386
387 async fn connect_to(instance: Instance) -> Result<Socket, anyhow::Error> {
388 let url = &instance.url;
389 info!(
390 "Connecting to {}",
391 format!("wss://{}/.giterated/daemon/", url)
392 );
393 let (websocket, _response) =
394 connect_async(&format!("wss://{}/.giterated/daemon/", url)).await?;
395 info!("Connection established with {}", url);
108 396
109 397 Ok(websocket)
110 398 }
111 399
112 async fn handle_handshake(socket: &mut Socket) -> Result<(), Box<dyn Error>> {
400 async fn handle_handshake(&mut self) -> Result<(), anyhow::Error> {
113 401 // Send handshake initiation
114 402
115 Self::send_message(
116 &MessageKind::Handshake(HandshakeMessage::Initiate(InitiateHandshake {
117 identity: Instance {
118 url: String::from("foo.com"),
119 },
120 version: String::from("0.1.0"),
121 })),
122 socket,
123 )
403 self.send_message(&MessageKind::Handshake(HandshakeMessage::Initiate(
404 InitiateHandshake {
405 identity: self.our_instance.clone(),
406 version: version(),
407 },
408 )))
124 409 .await?;
125 410
126 while let Some(message) = socket.next().await {
411 while let Some(message) = self.connection.next().await {
127 412 let message = match message {
128 413 Ok(message) => message,
129 414 Err(err) => {
@@ -156,14 +441,25 @@ impl GiteratedApi {
156 441 if let MessageKind::Handshake(handshake) = message {
157 442 match handshake {
158 443 HandshakeMessage::Initiate(_) => unimplemented!(),
159 HandshakeMessage::Response(_) => {
444 HandshakeMessage::Response(response) => {
445
446 let message = if !validate_version(&response.version) {
447 error!(
448 "Version compatibility failure! Our Version: {}, Their Version: {}",
449 version(),
450 response.version
451 );
452
453 HandshakeFinalize { success: false }
454 } else {
455 info!("Connected with a compatible version");
456
457 HandshakeFinalize { success: true }
458 };
160 459 // Send HandshakeMessage::Finalize
161 Self::send_message(
162 &MessageKind::Handshake(HandshakeMessage::Finalize(
163 HandshakeFinalize { success: true },
164 )),
165 socket,
166 )
460 self.send_message(&MessageKind::Handshake(HandshakeMessage::Finalize(
461 message
462 )))
167 463 .await?;
168 464 }
169 465 HandshakeMessage::Finalize(finalize) => {
@@ -180,18 +476,15 @@ impl GiteratedApi {
180 476 Ok(())
181 477 }
182 478
183 async fn send_message<T: Serialize>(
184 message: &T,
185 socket: &mut Socket,
186 ) -> Result<(), Box<dyn Error>> {
187 socket
479 async fn send_message<T: Serialize>(&mut self, message: &T) -> Result<(), anyhow::Error> {
480 self.connection
188 481 .send(Message::Binary(serde_json::to_vec(&message).unwrap()))
189 482 .await?;
190 483 Ok(())
191 484 }
192 485
193 async fn next_payload(socket: &mut Socket) -> Result<Vec<u8>, Box<dyn Error>> {
194 while let Some(message) = socket.next().await {
486 async fn next_payload(&mut self) -> Result<Vec<u8>, Box<dyn Error>> {
487 while let Some(message) = self.connection.next().await {
195 488 let message = message?;
196 489
197 490 match message {

src/main.rs

View file
@@ -1,9 +1,17 @@
1 use std::collections::BTreeMap;
1 use std::{collections::BTreeMap, str::FromStr, time::SystemTime};
2 2
3 use giterated_api::GiteratedApi;
4 use giterated_daemon::model::{instance::Instance, repository::Repository};
5 use jsonwebtoken::{encode, EncodingKey, Algorithm};
6 use serde::{Serialize, Deserialize};
3 use chrono::{DateTime, NaiveDateTime, Utc};
4 use giterated_api::{GiteratedApi, GiteratedApiBuilder};
5 use giterated_daemon::{
6 messages::repository::CreateRepositoryRequest,
7 model::{
8 instance::Instance,
9 repository::{Repository, RepositoryVisibility},
10 user::User,
11 },
12 };
13 use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, TokenData, Validation};
14 use serde::{Deserialize, Serialize};
7 15 // use jwt::SignWithKey;
8 16
9 17 #[macro_use]
@@ -23,21 +31,113 @@ async fn main() {
23 31 // .await
24 32 // );
25 33
26 let encoding_key= EncodingKey::from_ec_pem(include_bytes!("example_keys/ec-private.pem")).unwrap();
34 // let encoding_key =
35 // EncodingKey::from_rsa_pem(include_bytes!("example_keys/giterated.key")).unwrap();
27 36
28 let claims = Claims {
29 instance: String::from("giterated.dev"),
30 username: String::from("ambee")
31 };
37 // let claims = UserTokenMetadata {
38 // user: User {
39 // username: String::from("ambee"),
40 // instance: Instance {
41 // url: String::from("giterated.dev"),
42 // },
43 // },
44 // generated_for: Instance {
45 // url: String::from("giterated.dev"),
46 // },
47 // exp: SystemTime::UNIX_EPOCH.elapsed().unwrap().as_secs(),
48 // };
49
50 // let token = encode(
51 // &jsonwebtoken::Header::new(Algorithm::RS256),
52 // &claims,
53 // &encoding_key,
54 // )
55 // .unwrap();
56
57 let mut api = GiteratedApiBuilder::from_local("giterated.dev")
58 .unwrap()
59 .private_key(include_str!("example_keys/giterated.key"))
60 .public_key(include_str!("example_keys/giterated.key"))
61 .build()
62 .await
63 .unwrap();
64
65 info!("Lets try to make an account!");
66
67 let response = api
68 .register(
69 String::from("ambee"),
70 None,
71 String::from("lolthisisinthecommithistory"),
72 )
73 .await;
32 74
33 let token = encode(&jsonwebtoken::Header::new(Algorithm::ES256), &claims, &encoding_key).unwrap();
75 info!("Registration response: {:?}", response);
76
77 let token = api
78 .authentication_token(
79 String::from("foobar"),
80 String::from("ambee"),
81 String::from("password"),
82 )
83 .await
84 .unwrap();
34 85
35 86 println!("Token: {}", token);
36 }
37 87
88 let public_key = api.public_key().await;
89
90 println!("Server public key:\n{}", public_key);
91 let verification_key = DecodingKey::from_rsa_pem(public_key.as_bytes()).unwrap();
92 let data: TokenData<UserTokenMetadata> = decode(
93 &token,
94 &verification_key,
95 &Validation::new(Algorithm::RS256),
96 )
97 .unwrap();
98
99 println!("The token was valid! Data:\n{:#?}", data.claims);
100
101 info!("Lets extend that token!");
102
103 let new_token = api
104 .extend_token(String::from("foobar"), token.clone())
105 .await
106 .unwrap();
107 info!("New Token Returned:\n{:?}", new_token);
108
109 info!("Try to create a repository? uwu");
110
111 let repository = api
112 .create_repository(
113 new_token.unwrap(),
114 String::from("super-repository"),
115 None,
116 RepositoryVisibility::Public,
117 String::from("master"),
118 User::from_str("ambee:giterated.dev").unwrap(),
119 )
120 .await
121 .unwrap();
122
123 assert!(repository);
124
125 info!("Lets view our repository!");
126
127 let view = api
128 .repository_info(
129 &token,
130 Repository::from_str("ambee:giterated.dev/[email protected]").unwrap(),
131 )
132 .await
133 .unwrap();
134
135 info!("Repository Info:\n{:#?}", view);
136 }
38 137
39 138 #[derive(Debug, Serialize, Deserialize)]
40 struct Claims {
41 username: String,
42 instance: String
43 }
43 \ No newline at end of file
139 struct UserTokenMetadata {
140 user: User,
141 generated_for: Instance,
142 exp: u64,
143 }