1#![allow(clippy::disallowed_macros)] use 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
30pub type CE = DefaultEngine;
32pub type CS = <DefaultEngine as Engine>::CS;
34
35#[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 pub struct DeviceId;
87}
88
89custom_id! {
90 pub struct TeamId;
92}
93
94custom_id! {
95 pub struct LabelId;
97}
98
99#[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#[derive(Copy, Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
109pub enum Role {
110 Owner,
111 Admin,
112 Operator,
113 Member,
114}
115
116#[derive(Debug, Serialize, Deserialize)]
119pub struct AddTeamConfig {
120 pub team_id: TeamId,
121 pub quic_sync: Option<AddTeamQuicSyncConfig>,
122}
123
124#[derive(Debug, Serialize, Deserialize)]
127pub struct CreateTeamConfig {
128 pub quic_sync: Option<CreateTeamQuicSyncConfig>,
129}
130
131#[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#[derive(Clone, Serialize, Deserialize)]
170pub struct Ikm([u8; SEED_IKM_SIZE]);
171
172impl Ikm {
173 #[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#[derive(Clone, Serialize, Deserialize)]
207pub struct Secret(Box<[u8]>);
208
209impl Secret {
210 #[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#[derive(Clone, Debug, Serialize, Deserialize)]
247pub struct SyncPeerConfig {
248 pub interval: Duration,
250 pub sync_now: bool,
252}
253
254#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
256pub enum ChanOp {
257 RecvOnly,
260 SendOnly,
263 SendRecv,
266}
267
268#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
270pub struct Label {
271 pub id: LabelId,
272 pub name: Text,
273}
274
275#[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 async fn version() -> Result<Version>;
302
303 async fn aranya_local_addr() -> Result<SocketAddr>;
305
306 async fn get_key_bundle() -> Result<KeyBundle>;
308
309 async fn get_device_id() -> Result<DeviceId>;
311
312 async fn add_sync_peer(addr: Addr, team: TeamId, config: SyncPeerConfig) -> Result<()>;
314
315 async fn sync_now(addr: Addr, team: TeamId, cfg: Option<SyncPeerConfig>) -> Result<()>;
317
318 async fn remove_sync_peer(addr: Addr, team: TeamId) -> Result<()>;
320
321 async fn add_team(cfg: AddTeamConfig) -> Result<()>;
323
324 async fn remove_team(team: TeamId) -> Result<()>;
326
327 async fn create_team(cfg: CreateTeamConfig) -> Result<TeamId>;
329 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 async fn add_device_to_team(team: TeamId, keys: KeyBundle) -> Result<()>;
339 async fn remove_device_from_team(team: TeamId, device: DeviceId) -> Result<()>;
341
342 async fn assign_role(team: TeamId, device: DeviceId, role: Role) -> Result<()>;
344 async fn revoke_role(team: TeamId, device: DeviceId, role: Role) -> Result<()>;
346
347 async fn create_label(team: TeamId, name: Text) -> Result<LabelId>;
349 async fn delete_label(team: TeamId, label_id: LabelId) -> Result<()>;
351 async fn assign_label(
353 team: TeamId,
354 device: DeviceId,
355 label_id: LabelId,
356 op: ChanOp,
357 ) -> Result<()>;
358 async fn revoke_label(team: TeamId, device: DeviceId, label_id: LabelId) -> Result<()>;
360
361 #[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 #[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 #[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 #[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 #[cfg(feature = "aqc")]
395 #[cfg_attr(docsrs, doc(cfg(feature = "aqc")))]
396 async fn delete_aqc_bidi_channel(chan: AqcBidiChannelId) -> Result<AqcCtrl>;
397 #[cfg(feature = "aqc")]
399 #[cfg_attr(docsrs, doc(cfg(feature = "aqc")))]
400 async fn delete_aqc_uni_channel(chan: AqcUniChannelId) -> Result<AqcCtrl>;
401 #[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 #[cfg(feature = "afc")]
408 #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
409 async fn afc_shm_info() -> Result<AfcShmInfo>;
410 #[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 #[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 #[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 #[cfg(feature = "afc")]
436 #[cfg_attr(docsrs, doc(cfg(feature = "afc")))]
437 async fn delete_afc_channel(chan: AfcChannelId) -> Result<()>;
438 #[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 async fn query_devices_on_team(team: TeamId) -> Result<Vec<DeviceId>>;
448 async fn query_device_role(team: TeamId, device: DeviceId) -> Result<Role>;
450 async fn query_device_keybundle(team: TeamId, device: DeviceId) -> Result<KeyBundle>;
452 async fn query_device_label_assignments(team: TeamId, device: DeviceId) -> Result<Vec<Label>>;
454 #[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 async fn query_labels(team: TeamId) -> Result<Vec<Label>>;
463 async fn query_label_exists(team: TeamId, label: LabelId) -> Result<bool>;
465}