uniauth/
daemon.rs

1//! The daemon RPC API for use by clients.
2
3use crate::{
4	any::*,
5	error::*,
6	requests,
7	util::{AsyncReadExtraExt, AsyncWriteExtraExt},
8	daemon_path
9};
10
11use std::path::Path;
12
13use tokio::{
14	io::{AsyncReadExt, AsyncWriteExt},
15	net::UnixStream
16};
17
18/// Connection to the user's uniauth daemon, used for RPC
19/// Connection with the daemon will last as long as this struct exists.
20/// Should only be used by an application's client, never a server.
21pub struct Daemon {
22	sock: UnixStream
23}
24
25impl Daemon {
26	/// Connect to the default daemon path.
27	///
28	/// # Arguments
29	/// * `service` - Name of this service
30	///
31	/// # Example
32	/// ```
33	/// let daemon = Daemon::new("matrix").await?;
34	/// ```
35	pub async fn new(service: &str) -> Result<Self> {
36		Self::connect(service, &daemon_path()).await
37	}
38
39	/// Connect to a custom daemon path
40	///
41	/// # Arguments
42	/// * `service` - Name of this service
43	/// * `path` - Path to the daemon's unix socket
44	///
45	/// # Example
46	/// ```
47	/// let daemon = Daemon::connect("test_thing", "/tmp/test.sock").await?;
48	/// ```
49	pub async fn connect(service: &str, path: impl AsRef<Path>) -> Result<Self> {
50		let mut sock = UnixStream::connect(path).await?;
51
52		sock.write_str(service).await?;
53
54		Ok(Self {
55			sock
56		})
57	}
58
59	/// Authenticate an action for a given service login, returning its signature.
60	/// All fields must be known by the server to authenticate with through communication or hardcoding.
61	///
62	/// # Arguments
63	/// * `name` - Name of the service's key to use
64	/// * `action` - Action to authenticate. Must be human readable, but also completely deterministic
65	/// * `nonce` - Unique random data or atomic counter that is unique to this challenge and never used again
66	///
67	/// # Example
68	/// ```
69	/// let nonce = random_data_from_server();
70	/// let sig = daemon.authenticate("username", "login", &nonce).await?;
71	/// send_signature_to_server(sig);
72	/// ```
73	pub async fn authenticate(&mut self, name: &str, action: &str, nonce: &[u8]) -> Result<AnySignature> {
74		let sock = &mut self.sock;
75		sock.write_u8(requests::AUTHENTICATE).await?;
76		sock.write_str(name).await?;
77		sock.write_str(action).await?;
78		sock.write_b8(nonce).await?;
79
80		let status = sock.read_u8().await?;
81		Error::from_status(status)?;
82
83		let algo = sock.read_str().await?;
84		let bytes = sock.read_b16().await?;
85
86		AnySignature::new(&algo, &bytes)
87	}
88
89	/// Get the public key for a given name
90	///
91	/// # Arguments
92	/// * `name` - Name of the key as added with `store`
93	///
94	/// # Example
95	/// ```
96	/// let pubkey = daemon.pubkey("username").await?;
97	/// send_server_pubkey(pubkey);
98	/// // have the server verify a regsiter action now
99	/// ```
100	pub async fn pubkey(&mut self, name: &str) -> Result<AnyPubkey> {
101		let sock = &mut self.sock;
102		sock.write_u8(requests::PUBKEY).await?;
103		sock.write_str(name).await?;
104
105		let status = sock.read_u8().await?;
106		Error::from_status(status)?;
107
108		let algo = sock.read_str().await?;
109		let bytes = sock.read_b16().await?;
110		AnyPubkey::new(&algo, &bytes)
111	}
112
113	/// Store a keypair for a new service login.
114	/// Will fail if a keypair already exists.
115	///
116	/// # Warning
117	/// Since the client provides the keypair, this gives it a requirement for extra security.
118	/// Keys that are generated and immediately stored should use `generate` instead.
119	///
120	/// # Arguments
121	/// * `name` - Name of the key to be retrieved by `authenticate` or `pubkey`
122	/// * `keypair` - The keypair used for signing challenges
123	///
124	/// # Example
125	/// ```
126	/// let keypair = import_keypair();
127	/// daemon.store("username", keypair).await?;
128	/// ```
129	pub async fn store(&mut self, name: &str, keypair: AnyKeypair) -> Result<()> {
130		let sock = &mut self.sock;
131		sock.write_u8(requests::STORE).await?;
132		sock.write_str(name).await?;
133		sock.write_str(keypair.name()).await?;
134		sock.write_b16(keypair.public_bytes()).await?;
135		sock.write_b16(keypair.secret_bytes()).await?;
136
137		let status = sock.read_u8().await?;
138		Error::from_status(status)
139	}
140
141	/// Generate a new keypair and return its public half.
142	/// Will fail if a keypair already exists
143	///
144	/// # Arguments
145	/// * `name` - Name of the key to generate
146	///
147	/// # Example
148	/// ```
149	/// let pubkey = daemon.generate("username").await?;
150	/// pubkey.verify(b"whatever", signature)?;
151	/// ```
152	pub async fn generate(&mut self, name: &str) -> Result<AnyPubkey> {
153		let sock = &mut self.sock;
154		sock.write_u8(requests::GENERATE).await?;
155		sock.write_str(name).await?;
156
157		let status = sock.read_u8().await?;
158		Error::from_status(status)?;
159
160		let algo = sock.read_str().await?;
161		let bytes = sock.read_b16().await?;
162		AnyPubkey::new(&algo, &bytes)
163	}
164}