aranya_daemon_api/
service.rs

1#![allow(clippy::disallowed_macros)] // tarpc uses unreachable
2
3use core::{fmt, hash::Hash, net::SocketAddr, time::Duration};
4
5use aranya_base58::ToBase58;
6use aranya_crypto::{
7    afc::{BidiChannelId, UniChannelId},
8    custom_id,
9    default::DefaultCipherSuite,
10    Id,
11};
12use aranya_fast_channels::{Label, NodeId};
13use aranya_util::Addr;
14use serde::{Deserialize, Serialize};
15use tracing::error;
16
17/// CS = Cipher Suite
18pub type CS = DefaultCipherSuite;
19
20/// An error returned by the API.
21// TODO: enum?
22#[derive(Serialize, Deserialize, Debug)]
23pub struct Error(String);
24
25impl From<anyhow::Error> for Error {
26    fn from(err: anyhow::Error) -> Self {
27        error!(?err);
28        Self(format!("{err:?}"))
29    }
30}
31
32impl From<aranya_crypto::id::IdError> for Error {
33    fn from(err: aranya_crypto::id::IdError) -> Self {
34        error!(%err);
35        Self(err.to_string())
36    }
37}
38
39impl fmt::Display for Error {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        self.0.fmt(f)
42    }
43}
44
45impl core::error::Error for Error {}
46
47pub type Result<T, E = Error> = core::result::Result<T, E>;
48
49custom_id! {
50    /// The Device ID.
51    pub struct DeviceId;
52}
53
54custom_id! {
55    /// The Team ID (a.k.a Graph ID).
56    pub struct TeamId;
57}
58
59/// A device's public key bundle.
60#[derive(Clone, Debug, Serialize, Deserialize)]
61pub struct KeyBundle {
62    pub identity: Vec<u8>,
63    pub signing: Vec<u8>,
64    pub encoding: Vec<u8>,
65}
66
67/// A device's role on the team.
68#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
69pub enum Role {
70    Owner,
71    Admin,
72    Operator,
73    Member,
74}
75
76/// A device's network identifier.
77#[derive(Clone, Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
78pub struct NetIdentifier(pub String);
79
80impl AsRef<str> for NetIdentifier {
81    fn as_ref(&self) -> &str {
82        &self.0
83    }
84}
85
86impl fmt::Display for NetIdentifier {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        self.0.fmt(f)
89    }
90}
91
92/// Uniquely identifies an AFC channel.
93///
94/// It is a [`BidiChannelId`] or [`UniChannelId`] truncated to
95/// 128 bits.
96#[repr(transparent)]
97#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
98pub struct AfcId([u8; 16]);
99
100impl fmt::Display for AfcId {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        write!(f, "{}", self.0.to_base58())
103    }
104}
105
106fn truncate<const BIG: usize, const SMALL: usize>(arr: &[u8; BIG]) -> &[u8; SMALL] {
107    const { assert!(BIG >= SMALL) };
108    arr[..SMALL].try_into().expect("array must fit")
109}
110
111/// Convert from [`BidiChannelId`] to [`AfcId`]
112impl From<BidiChannelId> for AfcId {
113    fn from(value: BidiChannelId) -> Self {
114        Self(*truncate(value.as_array()))
115    }
116}
117
118/// Convert from [`UniChannelId`] to [`AfcId`]
119impl From<UniChannelId> for AfcId {
120    fn from(value: UniChannelId) -> Self {
121        Self(*truncate(value.as_array()))
122    }
123}
124
125/// Convert from [`Id`] to [`AfcId`]
126impl From<Id> for AfcId {
127    fn from(value: Id) -> Self {
128        Self(*truncate(value.as_array()))
129    }
130}
131
132// serialized command which must be passed over AFC.
133pub type AfcCtrl = Vec<Box<[u8]>>;
134
135#[tarpc::service]
136pub trait DaemonApi {
137    /// Gets local address the Aranya sync server is bound to.
138    async fn aranya_local_addr() -> Result<SocketAddr>;
139
140    /// Gets the public key bundle for this device
141    async fn get_key_bundle() -> Result<KeyBundle>;
142
143    /// Gets the public device id.
144    async fn get_device_id() -> Result<DeviceId>;
145
146    /// Adds the peer for automatic periodic syncing.
147    async fn add_sync_peer(addr: Addr, team: TeamId, interval: Duration) -> Result<()>;
148
149    /// Removes the peer from automatic syncing.
150    async fn remove_sync_peer(addr: Addr, team: TeamId) -> Result<()>;
151
152    /// add a team to the local device store that was created by someone else. Not an aranya action/command.
153    async fn add_team(team: TeamId) -> Result<()>;
154
155    /// remove a team from the local device store.
156    async fn remove_team(team: TeamId) -> Result<()>;
157
158    /// Create a new graph/team with the current device as the owner.
159    async fn create_team() -> Result<TeamId>;
160    /// Close the team.
161    async fn close_team(team: TeamId) -> Result<()>;
162
163    /// Add device to the team.
164    async fn add_device_to_team(team: TeamId, keys: KeyBundle) -> Result<()>;
165    /// Remove device from the team.
166    async fn remove_device_from_team(team: TeamId, device: DeviceId) -> Result<()>;
167
168    /// Assign a role to a device.
169    async fn assign_role(team: TeamId, device: DeviceId, role: Role) -> Result<()>;
170    /// Revoke a role from a device.
171    async fn revoke_role(team: TeamId, device: DeviceId, role: Role) -> Result<()>;
172
173    /// Assign a network identifier to a device.
174    async fn assign_net_identifier(
175        team: TeamId,
176        device: DeviceId,
177        name: NetIdentifier,
178    ) -> Result<()>;
179    /// Remove a network identifier from a device.
180    async fn remove_net_identifier(
181        team: TeamId,
182        device: DeviceId,
183        name: NetIdentifier,
184    ) -> Result<()>;
185
186    /// Create a fast channels label.
187    async fn create_label(team: TeamId, label: Label) -> Result<()>;
188    /// Delete a fast channels label.
189    async fn delete_label(team: TeamId, label: Label) -> Result<()>;
190
191    /// Assign a fast channels label to a device.
192    async fn assign_label(team: TeamId, device: DeviceId, label: Label) -> Result<()>;
193    /// Revoke a fast channels label from a device.
194    async fn revoke_label(team: TeamId, device: DeviceId, label: Label) -> Result<()>;
195    /// Create a fast channel.
196    async fn create_bidi_channel(
197        team: TeamId,
198        peer: NetIdentifier,
199        node_id: NodeId,
200        label: Label,
201    ) -> Result<(AfcId, AfcCtrl)>;
202    /// Delete a fast channel.
203    async fn delete_channel(chan: AfcId) -> Result<AfcCtrl>;
204    /// Receive a fast channel ctrl message.
205    async fn receive_afc_ctrl(
206        team: TeamId,
207        node_id: NodeId,
208        ctrl: AfcCtrl,
209    ) -> Result<(AfcId, NetIdentifier, Label)>;
210}