1mod access_mode;
2mod local_secret;
3mod share_token;
4
5pub use self::{
6 access_mode::AccessMode,
7 local_secret::{LocalSecret, SetLocalSecret},
8 share_token::ShareToken,
9};
10
11use crate::{
12 crypto::{cipher, sign},
13 error::Error,
14 protocol::RepositoryId,
15 Result,
16};
17use ouisync_macros::api;
18use rand::{rngs::OsRng, CryptoRng, Rng};
19use serde::{Deserialize, Deserializer, Serialize, Serializer};
20use std::{fmt, str::Utf8Error, string::FromUtf8Error, sync::Arc};
21use thiserror::Error;
22
23#[derive(Clone, Serialize, Deserialize)]
25pub enum AccessSecrets {
26 Blind {
27 id: RepositoryId,
28 },
29 Read {
30 id: RepositoryId,
31 read_key: cipher::SecretKey,
32 },
33 Write(WriteSecrets),
34}
35
36impl AccessSecrets {
37 pub fn generate_write<R: Rng + CryptoRng>(rng: &mut R) -> Self {
39 Self::Write(WriteSecrets::generate(rng))
40 }
41
42 pub fn random_write() -> Self {
44 Self::Write(WriteSecrets::random())
45 }
46
47 pub fn with_mode(&self, mode: AccessMode) -> Self {
50 match (self, mode) {
51 (Self::Blind { .. }, AccessMode::Blind | AccessMode::Read | AccessMode::Write)
52 | (Self::Read { .. }, AccessMode::Read | AccessMode::Write)
53 | (Self::Write { .. }, AccessMode::Write) => self.clone(),
54 (Self::Read { id, .. } | Self::Write(WriteSecrets { id, .. }), AccessMode::Blind) => {
55 Self::Blind { id: *id }
56 }
57 (Self::Write(WriteSecrets { id, read_key, .. }), AccessMode::Read) => Self::Read {
58 id: *id,
59 read_key: read_key.clone(),
60 },
61 }
62 }
63
64 pub fn access_mode(&self) -> AccessMode {
65 match self {
66 Self::Blind { .. } => AccessMode::Blind,
67 Self::Read { .. } => AccessMode::Read,
68 Self::Write(_) => AccessMode::Write,
69 }
70 }
71
72 pub fn id(&self) -> &RepositoryId {
73 match self {
74 Self::Blind { id } | Self::Read { id, .. } | Self::Write(WriteSecrets { id, .. }) => id,
75 }
76 }
77
78 pub fn can_write(&self) -> bool {
79 matches!(self, Self::Write(_))
80 }
81
82 pub fn can_read(&self) -> bool {
83 matches!(self, Self::Read { .. } | Self::Write(_))
84 }
85
86 pub fn read_key(&self) -> Option<&cipher::SecretKey> {
87 match self {
88 Self::Blind { .. } => None,
89 Self::Read { read_key, .. } => Some(read_key),
90 Self::Write(secrets) => Some(&secrets.read_key),
91 }
92 }
93
94 pub fn write_secrets(&self) -> Option<&WriteSecrets> {
95 match self {
96 Self::Blind { .. } => None,
97 Self::Read { .. } => None,
98 Self::Write(secrets) => Some(secrets),
99 }
100 }
101
102 pub fn into_write_secrets(self) -> Option<WriteSecrets> {
103 match self {
104 Self::Blind { .. } => None,
105 Self::Read { .. } => None,
106 Self::Write(secrets) => Some(secrets),
107 }
108 }
109
110 pub(crate) fn keys(&self) -> Option<AccessKeys> {
111 match self {
112 Self::Blind { .. } => None,
113 Self::Read { read_key, .. } => Some(AccessKeys {
114 read: read_key.clone(),
115 write: None,
116 }),
117 Self::Write(secrets) => Some(AccessKeys {
118 read: secrets.read_key.clone(),
119 write: Some(secrets.write_keys.clone()),
120 }),
121 }
122 }
123}
124
125impl fmt::Debug for AccessSecrets {
126 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127 match self {
128 Self::Blind { .. } => f.debug_struct("Blind").finish_non_exhaustive(),
129 Self::Read { .. } => f.debug_struct("Read").finish_non_exhaustive(),
130 Self::Write { .. } => f.debug_struct("Write").finish_non_exhaustive(),
131 }
132 }
133}
134
135impl PartialEq for AccessSecrets {
136 fn eq(&self, other: &Self) -> bool {
137 self.access_mode() == other.access_mode() && self.id() == other.id()
138 }
139}
140
141impl Eq for AccessSecrets {}
142
143#[derive(Clone)]
145pub struct WriteSecrets {
146 pub id: RepositoryId,
147 pub read_key: cipher::SecretKey,
148 pub write_keys: Arc<sign::Keypair>,
149}
150
151impl WriteSecrets {
152 pub fn generate<R: Rng + CryptoRng>(rng: &mut R) -> Self {
154 Self::from(sign::Keypair::generate(rng))
155 }
156
157 pub fn random() -> Self {
159 Self::generate(&mut OsRng)
160 }
161}
162
163impl PartialEq for WriteSecrets {
164 fn eq(&self, other: &Self) -> bool {
165 self.id == other.id
166 }
167}
168
169impl Eq for WriteSecrets {}
170
171impl From<sign::Keypair> for WriteSecrets {
172 fn from(keys: sign::Keypair) -> Self {
173 let id = keys.public_key().into();
174 let read_key = derive_read_key_from_write_keys(&keys);
175
176 Self {
177 id,
178 read_key,
179 write_keys: Arc::new(keys),
180 }
181 }
182}
183
184impl Serialize for WriteSecrets {
185 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
186 where
187 S: Serializer,
188 {
189 self.write_keys.serialize(s)
191 }
192}
193
194impl<'de> Deserialize<'de> for WriteSecrets {
195 fn deserialize<D>(d: D) -> Result<Self, D::Error>
196 where
197 D: Deserializer<'de>,
198 {
199 Ok(Self::from(sign::Keypair::deserialize(d)?))
200 }
201}
202
203#[derive(Clone)]
205pub(crate) struct AccessKeys {
206 read: cipher::SecretKey,
207 write: Option<Arc<sign::Keypair>>,
208}
209
210impl AccessKeys {
211 pub fn read(&self) -> &cipher::SecretKey {
212 &self.read
213 }
214
215 pub fn write(&self) -> Option<&sign::Keypair> {
216 self.write.as_deref()
217 }
218
219 pub fn read_only(self) -> Self {
220 Self {
221 read: self.read,
222 write: None,
223 }
224 }
225}
226
227impl From<WriteSecrets> for AccessKeys {
228 fn from(secrets: WriteSecrets) -> Self {
229 Self {
230 read: secrets.read_key,
231 write: Some(secrets.write_keys),
232 }
233 }
234}
235
236fn derive_read_key_from_write_keys(write_keys: &sign::Keypair) -> cipher::SecretKey {
237 cipher::SecretKey::derive_from_key(&write_keys.to_bytes(), b"ouisync repository read key")
238}
239
240#[derive(Debug, Error)]
241#[error("decode error")]
242pub struct DecodeError;
243
244impl From<base64::DecodeError> for DecodeError {
245 fn from(_: base64::DecodeError) -> Self {
246 Self
247 }
248}
249
250impl From<bincode::Error> for DecodeError {
251 fn from(_: bincode::Error) -> Self {
252 Self
253 }
254}
255
256impl From<FromUtf8Error> for DecodeError {
257 fn from(_: FromUtf8Error) -> Self {
258 Self
259 }
260}
261
262impl From<Utf8Error> for DecodeError {
263 fn from(_: Utf8Error) -> Self {
264 Self
265 }
266}
267
268impl From<sign::SignatureError> for DecodeError {
269 fn from(_: sign::SignatureError) -> Self {
270 Self
271 }
272}
273
274impl From<cipher::SecretKeyLengthError> for DecodeError {
275 fn from(_: cipher::SecretKeyLengthError) -> Self {
276 Self
277 }
278}
279
280impl From<DecodeError> for Error {
281 fn from(_: DecodeError) -> Self {
282 Self::MalformedData
283 }
284}
285
286pub enum Access {
287 Blind {
289 id: RepositoryId,
290 },
291 ReadUnlocked {
293 id: RepositoryId,
294 read_key: cipher::SecretKey,
295 },
296 ReadLocked {
298 id: RepositoryId,
299 local_secret: SetLocalSecret,
300 read_key: cipher::SecretKey,
301 },
302 WriteUnlocked {
304 secrets: WriteSecrets,
305 },
306 WriteLocked {
309 local_read_secret: SetLocalSecret,
310 local_write_secret: SetLocalSecret,
311 secrets: WriteSecrets,
312 },
313 WriteLockedReadUnlocked {
315 local_write_secret: SetLocalSecret,
316 secrets: WriteSecrets,
317 },
318}
319
320impl Access {
321 pub fn new(
322 local_read_secret: Option<SetLocalSecret>,
323 local_write_secret: Option<SetLocalSecret>,
324 secrets: AccessSecrets,
325 ) -> Self {
326 match (local_read_secret, local_write_secret, secrets) {
327 (_, _, AccessSecrets::Blind { id }) => Access::Blind { id },
328 (None, _, AccessSecrets::Read { id, read_key }) => {
329 Access::ReadUnlocked { id, read_key }
330 }
331 (Some(local_read_secret), _, AccessSecrets::Read { id, read_key }) => {
332 Access::ReadLocked {
333 id,
334 local_secret: local_read_secret,
335 read_key,
336 }
337 }
338 (None, None, AccessSecrets::Write(secrets)) => Access::WriteUnlocked { secrets },
339 (Some(local_read_secret), None, AccessSecrets::Write(secrets)) => Access::ReadLocked {
340 id: secrets.id,
341 local_secret: local_read_secret,
342 read_key: secrets.read_key,
343 },
344 (None, Some(local_write_secret), AccessSecrets::Write(secrets)) => {
345 Access::WriteLockedReadUnlocked {
346 local_write_secret,
347 secrets,
348 }
349 }
350 (Some(local_read_secret), Some(local_write_secret), AccessSecrets::Write(secrets)) => {
351 Access::WriteLocked {
352 local_read_secret,
353 local_write_secret,
354 secrets,
355 }
356 }
357 }
358 }
359
360 pub fn id(&self) -> &RepositoryId {
361 match self {
362 Self::Blind { id } => id,
363 Self::ReadUnlocked { id, .. } => id,
364 Self::ReadLocked { id, .. } => id,
365 Self::WriteUnlocked { secrets } => &secrets.id,
366 Self::WriteLocked { secrets, .. } => &secrets.id,
367 Self::WriteLockedReadUnlocked { secrets, .. } => &secrets.id,
368 }
369 }
370
371 pub fn secrets(self) -> AccessSecrets {
372 match self {
373 Self::Blind { id } => AccessSecrets::Blind { id },
374 Self::ReadUnlocked { id, read_key } => AccessSecrets::Read { id, read_key },
375 Self::ReadLocked { id, read_key, .. } => AccessSecrets::Read { id, read_key },
376 Self::WriteUnlocked { secrets } => AccessSecrets::Write(secrets),
377 Self::WriteLocked { secrets, .. } => AccessSecrets::Write(secrets),
378 Self::WriteLockedReadUnlocked { secrets, .. } => AccessSecrets::Write(secrets),
379 }
380 }
381
382 pub fn local_write_secret(&self) -> Option<&SetLocalSecret> {
383 match self {
384 Self::WriteLocked {
385 local_write_secret, ..
386 } => Some(local_write_secret),
387 Self::WriteLockedReadUnlocked {
388 local_write_secret, ..
389 } => Some(local_write_secret),
390 _ => None,
391 }
392 }
393
394 #[cfg(test)]
395 pub fn highest_local_secret(&self) -> Option<&SetLocalSecret> {
396 match self {
397 Self::Blind { .. } => None,
398 Self::ReadUnlocked { .. } => None,
399 Self::ReadLocked { local_secret, .. } => Some(local_secret),
400 Self::WriteUnlocked { .. } => None,
401 Self::WriteLocked {
402 local_write_secret, ..
403 } => Some(local_write_secret),
404 Self::WriteLockedReadUnlocked {
405 local_write_secret, ..
406 } => Some(local_write_secret),
407 }
408 }
409}
410
411#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
413#[api]
414pub enum AccessChange {
415 Enable(Option<SetLocalSecret>),
417
418 Disable,
420}
421
422#[cfg(test)]
423mod tests {
424 use crate::crypto::PasswordSalt;
425
426 use super::*;
427
428 #[test]
431 fn access_change_serialize_deserialize_json() {
432 for (orig, expected_serialized) in [
433 (
434 AccessChange::Enable(Some(SetLocalSecret::Password("mellon".to_string().into()))),
435 "{\"Enable\":{\"Password\":\"mellon\"}}",
436 ),
437 (AccessChange::Enable(None), "{\"Enable\":null}"),
438 (AccessChange::Disable, "\"Disable\""),
439 ] {
440 let serialized = serde_json::to_string(&orig).unwrap();
441 assert_eq!(serialized, expected_serialized);
442
443 let deserialized: AccessChange = serde_json::from_str(&serialized).unwrap();
444 assert_eq!(deserialized, orig);
445 }
446 }
447
448 #[ignore]
451 #[test]
452 fn access_change_key_serialize_deserialize_json() {
453 let key = cipher::SecretKey::random();
454 let salt = PasswordSalt::random();
455 let key_serialized = serde_json::to_string(&key).unwrap();
456 let salt_serialized = serde_json::to_string(&salt).unwrap();
457
458 let orig = AccessChange::Enable(Some(SetLocalSecret::KeyAndSalt { key, salt }));
459
460 let expected_serialized = format!(
461 "{{\"enable\":{{\"key_and_salt\":{{\"key\":{}, \"salt\":{}}}}}}}",
462 key_serialized, salt_serialized
463 );
464
465 let serialized = serde_json::to_string(&orig).unwrap();
466 assert_eq!(serialized, expected_serialized);
467
468 let deserialized: AccessChange = serde_json::from_str(&serialized).unwrap();
469 assert_eq!(deserialized, orig);
470 }
471
472 #[test]
473 fn access_change_serialize_deserialize_msgpack() {
474 for (orig, expected_serialized_hex) in [
475 (
476 AccessChange::Enable(Some(SetLocalSecret::Password("mellon".to_string().into()))),
477 "81a6456e61626c6581a850617373776f7264a66d656c6c6f6e",
478 ),
479 (AccessChange::Enable(None), "81a6456e61626c65c0"),
480 (AccessChange::Disable, "a744697361626c65"),
481 ] {
482 let serialized = rmp_serde::to_vec(&orig).unwrap();
483 assert_eq!(hex::encode(&serialized), expected_serialized_hex);
484
485 let deserialized: AccessChange = rmp_serde::from_slice(&serialized).unwrap();
486 assert_eq!(deserialized, orig);
487 }
488 }
489
490 #[test]
491 fn access_change_key_serialize_deserialize_msgpack() {
492 let key = cipher::SecretKey::random();
493 let salt = PasswordSalt::random();
494
495 let orig = AccessChange::Enable(Some(SetLocalSecret::KeyAndSalt { key, salt }));
496 let serialized = rmp_serde::to_vec(&orig).unwrap();
497 let deserialized: AccessChange = rmp_serde::from_slice(&serialized).unwrap();
498 assert_eq!(deserialized, orig);
499 }
500}