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

ambee/giterated

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

Add authentication operations

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨c27b4f3

⁨giterated-daemon/src/database_backend/mod.rs⁩ - ⁨12781⁩ bytes
Raw
1 pub mod handler;
2
3 use std::sync::Arc;
4
5 use giterated_models::error::OperationError;
6 use giterated_models::instance::Instance;
7 use giterated_models::object::{GiteratedObject, Object, ObjectRequestError};
8 use giterated_models::object_backend::ObjectBackend;
9 use giterated_models::operation::GiteratedOperation;
10 use giterated_models::repository::Repository;
11 use giterated_models::user::User;
12 use giterated_stack::handler::GiteratedBackend;
13 use giterated_stack::{OperationHandlers, StackOperationState};
14 use std::fmt::Debug;
15 use tokio::sync::Mutex;
16
17 use crate::backend::{RepositoryBackend, UserBackend};
18
19 use self::handler::{
20 instance_authentication_request, instance_registration_request, repository_commit_before,
21 repository_diff, repository_file_from_id, repository_get_setting, repository_get_value,
22 repository_info, repository_set_setting, user_get_repositories, user_get_setting,
23 user_get_value, user_set_setting,
24 };
25
26 #[derive(Clone, Debug)]
27 pub struct Foobackend {}
28
29 #[async_trait::async_trait]
30 impl ObjectBackend<StackOperationState> for Foobackend {
31 async fn object_operation<O: GiteratedObject + Debug, D: GiteratedOperation<O> + Debug>(
32 &self,
33 _object: O,
34 _operation: &str,
35 _payload: D,
36 _operation_state: &StackOperationState,
37 ) -> Result<D::Success, OperationError<D::Failure>> {
38 // We don't handle operations with this backend
39 Err(OperationError::Unhandled)
40 }
41
42 async fn get_object<O: GiteratedObject + Debug>(
43 &self,
44 _object_str: &str,
45 _operation_state: &StackOperationState,
46 ) -> Result<Object<StackOperationState, O, Self>, OperationError<ObjectRequestError>> {
47 Err(OperationError::Unhandled)
48 }
49 }
50
51 /// A backend implementation which attempts to resolve data from the instance's database.
52 #[derive(Clone)]
53 pub struct DatabaseBackend {
54 pub(self) our_instance: Instance,
55 pub(self) user_backend: Arc<Mutex<dyn UserBackend + Send>>,
56 pub(self) repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>,
57 }
58
59 impl DatabaseBackend {
60 pub fn new(
61 instance: Instance,
62 user_backend: Arc<Mutex<dyn UserBackend + Send>>,
63 repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>,
64 ) -> Self {
65 Self {
66 our_instance: instance,
67 user_backend,
68 repository_backend,
69 }
70 }
71
72 pub fn into_backend(&self) -> GiteratedBackend<Self> {
73 let mut handlers = OperationHandlers::default();
74
75 handlers
76 .insert(user_get_repositories)
77 .insert(user_get_value)
78 .insert(user_get_setting)
79 .insert(user_set_setting)
80 .insert(repository_info)
81 .insert(repository_file_from_id)
82 .insert(repository_diff)
83 .insert(repository_commit_before)
84 .insert(repository_get_value)
85 .insert(repository_get_setting)
86 .insert(repository_set_setting)
87 .insert(instance_registration_request)
88 .insert(instance_authentication_request)
89 .register_object::<Instance>()
90 .register_object::<Repository>()
91 .register_object::<User>();
92
93 GiteratedBackend::new(self.clone(), handlers)
94 }
95 }
96
97 impl Debug for DatabaseBackend {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 f.debug_struct("DatabaseBackend").finish()
100 }
101 }
102
103 // TODO: These should be on the stack
104 // These tests verify that the essential handling of the database backend is
105 // functional and correct.
106 #[cfg(test)]
107 mod test {
108 use std::{str::FromStr, sync::Arc};
109
110 use anyhow::Error;
111
112 use giterated_models::authenticated::UserAuthenticationToken;
113
114 use giterated_models::instance::{
115 AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest,
116 };
117
118 use giterated_models::object_backend::ObjectBackend;
119
120 use giterated_models::repository::{
121 Commit, Description, Repository, RepositoryCommitBeforeRequest, RepositoryDiff,
122 RepositoryDiffRequest, RepositoryFile, RepositoryFileFromIdRequest,
123 RepositoryFileInspectRequest, RepositorySummary, RepositoryTreeEntry,
124 };
125 use giterated_models::settings::AnySetting;
126 use giterated_models::user::{DisplayName, User};
127 use giterated_models::value::{AnyValue, GiteratedObjectValue};
128 use giterated_stack::handler::GiteratedBackend;
129 use giterated_stack::StackOperationState;
130 use serde_json::Value;
131 use tokio::sync::Mutex;
132
133 use crate::backend::{git::GitBackendError, AuthBackend, RepositoryBackend, UserBackend};
134
135 use super::DatabaseBackend;
136 pub struct TestUserDatabaseBackend;
137
138 #[async_trait::async_trait]
139 impl UserBackend for TestUserDatabaseBackend {
140 async fn get_value(&mut self, _user: &User, name: &str) -> Result<AnyValue<User>, Error> {
141 assert_eq!(name, DisplayName::value_name());
142
143 Ok(serde_json::from_slice(
144 &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(),
145 )
146 .unwrap())
147 }
148 async fn get_setting(&mut self, _user: &User, _name: &str) -> Result<AnySetting, Error> {
149 Ok(serde_json::from_slice(
150 &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(),
151 )
152 .unwrap())
153 }
154 async fn write_setting(
155 &mut self,
156 _user: &User,
157 _name: &str,
158 _setting: &Value,
159 ) -> Result<(), Error> {
160 Ok(())
161 }
162 async fn exists(&mut self, user: &User) -> Result<bool, Error> {
163 Ok(user == &User::from_str("test_user:test.giterated.dev").unwrap())
164 }
165 async fn repositories_for_user(
166 &mut self,
167 _requester: Option<&User>,
168 _user: &User,
169 ) -> Result<Vec<RepositorySummary>, Error> {
170 todo!()
171 }
172 }
173
174 #[async_trait::async_trait]
175 impl AuthBackend for TestUserDatabaseBackend {
176 async fn register(
177 &mut self,
178 _request: RegisterAccountRequest,
179 ) -> Result<UserAuthenticationToken, Error> {
180 todo!()
181 }
182
183 async fn login(
184 &mut self,
185 _source: &Instance,
186 _request: AuthenticationTokenRequest,
187 ) -> Result<UserAuthenticationToken, Error> {
188 todo!()
189 }
190 }
191
192 pub struct TestUserRepositoryBackend;
193
194 #[async_trait::async_trait]
195 impl RepositoryBackend for TestUserRepositoryBackend {
196 async fn create_repository(
197 &mut self,
198 _user: &User,
199 _request: &RepositoryCreateRequest,
200 ) -> Result<Repository, GitBackendError> {
201 todo!()
202 }
203 async fn repository_file_inspect(
204 &mut self,
205 _requester: Option<&User>,
206 _repository: &Repository,
207 _request: &RepositoryFileInspectRequest,
208 ) -> Result<Vec<RepositoryTreeEntry>, Error> {
209 todo!()
210 }
211 async fn repository_file_from_id(
212 &mut self,
213 _requester: Option<&User>,
214 _repository: &Repository,
215 _request: &RepositoryFileFromIdRequest,
216 ) -> Result<RepositoryFile, Error> {
217 todo!()
218 }
219 async fn repository_diff(
220 &mut self,
221 _requester: Option<&User>,
222 _repository: &Repository,
223 _request: &RepositoryDiffRequest,
224 ) -> Result<RepositoryDiff, Error> {
225 todo!()
226 }
227 async fn repository_commit_before(
228 &mut self,
229 _requester: Option<&User>,
230 _repository: &Repository,
231 _request: &RepositoryCommitBeforeRequest,
232 ) -> Result<Commit, Error> {
233 todo!()
234 }
235 async fn get_value(
236 &mut self,
237 _repository: &Repository,
238 _name: &str,
239 ) -> Result<AnyValue<Repository>, Error> {
240 Ok(serde_json::from_slice(
241 &serde_json::to_vec(&Description(String::from("test"))).unwrap(),
242 )
243 .unwrap())
244 }
245 async fn get_setting(
246 &mut self,
247 _repository: &Repository,
248 _name: &str,
249 ) -> Result<AnySetting, Error> {
250 Ok(serde_json::from_slice(
251 &serde_json::to_vec(&Description(String::from("test"))).unwrap(),
252 )
253 .unwrap())
254 }
255 async fn write_setting(
256 &mut self,
257 _repository: &Repository,
258 _name: &str,
259 _setting: &Value,
260 ) -> Result<(), Error> {
261 Ok(())
262 }
263
264 async fn exists(&mut self, repository: &Repository) -> Result<bool, Error> {
265 // Ok(true)
266 Ok(repository
267 == &Repository::from_str(
268 "test_user:test.giterated.dev/[email protected]",
269 )
270 .unwrap())
271 }
272 }
273
274 fn test_backend() -> GiteratedBackend<DatabaseBackend> {
275 DatabaseBackend {
276 our_instance: Instance::from_str("testing.giterated.dev").unwrap(),
277 user_backend: Arc::new(Mutex::new(TestUserDatabaseBackend)) as _,
278 repository_backend: Arc::new(Mutex::new(TestUserRepositoryBackend)) as _,
279 }
280 .into_backend()
281 }
282
283 fn operation_state() -> StackOperationState {
284 todo!()
285 }
286
287 #[tokio::test]
288 async fn test_user_get() {
289 let backend = test_backend();
290 let operation_state = operation_state();
291
292 let mut user = backend
293 .get_object::<User>("test_user:test.giterated.dev", &operation_state)
294 .await
295 .expect("object should have been returned");
296
297 user.get::<DisplayName>(&operation_state)
298 .await
299 .expect("object value should have been returned");
300 }
301
302 #[tokio::test]
303 async fn test_user_get_setting() {
304 let backend = test_backend();
305 let operation_state = operation_state();
306
307 let mut user = backend
308 .get_object::<User>("test_user:test.giterated.dev", &operation_state)
309 .await
310 .expect("object should have been returned");
311
312 user.get_setting::<DisplayName>(&operation_state)
313 .await
314 .expect("object value should have been returned");
315 }
316
317 #[tokio::test]
318 async fn test_user_set_setting() {
319 let backend = test_backend();
320 let operation_state = operation_state();
321
322 let mut user = backend
323 .get_object::<User>("test_user:test.giterated.dev", &operation_state)
324 .await
325 .expect("object should have been returned");
326
327 user.set_setting::<DisplayName>(DisplayName(String::from("test")), &operation_state)
328 .await
329 .expect("object value should have been returned");
330 }
331
332 #[tokio::test]
333 async fn test_respository_get() {
334 let backend = test_backend();
335 let operation_state = operation_state();
336
337 let mut repository = backend
338 .get_object::<Repository>(
339 "test_user:test.giterated.dev/[email protected]",
340 &operation_state,
341 )
342 .await
343 .expect("object should have been returned");
344
345 repository
346 .get::<Description>(&operation_state)
347 .await
348 .expect("object value should have been returned");
349 }
350
351 #[tokio::test]
352 async fn test_repository_get_setting() {
353 let backend = test_backend();
354 let operation_state = operation_state();
355
356 let mut repository = backend
357 .get_object::<Repository>(
358 "test_user:test.giterated.dev/[email protected]",
359 &operation_state,
360 )
361 .await
362 .expect("object should have been returned");
363
364 repository
365 .get_setting::<Description>(&operation_state)
366 .await
367 .expect("object value should have been returned");
368 }
369
370 #[tokio::test]
371 async fn test_repository_set_setting() {
372 let backend = test_backend();
373 let operation_state = operation_state();
374
375 let mut repository = backend
376 .get_object::<Repository>(
377 "test_user:test.giterated.dev/[email protected]",
378 &operation_state,
379 )
380 .await
381 .expect("object should have been returned");
382
383 repository
384 .set_setting::<Description>(Description(String::from("test")), &operation_state)
385 .await
386 .expect("object value should have been returned");
387 }
388 }
389