1#![allow(clippy::disallowed_macros)] use core::{error, fmt, hash::Hash, time::Duration};
4
5pub use aranya_crypto::tls::CipherSuiteId;
6use aranya_crypto::{
7 dangerous::spideroak_crypto::hex::Hex,
8 default::DefaultEngine,
9 id::IdError,
10 subtle::{Choice, ConstantTimeEq},
11 zeroize::{Zeroize, ZeroizeOnDrop},
12 EncryptionPublicKey, Engine,
13};
14use aranya_id::custom_id;
15pub use aranya_policy_text::{text, InvalidText, Text};
16use aranya_util::{error::ReportExt, Addr};
17use buggy::Bug;
18pub use semver::Version;
19use serde::{Deserialize, Serialize};
20
21pub mod afc;
22pub mod quic_sync;
23
24#[cfg(feature = "afc")]
25pub use self::afc::*;
26pub use self::quic_sync::*;
27
28pub type CE = DefaultEngine;
30pub type CS = <DefaultEngine as Engine>::CS;
32
33#[derive(Serialize, Deserialize, Debug)]
36pub struct Error(String);
37
38impl Error {
39 pub fn from_msg(err: &str) -> Self {
40 Self(err.into())
41 }
42
43 pub fn from_err<E: error::Error>(err: E) -> Self {
44 Self(ReportExt::report(&err).to_string())
45 }
46}
47
48impl From<Bug> for Error {
49 fn from(err: Bug) -> Self {
50 Self::from_err(err)
51 }
52}
53
54impl From<anyhow::Error> for Error {
55 fn from(err: anyhow::Error) -> Self {
56 Self(format!("{err:?}"))
57 }
58}
59
60impl From<InvalidText> for Error {
61 fn from(err: InvalidText) -> Self {
62 Self(format!("{err:?}"))
63 }
64}
65
66impl From<semver::Error> for Error {
67 fn from(err: semver::Error) -> Self {
68 Self::from_err(err)
69 }
70}
71
72impl From<IdError> for Error {
73 fn from(err: IdError) -> Self {
74 Self::from_err(err)
75 }
76}
77
78impl fmt::Display for Error {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 self.0.fmt(f)
81 }
82}
83
84impl error::Error for Error {}
85
86pub type Result<T, E = Error> = core::result::Result<T, E>;
87
88custom_id! {
89 pub struct DeviceId;
91}
92
93custom_id! {
94 pub struct TeamId;
96}
97
98custom_id! {
99 pub struct LabelId;
101}
102
103custom_id! {
104 pub struct RoleId;
106}
107
108#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
109pub struct Role {
110 pub id: RoleId,
112 pub name: Text,
114 pub author_id: DeviceId,
116 pub default: bool,
118}
119
120#[derive(Clone, Serialize, Deserialize, Eq, PartialEq)]
122pub struct PublicKeyBundle {
123 pub identity: Vec<u8>,
124 pub signing: Vec<u8>,
125 pub encryption: Vec<u8>,
126}
127
128impl fmt::Debug for PublicKeyBundle {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 f.debug_struct("PublicKeyBundle")
131 .field("identity", &Hex::new(&*self.identity))
132 .field("signing", &Hex::new(&*self.signing))
133 .field("encryption", &Hex::new(&*self.encryption))
134 .finish()
135 }
136}
137
138#[derive(Debug, Serialize, Deserialize)]
141pub struct AddTeamConfig {
142 pub team_id: TeamId,
143 pub quic_sync: Option<AddTeamQuicSyncConfig>,
144}
145
146#[derive(Debug, Serialize, Deserialize)]
149pub struct CreateTeamConfig {
150 pub quic_sync: Option<CreateTeamQuicSyncConfig>,
151}
152
153#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
155pub struct Label {
156 pub id: LabelId,
157 pub name: Text,
158 pub author_id: DeviceId,
159}
160
161#[derive(Clone, Serialize, Deserialize)]
163pub struct Ikm([u8; SEED_IKM_SIZE]);
164
165impl Ikm {
166 #[inline]
168 pub fn raw_ikm_bytes(&self) -> &[u8; SEED_IKM_SIZE] {
169 &self.0
170 }
171}
172
173impl From<[u8; SEED_IKM_SIZE]> for Ikm {
174 fn from(value: [u8; SEED_IKM_SIZE]) -> Self {
175 Self(value)
176 }
177}
178
179impl ConstantTimeEq for Ikm {
180 fn ct_eq(&self, other: &Self) -> Choice {
181 self.0.ct_eq(&other.0)
182 }
183}
184
185impl ZeroizeOnDrop for Ikm {}
186impl Drop for Ikm {
187 fn drop(&mut self) {
188 self.0.zeroize()
189 }
190}
191
192impl fmt::Debug for Ikm {
193 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194 f.debug_struct("Ikm").finish_non_exhaustive()
195 }
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#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
267pub enum RoleManagementPerm {
268 CanAssignRole,
271 CanRevokeRole,
274 CanChangeRolePerms,
277}
278
279#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
281pub enum SimplePerm {
282 AddDevice,
286 RemoveDevice,
288 TerminateTeam,
291
292 CreateRole,
296 DeleteRole,
298 AssignRole,
300 RevokeRole,
302 ChangeRoleManagementPerms,
304 SetupDefaultRole,
308 ChangeRoleManagingRole,
311
312 CreateLabel,
316 DeleteLabel,
318 ChangeLabelManagingRole,
322 AssignLabel,
326 RevokeLabel,
330
331 CanUseAfc,
336 CreateAfcUniChannel,
338}
339
340#[cfg(not(feature = "afc"))]
342use afc_stub::{AfcReceiveChannelInfo, AfcSendChannelInfo, AfcShmInfo};
343#[cfg(not(feature = "afc"))]
344mod afc_stub {
345 #[derive(Debug, serde::Serialize, serde::Deserialize)]
346 pub enum Never {}
347 pub type AfcShmInfo = Never;
348 pub type AfcSendChannelInfo = Never;
349 pub type AfcReceiveChannelInfo = Never;
350}
351
352#[tarpc::service]
353pub trait DaemonApi {
354 async fn version() -> Result<Version>;
360 async fn aranya_local_addr() -> Result<Addr>;
362
363 async fn get_public_key_bundle() -> Result<PublicKeyBundle>;
365 async fn get_device_id() -> Result<DeviceId>;
367
368 async fn add_sync_peer(addr: Addr, team: TeamId, config: SyncPeerConfig) -> Result<()>;
374 async fn sync_now(addr: Addr, team: TeamId, cfg: Option<SyncPeerConfig>) -> Result<()>;
376
377 #[cfg(feature = "preview")]
379 async fn sync_hello_subscribe(
380 peer: Addr,
381 team: TeamId,
382 graph_change_debounce: Duration,
383 duration: Duration,
384 schedule_delay: Duration,
385 ) -> Result<()>;
386
387 #[cfg(feature = "preview")]
389 async fn sync_hello_unsubscribe(peer: Addr, team: TeamId) -> Result<()>;
390
391 async fn remove_sync_peer(addr: Addr, team: TeamId) -> Result<()>;
393 async fn add_team(cfg: AddTeamConfig) -> Result<()>;
395
396 async fn remove_team(team: TeamId) -> Result<()>;
398
399 async fn create_team(cfg: CreateTeamConfig) -> Result<TeamId>;
401 async fn close_team(team: TeamId) -> Result<()>;
403
404 async fn encrypt_psk_seed_for_peer(
406 team: TeamId,
407 peer_enc_pk: EncryptionPublicKey<CS>,
408 ) -> Result<WrappedSeed>;
409
410 async fn add_device_to_team(
416 team: TeamId,
417 keys: PublicKeyBundle,
418 initial_role: Option<RoleId>,
419 ) -> Result<()>;
420 async fn remove_device_from_team(team: TeamId, device: DeviceId) -> Result<()>;
422 async fn devices_on_team(team: TeamId) -> Result<Box<[DeviceId]>>;
424 async fn device_public_key_bundle(team: TeamId, device: DeviceId) -> Result<PublicKeyBundle>;
426
427 async fn setup_default_roles(team: TeamId, owning_role: RoleId) -> Result<Box<[Role]>>;
435 #[cfg(feature = "preview")]
437 async fn create_role(team: TeamId, role_name: Text, owning_role: RoleId) -> Result<Role>;
438 #[cfg(feature = "preview")]
440 async fn delete_role(team: TeamId, role_id: RoleId) -> Result<()>;
441 async fn team_roles(team: TeamId) -> Result<Box<[Role]>>;
443
444 #[cfg(feature = "preview")]
450 async fn add_perm_to_role(team: TeamId, role: RoleId, perm: SimplePerm) -> Result<()>;
451 #[cfg(feature = "preview")]
453 async fn remove_perm_from_role(team: TeamId, role: RoleId, perm: SimplePerm) -> Result<()>;
454 #[cfg(feature = "preview")]
456 async fn add_role_owner(team: TeamId, role: RoleId, owning_role: RoleId) -> Result<()>;
457 #[cfg(feature = "preview")]
459 async fn remove_role_owner(team: TeamId, role: RoleId, owning_role: RoleId) -> Result<()>;
460 async fn role_owners(team: TeamId, role: RoleId) -> Result<Box<[Role]>>;
462 #[cfg(feature = "preview")]
464 async fn assign_role_management_perm(
465 team: TeamId,
466 role: RoleId,
467 managing_role: RoleId,
468 perm: RoleManagementPerm,
469 ) -> Result<()>;
470 #[cfg(feature = "preview")]
472 async fn revoke_role_management_perm(
473 team: TeamId,
474 role: RoleId,
475 managing_role: RoleId,
476 perm: RoleManagementPerm,
477 ) -> Result<()>;
478
479 async fn assign_role(team: TeamId, device: DeviceId, role: RoleId) -> Result<()>;
485 async fn revoke_role(team: TeamId, device: DeviceId, role: RoleId) -> Result<()>;
487 async fn change_role(
489 team: TeamId,
490 device: DeviceId,
491 old_role: RoleId,
492 new_role: RoleId,
493 ) -> Result<()>;
494 async fn device_role(team: TeamId, device: DeviceId) -> Result<Option<Role>>;
496
497 async fn create_label(team: TeamId, name: Text, managing_role_id: RoleId) -> Result<LabelId>;
503 async fn delete_label(team: TeamId, label_id: LabelId) -> Result<()>;
505 async fn label(team: TeamId, label: LabelId) -> Result<Option<Label>>;
507 async fn labels(team: TeamId) -> Result<Vec<Label>>;
509
510 async fn add_label_managing_role(
515 team: TeamId,
516 label_id: LabelId,
517 managing_role_id: RoleId,
518 ) -> Result<()>;
519
520 async fn assign_label_to_device(
526 team: TeamId,
527 device: DeviceId,
528 label: LabelId,
529 op: ChanOp,
530 ) -> Result<()>;
531 async fn revoke_label_from_device(team: TeamId, device: DeviceId, label: LabelId)
533 -> Result<()>;
534 async fn labels_assigned_to_device(team: TeamId, device: DeviceId) -> Result<Box<[Label]>>;
536
537 #[cfg(feature = "afc")]
539 #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
540 async fn afc_shm_info() -> Result<AfcShmInfo>;
541 #[cfg(feature = "afc")]
543 #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
544 async fn create_afc_channel(
545 team: TeamId,
546 peer_id: DeviceId,
547 label_id: LabelId,
548 ) -> Result<AfcSendChannelInfo>;
549 #[cfg(feature = "afc")]
551 #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
552 async fn delete_afc_channel(chan: AfcLocalChannelId) -> Result<()>;
553 #[cfg(feature = "afc")]
555 #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
556 async fn accept_afc_channel(team: TeamId, ctrl: AfcCtrl) -> Result<AfcReceiveChannelInfo>;
557}