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}