aranya_daemon_api/
service.rs

1#![allow(clippy::disallowed_macros)] // tarpc uses unreachable
2
3use core::{borrow::Borrow, error, fmt, hash::Hash, net::SocketAddr, ops::Deref, time::Duration};
4
5pub use aranya_crypto::tls::CipherSuiteId;
6use aranya_crypto::{
7    custom_id,
8    default::DefaultEngine,
9    id::IdError,
10    subtle::{Choice, ConstantTimeEq},
11    zeroize::{Zeroize, ZeroizeOnDrop},
12    EncryptionPublicKey, Engine,
13};
14pub use aranya_policy_text::{text, Text};
15use aranya_util::{error::ReportExt, Addr};
16use buggy::Bug;
17pub use semver::Version;
18use serde::{Deserialize, Serialize};
19
20pub mod afc;
21pub mod aqc;
22pub mod quic_sync;
23
24#[cfg(feature = "afc")]
25pub use self::afc::*;
26#[cfg(feature = "aqc")]
27pub use self::aqc::*;
28pub use self::quic_sync::*;
29
30/// CE = Crypto Engine
31pub type CE = DefaultEngine;
32/// CS = Cipher Suite
33pub type CS = <DefaultEngine as Engine>::CS;
34
35/// An error returned by the API.
36// TODO: enum?
37#[derive(Serialize, Deserialize, Debug)]
38pub struct Error(String);
39
40impl Error {
41    pub fn from_msg(err: &str) -> Self {
42        Self(err.into())
43    }
44
45    pub fn from_err<E: error::Error>(err: E) -> Self {
46        Self(ReportExt::report(&err).to_string())
47    }
48}
49
50impl From<Bug> for Error {
51    fn from(err: Bug) -> Self {
52        Self::from_err(err)
53    }
54}
55
56impl From<anyhow::Error> for Error {
57    fn from(err: anyhow::Error) -> Self {
58        Self(format!("{err:?}"))
59    }
60}
61
62impl From<semver::Error> for Error {
63    fn from(err: semver::Error) -> Self {
64        Self::from_err(err)
65    }
66}
67
68impl From<IdError> for Error {
69    fn from(err: IdError) -> Self {
70        Self::from_err(err)
71    }
72}
73
74impl fmt::Display for Error {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        self.0.fmt(f)
77    }
78}
79
80impl error::Error for Error {}
81
82pub type Result<T, E = Error> = core::result::Result<T, E>;
83
84custom_id! {
85    /// The Device ID.
86    pub struct DeviceId;
87}
88
89custom_id! {
90    /// The Team ID (a.k.a Graph ID).
91    pub struct TeamId;
92}
93
94custom_id! {
95    /// An AQC label ID.
96    pub struct LabelId;
97}
98
99/// A device's public key bundle.
100#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
101pub struct KeyBundle {
102    pub identity: Vec<u8>,
103    pub signing: Vec<u8>,
104    pub encryption: Vec<u8>,
105}
106
107/// A device's role on the team.
108#[derive(Copy, Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
109pub enum Role {
110    Owner,
111    Admin,
112    Operator,
113    Member,
114}
115
116// Note: any fields added to this type should be public
117/// A configuration for adding a team in the daemon.
118#[derive(Debug, Serialize, Deserialize)]
119pub struct AddTeamConfig {
120    pub team_id: TeamId,
121    pub quic_sync: Option<AddTeamQuicSyncConfig>,
122}
123
124// Note: any fields added to this type should be public
125/// A configuration for creating a team in the daemon.
126#[derive(Debug, Serialize, Deserialize)]
127pub struct CreateTeamConfig {
128    pub quic_sync: Option<CreateTeamQuicSyncConfig>,
129}
130
131/// A device's network identifier.
132#[derive(Clone, Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
133pub struct NetIdentifier(pub Text);
134
135impl Borrow<str> for NetIdentifier {
136    #[inline]
137    fn borrow(&self) -> &str {
138        &self.0
139    }
140}
141
142impl<T> AsRef<T> for NetIdentifier
143where
144    T: ?Sized,
145    <Self as Deref>::Target: AsRef<T>,
146{
147    #[inline]
148    fn as_ref(&self) -> &T {
149        self.deref().as_ref()
150    }
151}
152
153impl Deref for NetIdentifier {
154    type Target = str;
155
156    #[inline]
157    fn deref(&self) -> &Self::Target {
158        &self.0
159    }
160}
161
162impl fmt::Display for NetIdentifier {
163    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164        self.0.fmt(f)
165    }
166}
167
168/// A PSK IKM.
169#[derive(Clone, Serialize, Deserialize)]
170pub struct Ikm([u8; SEED_IKM_SIZE]);
171
172impl Ikm {
173    /// Provides access to the raw IKM bytes.
174    #[inline]
175    pub fn raw_ikm_bytes(&self) -> &[u8; SEED_IKM_SIZE] {
176        &self.0
177    }
178}
179
180impl From<[u8; SEED_IKM_SIZE]> for Ikm {
181    fn from(value: [u8; SEED_IKM_SIZE]) -> Self {
182        Self(value)
183    }
184}
185
186impl ConstantTimeEq for Ikm {
187    fn ct_eq(&self, other: &Self) -> Choice {
188        self.0.ct_eq(&other.0)
189    }
190}
191
192impl ZeroizeOnDrop for Ikm {}
193impl Drop for Ikm {
194    fn drop(&mut self) {
195        self.0.zeroize()
196    }
197}
198
199impl fmt::Debug for Ikm {
200    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201        f.debug_struct("Ikm").finish_non_exhaustive()
202    }
203}
204
205/// A secret.
206#[derive(Clone, Serialize, Deserialize)]
207pub struct Secret(Box<[u8]>);
208
209impl Secret {
210    /// Provides access to the raw secret bytes.
211    #[inline]
212    pub fn raw_secret_bytes(&self) -> &[u8] {
213        &self.0
214    }
215}
216
217impl<T> From<T> for Secret
218where
219    T: Into<Box<[u8]>>,
220{
221    fn from(value: T) -> Self {
222        Self(value.into())
223    }
224}
225
226impl ConstantTimeEq for Secret {
227    fn ct_eq(&self, other: &Self) -> Choice {
228        self.0.ct_eq(&other.0)
229    }
230}
231
232impl ZeroizeOnDrop for Secret {}
233impl Drop for Secret {
234    fn drop(&mut self) {
235        self.0.zeroize()
236    }
237}
238
239impl fmt::Debug for Secret {
240    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        f.debug_struct("Secret").finish_non_exhaustive()
242    }
243}
244
245/// Configuration values for syncing with a peer
246#[derive(Clone, Debug, Serialize, Deserialize)]
247pub struct SyncPeerConfig {
248    /// The interval at which syncing occurs
249    pub interval: Duration,
250    /// Determines if a peer should be synced with immediately after they're added
251    pub sync_now: bool,
252}
253
254/// Valid channel operations for a label assignment.
255#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
256pub enum ChanOp {
257    /// The device can only receive data in channels with this
258    /// label.
259    RecvOnly,
260    /// The device can only send data in channels with this
261    /// label.
262    SendOnly,
263    /// The device can send and receive data in channels with this
264    /// label.
265    SendRecv,
266}
267
268/// A label.
269#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
270pub struct Label {
271    pub id: LabelId,
272    pub name: Text,
273}
274
275// TODO(jdygert): tarpc does not cfg return types properly.
276#[cfg(not(feature = "aqc"))]
277use aqc_stub::{AqcBidiPsks, AqcCtrl, AqcPsks, AqcUniPsks};
278#[cfg(not(feature = "aqc"))]
279mod aqc_stub {
280    #[derive(Debug, serde::Serialize, serde::Deserialize)]
281    pub enum Never {}
282    pub type AqcCtrl = Never;
283    pub type AqcPsks = Never;
284    pub type AqcBidiPsks = Never;
285    pub type AqcUniPsks = Never;
286}
287#[cfg(not(feature = "afc"))]
288use afc_stub::{AfcChannelId, AfcCtrl, AfcShmInfo};
289#[cfg(not(feature = "afc"))]
290mod afc_stub {
291    #[derive(Debug, serde::Serialize, serde::Deserialize)]
292    pub enum Never {}
293    pub type AfcCtrl = Never;
294    pub type AfcShmInfo = Never;
295    pub type AfcChannelId = Never;
296}
297
298#[tarpc::service]
299pub trait DaemonApi {
300    /// Returns the daemon's version.
301    async fn version() -> Result<Version>;
302
303    /// Gets local address the Aranya sync server is bound to.
304    async fn aranya_local_addr() -> Result<SocketAddr>;
305
306    /// Gets the public key bundle for this device
307    async fn get_key_bundle() -> Result<KeyBundle>;
308
309    /// Gets the public device id.
310    async fn get_device_id() -> Result<DeviceId>;
311
312    /// Adds the peer for automatic periodic syncing.
313    async fn add_sync_peer(addr: Addr, team: TeamId, config: SyncPeerConfig) -> Result<()>;
314
315    /// Sync with peer immediately.
316    async fn sync_now(addr: Addr, team: TeamId, cfg: Option<SyncPeerConfig>) -> Result<()>;
317
318    /// Removes the peer from automatic syncing.
319    async fn remove_sync_peer(addr: Addr, team: TeamId) -> Result<()>;
320
321    /// add a team to the local device store that was created by someone else. Not an aranya action/command.
322    async fn add_team(cfg: AddTeamConfig) -> Result<()>;
323
324    /// Remove a team from local device storage.
325    async fn remove_team(team: TeamId) -> Result<()>;
326
327    /// Create a new graph/team with the current device as the owner.
328    async fn create_team(cfg: CreateTeamConfig) -> Result<TeamId>;
329    /// Close the team.
330    async fn close_team(team: TeamId) -> Result<()>;
331
332    async fn encrypt_psk_seed_for_peer(
333        team: TeamId,
334        peer_enc_pk: EncryptionPublicKey<CS>,
335    ) -> Result<WrappedSeed>;
336
337    /// Add device to the team.
338    async fn add_device_to_team(team: TeamId, keys: KeyBundle) -> Result<()>;
339    /// Remove device from the team.
340    async fn remove_device_from_team(team: TeamId, device: DeviceId) -> Result<()>;
341
342    /// Assign a role to a device.
343    async fn assign_role(team: TeamId, device: DeviceId, role: Role) -> Result<()>;
344    /// Revoke a role from a device.
345    async fn revoke_role(team: TeamId, device: DeviceId, role: Role) -> Result<()>;
346
347    // Create a label.
348    async fn create_label(team: TeamId, name: Text) -> Result<LabelId>;
349    // Delete a label.
350    async fn delete_label(team: TeamId, label_id: LabelId) -> Result<()>;
351    // Assign a label to a device.
352    async fn assign_label(
353        team: TeamId,
354        device: DeviceId,
355        label_id: LabelId,
356        op: ChanOp,
357    ) -> Result<()>;
358    // Revoke a label from a device.
359    async fn revoke_label(team: TeamId, device: DeviceId, label_id: LabelId) -> Result<()>;
360
361    /// Assign a QUIC channels network identifier to a device.
362    #[cfg(feature = "aqc")]
363    #[cfg_attr(docsrs, doc(cfg(feature = "aqc")))]
364    async fn assign_aqc_net_identifier(
365        team: TeamId,
366        device: DeviceId,
367        name: NetIdentifier,
368    ) -> Result<()>;
369    /// Remove a QUIC channels network identifier from a device.
370    #[cfg(feature = "aqc")]
371    #[cfg_attr(docsrs, doc(cfg(feature = "aqc")))]
372    async fn remove_aqc_net_identifier(
373        team: TeamId,
374        device: DeviceId,
375        name: NetIdentifier,
376    ) -> Result<()>;
377    /// Create a bidirectional QUIC channel.
378    #[cfg(feature = "aqc")]
379    #[cfg_attr(docsrs, doc(cfg(feature = "aqc")))]
380    async fn create_aqc_bidi_channel(
381        team: TeamId,
382        peer: NetIdentifier,
383        label_id: LabelId,
384    ) -> Result<(AqcCtrl, AqcBidiPsks)>;
385    /// Create a unidirectional QUIC channel.
386    #[cfg(feature = "aqc")]
387    #[cfg_attr(docsrs, doc(cfg(feature = "aqc")))]
388    async fn create_aqc_uni_channel(
389        team: TeamId,
390        peer: NetIdentifier,
391        label_id: LabelId,
392    ) -> Result<(AqcCtrl, AqcUniPsks)>;
393    /// Delete a QUIC bidi channel.
394    #[cfg(feature = "aqc")]
395    #[cfg_attr(docsrs, doc(cfg(feature = "aqc")))]
396    async fn delete_aqc_bidi_channel(chan: AqcBidiChannelId) -> Result<AqcCtrl>;
397    /// Delete a QUIC uni channel.
398    #[cfg(feature = "aqc")]
399    #[cfg_attr(docsrs, doc(cfg(feature = "aqc")))]
400    async fn delete_aqc_uni_channel(chan: AqcUniChannelId) -> Result<AqcCtrl>;
401    /// Receive AQC ctrl message.
402    #[cfg(feature = "aqc")]
403    #[cfg_attr(docsrs, doc(cfg(feature = "aqc")))]
404    async fn receive_aqc_ctrl(team: TeamId, ctrl: AqcCtrl) -> Result<(LabelId, AqcPsks)>;
405
406    /// Gets AFC shared-memory configuration info.
407    #[cfg(feature = "afc")]
408    #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
409    async fn afc_shm_info() -> Result<AfcShmInfo>;
410    /// Create a bidirectional AFC channel.
411    #[cfg(feature = "afc")]
412    #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
413    async fn create_afc_bidi_channel(
414        team: TeamId,
415        peer_id: DeviceId,
416        label_id: LabelId,
417    ) -> Result<(AfcCtrl, AfcChannelId)>;
418    /// Create a unidirectional AFC send-only channel.
419    #[cfg(feature = "afc")]
420    #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
421    async fn create_afc_uni_send_channel(
422        team: TeamId,
423        peer_id: DeviceId,
424        label_id: LabelId,
425    ) -> Result<(AfcCtrl, AfcChannelId)>;
426    /// Create a unidirectional AFC receive-only channel.
427    #[cfg(feature = "afc")]
428    #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
429    async fn create_afc_uni_recv_channel(
430        team: TeamId,
431        peer_id: DeviceId,
432        label_id: LabelId,
433    ) -> Result<(AfcCtrl, AfcChannelId)>;
434    /// Delete a AFC channel.
435    #[cfg(feature = "afc")]
436    #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
437    async fn delete_afc_channel(chan: AfcChannelId) -> Result<()>;
438    /// Receive AFC ctrl message.
439    #[cfg(feature = "afc")]
440    #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
441    async fn receive_afc_ctrl(
442        team: TeamId,
443        ctrl: AfcCtrl,
444    ) -> Result<(LabelId, AfcChannelId, ChanOp)>;
445
446    /// Query devices on team.
447    async fn query_devices_on_team(team: TeamId) -> Result<Vec<DeviceId>>;
448    /// Query device role.
449    async fn query_device_role(team: TeamId, device: DeviceId) -> Result<Role>;
450    /// Query device keybundle.
451    async fn query_device_keybundle(team: TeamId, device: DeviceId) -> Result<KeyBundle>;
452    /// Query device label assignments.
453    async fn query_device_label_assignments(team: TeamId, device: DeviceId) -> Result<Vec<Label>>;
454    /// Query AQC network ID.
455    #[cfg(feature = "aqc")]
456    #[cfg_attr(docsrs, doc(cfg(feature = "aqc")))]
457    async fn query_aqc_net_identifier(
458        team: TeamId,
459        device: DeviceId,
460    ) -> Result<Option<NetIdentifier>>;
461    // Query labels on team.
462    async fn query_labels(team: TeamId) -> Result<Vec<Label>>;
463    /// Query whether a label exists.
464    async fn query_label_exists(team: TeamId, label: LabelId) -> Result<bool>;
465}