1#![allow(clippy::disallowed_macros)] use core::{error, fmt, hash::Hash, time::Duration};
4
5pub use aranya_crypto::tls::CipherSuiteId;
6use aranya_crypto::{
7 Engine,
8 dangerous::spideroak_crypto::hex::Hex,
9 default::DefaultEngine,
10 id::IdError,
11 subtle::{Choice, ConstantTimeEq},
12 zeroize::{Zeroize, ZeroizeOnDrop},
13};
14use aranya_id::custom_id;
15pub use aranya_policy_text::{InvalidText, Text, text};
16use aranya_util::{Addr, error::ReportExt};
17use buggy::Bug;
18pub use semver::Version;
19use serde::{Deserialize, Serialize};
20
21pub mod afc;
22
23#[cfg(feature = "afc")]
24pub use self::afc::*;
25
26pub type CE = DefaultEngine;
28pub type CS = <DefaultEngine as Engine>::CS;
30
31#[derive(Serialize, Deserialize, Debug)]
34pub enum Error {
35 DoesNotExist(String),
37 Other(String),
39}
40
41impl Error {
42 pub fn from_msg(err: &str) -> Self {
43 Self::Other(err.into())
44 }
45
46 pub fn from_err<E: error::Error>(err: E) -> Self {
47 Self::Other(ReportExt::report(&err).to_string())
48 }
49}
50
51impl From<Bug> for Error {
52 fn from(err: Bug) -> Self {
53 Self::from_err(err)
54 }
55}
56
57impl From<anyhow::Error> for Error {
58 fn from(err: anyhow::Error) -> Self {
59 Self::Other(format!("{err:?}"))
60 }
61}
62
63impl From<InvalidText> for Error {
64 fn from(err: InvalidText) -> Self {
65 Self::Other(format!("{err:?}"))
66 }
67}
68
69impl From<semver::Error> for Error {
70 fn from(err: semver::Error) -> Self {
71 Self::from_err(err)
72 }
73}
74
75impl From<IdError> for Error {
76 fn from(err: IdError) -> Self {
77 Self::from_err(err)
78 }
79}
80
81impl fmt::Display for Error {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 match self {
84 Self::DoesNotExist(msg) | Self::Other(msg) => msg.fmt(f),
85 }
86 }
87}
88
89impl error::Error for Error {}
90
91pub type Result<T, E = Error> = core::result::Result<T, E>;
92
93custom_id! {
94 pub struct DeviceId;
96}
97
98custom_id! {
99 pub struct TeamId;
101}
102
103custom_id! {
104 pub struct LabelId;
106}
107
108custom_id! {
109 pub struct RoleId;
111}
112
113custom_id! {
114 pub struct ObjectId;
116}
117
118#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
122pub struct Rank(i64);
123
124impl Rank {
125 pub const fn new(value: i64) -> Self {
127 Self(value)
128 }
129
130 pub const fn value(self) -> i64 {
132 self.0
133 }
134}
135
136impl fmt::Display for Rank {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 self.0.fmt(f)
139 }
140}
141
142impl From<i64> for Rank {
143 fn from(value: i64) -> Self {
144 Self::new(value)
145 }
146}
147
148#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
149pub struct Role {
150 pub id: RoleId,
152 pub name: Text,
154 pub author_id: DeviceId,
156 pub default: bool,
158}
159
160#[derive(Clone, Serialize, Deserialize, Eq, PartialEq)]
162pub struct PublicKeyBundle {
163 pub identity: Vec<u8>,
164 pub signing: Vec<u8>,
165 pub encryption: Vec<u8>,
166}
167
168impl fmt::Debug for PublicKeyBundle {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 f.debug_struct("PublicKeyBundle")
171 .field("identity", &Hex::new(&*self.identity))
172 .field("signing", &Hex::new(&*self.signing))
173 .field("encryption", &Hex::new(&*self.encryption))
174 .finish()
175 }
176}
177
178#[derive(Debug, Serialize, Deserialize)]
181pub struct AddTeamConfig {
182 pub team_id: TeamId,
183}
184
185#[derive(Debug, Serialize, Deserialize)]
188pub struct CreateTeamConfig {}
189
190#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
192pub struct Label {
193 pub id: LabelId,
194 pub name: Text,
195 pub author_id: DeviceId,
196}
197
198#[derive(Clone, Serialize, Deserialize)]
200pub struct Secret(Box<[u8]>);
201
202impl Secret {
203 #[inline]
205 pub fn raw_secret_bytes(&self) -> &[u8] {
206 &self.0
207 }
208}
209
210impl<T> From<T> for Secret
211where
212 T: Into<Box<[u8]>>,
213{
214 fn from(value: T) -> Self {
215 Self(value.into())
216 }
217}
218
219impl ConstantTimeEq for Secret {
220 fn ct_eq(&self, other: &Self) -> Choice {
221 self.0.ct_eq(&other.0)
222 }
223}
224
225impl ZeroizeOnDrop for Secret {}
226impl Drop for Secret {
227 fn drop(&mut self) {
228 self.0.zeroize()
229 }
230}
231
232impl fmt::Debug for Secret {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 f.debug_struct("Secret").finish_non_exhaustive()
235 }
236}
237
238#[derive(Clone, Debug, Serialize, Deserialize)]
240pub struct SyncPeerConfig {
241 pub interval: Option<Duration>,
243 pub sync_now: bool,
245 #[cfg(feature = "preview")]
248 pub sync_on_hello: bool,
249}
250
251#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
253pub enum ChanOp {
254 RecvOnly,
257 SendOnly,
260 SendRecv,
263}
264
265#[non_exhaustive]
283#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
284pub enum Perm {
285 AddDevice,
289 RemoveDevice,
291 TerminateTeam,
293
294 ChangeRank,
298
299 CreateRole,
303 DeleteRole,
305 AssignRole,
307 RevokeRole,
309 ChangeRolePerms,
311 SetupDefaultRole,
313
314 CreateLabel,
318 DeleteLabel,
320 AssignLabel,
322 RevokeLabel,
324
325 CanUseAfc,
329 CreateAfcUniChannel,
331}
332
333#[cfg(not(feature = "afc"))]
335use afc_stub::{AfcReceiveChannelInfo, AfcSendChannelInfo, AfcShmInfo};
336#[cfg(not(feature = "afc"))]
337mod afc_stub {
338 #[derive(Debug, serde::Serialize, serde::Deserialize)]
339 pub enum Never {}
340 pub type AfcShmInfo = Never;
341 pub type AfcSendChannelInfo = Never;
342 pub type AfcReceiveChannelInfo = Never;
343}
344
345#[tarpc::service]
346pub trait DaemonApi {
347 async fn version() -> Result<Version>;
353 async fn aranya_local_addr() -> Result<Addr>;
355
356 async fn get_public_key_bundle() -> Result<PublicKeyBundle>;
358 async fn get_device_id() -> Result<DeviceId>;
360 #[cfg(feature = "test-utils")]
364 async fn test_trace_id() -> Result<String>;
365
366 async fn add_sync_peer(addr: Addr, team: TeamId, config: SyncPeerConfig) -> Result<()>;
372 async fn sync_now(addr: Addr, team: TeamId, cfg: Option<SyncPeerConfig>) -> Result<()>;
374
375 #[cfg(feature = "preview")]
377 async fn sync_hello_subscribe(
378 peer: Addr,
379 team: TeamId,
380 graph_change_debounce: Duration,
381 duration: Duration,
382 schedule_delay: Duration,
383 ) -> Result<()>;
384
385 #[cfg(feature = "preview")]
387 async fn sync_hello_unsubscribe(peer: Addr, team: TeamId) -> Result<()>;
388
389 async fn remove_sync_peer(addr: Addr, team: TeamId) -> Result<()>;
391 async fn add_team(cfg: AddTeamConfig) -> Result<()>;
393
394 async fn remove_team(team: TeamId) -> Result<()>;
396
397 async fn create_team(cfg: CreateTeamConfig) -> Result<TeamId>;
399 async fn close_team(team: TeamId) -> Result<()>;
401
402 async fn add_device_to_team(
409 team: TeamId,
410 keys: PublicKeyBundle,
411 initial_role: Option<RoleId>,
412 rank: Rank,
413 ) -> Result<()>;
414 async fn remove_device_from_team(team: TeamId, device: DeviceId) -> Result<()>;
416 async fn devices_on_team(team: TeamId) -> Result<Box<[DeviceId]>>;
418 async fn device_public_key_bundle(team: TeamId, device: DeviceId) -> Result<PublicKeyBundle>;
420
421 async fn setup_default_roles(team: TeamId) -> Result<Box<[Role]>>;
429 async fn create_role(team: TeamId, role_name: Text, rank: Rank) -> Result<Role>;
431 async fn delete_role(team: TeamId, role_id: RoleId) -> Result<()>;
433 async fn team_roles(team: TeamId) -> Result<Box<[Role]>>;
435
436 async fn add_perm_to_role(team: TeamId, role: RoleId, perm: Perm) -> Result<()>;
442 async fn remove_perm_from_role(team: TeamId, role: RoleId, perm: Perm) -> Result<()>;
444 async fn query_role_perms(team: TeamId, role: RoleId) -> Result<Vec<Perm>>;
446 async fn change_rank(
454 team: TeamId,
455 object_id: ObjectId,
456 old_rank: Rank,
457 new_rank: Rank,
458 ) -> Result<()>;
459 async fn query_rank(team: TeamId, object_id: ObjectId) -> Result<Rank>;
461
462 #[cfg(feature = "test-utils")]
464 #[cfg_attr(docsrs, doc(cfg(feature = "test-utils")))]
465 async fn query_device_generation(team: TeamId, device_id: DeviceId) -> Result<Option<i64>>;
466
467 async fn assign_role(team: TeamId, device: DeviceId, role: RoleId) -> Result<()>;
473 async fn revoke_role(team: TeamId, device: DeviceId, role: RoleId) -> Result<()>;
475 async fn change_role(
477 team: TeamId,
478 device: DeviceId,
479 old_role: RoleId,
480 new_role: RoleId,
481 ) -> Result<()>;
482 async fn device_role(team: TeamId, device: DeviceId) -> Result<Option<Role>>;
484
485 async fn create_label(team: TeamId, name: Text, rank: Rank) -> Result<LabelId>;
491 async fn delete_label(team: TeamId, label_id: LabelId) -> Result<()>;
493 async fn label(team: TeamId, label: LabelId) -> Result<Label>;
495 async fn labels(team: TeamId) -> Result<Vec<Label>>;
497
498 async fn assign_label_to_device(
504 team: TeamId,
505 device: DeviceId,
506 label: LabelId,
507 op: ChanOp,
508 ) -> Result<()>;
509 async fn revoke_label_from_device(team: TeamId, device: DeviceId, label: LabelId)
511 -> Result<()>;
512 async fn labels_assigned_to_device(team: TeamId, device: DeviceId) -> Result<Box<[Label]>>;
514
515 #[cfg(feature = "afc")]
517 #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
518 async fn afc_shm_info() -> Result<AfcShmInfo>;
519 #[cfg(feature = "afc")]
521 #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
522 async fn create_afc_channel(
523 team: TeamId,
524 peer_id: DeviceId,
525 label_id: LabelId,
526 ) -> Result<AfcSendChannelInfo>;
527 #[cfg(feature = "afc")]
529 #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
530 async fn delete_afc_channel(chan: AfcLocalChannelId) -> Result<()>;
531 #[cfg(feature = "afc")]
533 #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
534 async fn accept_afc_channel(team: TeamId, ctrl: AfcCtrl) -> Result<AfcReceiveChannelInfo>;
535}