1pub struct Capability;
13
14impl Capability {
15 pub const CHAT_SEND: &str = "chat.send";
17 pub const CHAT_RECEIVE: &str = "chat.receive";
18 pub const PAGE_BROWSE: &str = "page.browse";
19 pub const RPC_PING: &str = "rpc.ping";
20 pub const RPC_STATUS: &str = "rpc.status";
21 pub const DATALINK_PING: &str = "datalink.ping";
22 pub const DATALINK_META: &str = "datalink.meta";
23 pub const DATALINK_INFO: &str = "datalink.info";
24 pub const DATALINK_STATUS: &str = "datalink.status";
25 pub const RELAY_REQUEST: &str = "relay.request";
26 pub const RELAY_LIST: &str = "relay.list";
27 pub const RELAY_TEARDOWN: &str = "relay.teardown";
28 pub const RELAY_ACCEPT: &str = "relay.accept";
29
30 pub const RPC_INBOX_READ: &str = "rpc.inbox_read";
32 pub const WEB_READ: &str = "web.read";
33 pub const DATALINK_ESTABLISH: &str = "datalink.establish";
34 pub const DATALINK_SPEEDTEST: &str = "datalink.speedtest";
35
36 pub const RPC_CONFIG_UPDATE: &str = "rpc.config_update";
38 pub const TERMINAL_RESTRICTED: &str = "terminal.restricted";
39 pub const WEB_WRITE: &str = "web.write";
40 pub const RELAY_REQUEST_PERMANENT: &str = "relay.request_permanent";
41 pub const RELAY_ACCEPT_PERMANENT: &str = "relay.accept_permanent";
42 pub const RELAY_PRIORITIZE: &str = "relay.prioritize";
43 pub const RELAY_BRIDGE: &str = "relay.bridge";
44
45 pub const RPC_EXEC: &str = "rpc.exec";
47 pub const RPC_REBOOT: &str = "rpc.reboot";
48 pub const RPC_SELF_UPDATE: &str = "rpc.self_update";
49 pub const TERMINAL_FULL: &str = "terminal.full";
50 pub const ADAPTER_PROVISION: &str = "adapter.provision";
51 pub const RELAY_ADMIN: &str = "relay.admin";
52
53 pub const TUNNEL_STATUS: &str = "tunnel.status";
56 pub const TUNNEL_ESTABLISH: &str = "tunnel.establish";
58 pub const TUNNEL_TEARDOWN: &str = "tunnel.teardown";
60
61 pub const VPN_HANDSHAKE: &str = "vpn.handshake";
63 pub const RELAY_REJECT: &str = "relay.reject";
64 pub const I2P_PROXY: &str = "i2p.proxy";
65
66 pub const AETHER_DELEGATE: &str = "aether.delegate";
68 pub const AETHER_QUERY: &str = "aether.query";
69 pub const AETHER_REPORT: &str = "aether.report";
70}
71
72pub const ALL_CAPABILITIES: &[&str] = &[
74 Capability::CHAT_SEND,
76 Capability::CHAT_RECEIVE,
77 Capability::PAGE_BROWSE,
78 Capability::RPC_PING,
79 Capability::RPC_STATUS,
80 Capability::DATALINK_PING,
81 Capability::DATALINK_META,
82 Capability::DATALINK_INFO,
83 Capability::DATALINK_STATUS,
84 Capability::RELAY_REQUEST,
85 Capability::RELAY_LIST,
86 Capability::RELAY_TEARDOWN,
87 Capability::RELAY_ACCEPT,
88 Capability::RPC_INBOX_READ,
90 Capability::WEB_READ,
91 Capability::DATALINK_ESTABLISH,
92 Capability::DATALINK_SPEEDTEST,
93 Capability::RPC_CONFIG_UPDATE,
95 Capability::TERMINAL_RESTRICTED,
96 Capability::WEB_WRITE,
97 Capability::RELAY_REQUEST_PERMANENT,
98 Capability::RELAY_ACCEPT_PERMANENT,
99 Capability::RELAY_PRIORITIZE,
100 Capability::RELAY_BRIDGE,
101 Capability::RPC_EXEC,
103 Capability::RPC_REBOOT,
104 Capability::RPC_SELF_UPDATE,
105 Capability::TERMINAL_FULL,
106 Capability::ADAPTER_PROVISION,
107 Capability::RELAY_ADMIN,
108 Capability::TUNNEL_STATUS,
110 Capability::TUNNEL_ESTABLISH,
111 Capability::TUNNEL_TEARDOWN,
112 Capability::VPN_HANDSHAKE,
114 Capability::RELAY_REJECT,
115 Capability::I2P_PROXY,
116 Capability::AETHER_DELEGATE,
118 Capability::AETHER_QUERY,
119 Capability::AETHER_REPORT,
120];
121
122pub const PEER_CAPS: &[&str] = &[
124 Capability::CHAT_SEND,
125 Capability::CHAT_RECEIVE,
126 Capability::PAGE_BROWSE,
127 Capability::RPC_PING,
128 Capability::RPC_STATUS,
129 Capability::DATALINK_PING,
130 Capability::DATALINK_META,
131 Capability::DATALINK_INFO,
132 Capability::DATALINK_STATUS,
133 Capability::RELAY_REQUEST,
134 Capability::RELAY_LIST,
135 Capability::RELAY_TEARDOWN,
136 Capability::RELAY_ACCEPT,
137 Capability::TUNNEL_STATUS,
139 Capability::AETHER_QUERY,
141 Capability::AETHER_REPORT,
142];
143
144pub const MONITOR_CAPS: &[&str] = &[
146 Capability::CHAT_SEND,
148 Capability::CHAT_RECEIVE,
149 Capability::PAGE_BROWSE,
150 Capability::RPC_PING,
151 Capability::RPC_STATUS,
152 Capability::DATALINK_PING,
153 Capability::DATALINK_META,
154 Capability::DATALINK_INFO,
155 Capability::DATALINK_STATUS,
156 Capability::RELAY_REQUEST,
157 Capability::RELAY_LIST,
158 Capability::RELAY_TEARDOWN,
159 Capability::RELAY_ACCEPT,
160 Capability::TUNNEL_STATUS,
161 Capability::AETHER_QUERY,
162 Capability::AETHER_REPORT,
163 Capability::RPC_INBOX_READ,
165 Capability::WEB_READ,
166 Capability::DATALINK_ESTABLISH,
167 Capability::DATALINK_SPEEDTEST,
168];
169
170pub const OPERATOR_CAPS: &[&str] = &[
172 Capability::CHAT_SEND,
174 Capability::CHAT_RECEIVE,
175 Capability::PAGE_BROWSE,
176 Capability::RPC_PING,
177 Capability::RPC_STATUS,
178 Capability::DATALINK_PING,
179 Capability::DATALINK_META,
180 Capability::DATALINK_INFO,
181 Capability::DATALINK_STATUS,
182 Capability::RELAY_REQUEST,
183 Capability::RELAY_LIST,
184 Capability::RELAY_TEARDOWN,
185 Capability::RELAY_ACCEPT,
186 Capability::TUNNEL_STATUS,
187 Capability::AETHER_QUERY,
188 Capability::AETHER_REPORT,
189 Capability::RPC_INBOX_READ,
191 Capability::WEB_READ,
192 Capability::DATALINK_ESTABLISH,
193 Capability::DATALINK_SPEEDTEST,
194 Capability::RPC_CONFIG_UPDATE,
196 Capability::TERMINAL_RESTRICTED,
197 Capability::WEB_WRITE,
198 Capability::RELAY_REQUEST_PERMANENT,
199 Capability::RELAY_ACCEPT_PERMANENT,
200 Capability::RELAY_PRIORITIZE,
201 Capability::RELAY_BRIDGE,
202 Capability::TUNNEL_ESTABLISH,
203 Capability::TUNNEL_TEARDOWN,
204 Capability::AETHER_DELEGATE,
206];
207
208pub const ADMIN_CAPS: &[&str] = &[
212 Capability::CHAT_SEND,
214 Capability::CHAT_RECEIVE,
215 Capability::PAGE_BROWSE,
216 Capability::RPC_PING,
217 Capability::RPC_STATUS,
218 Capability::DATALINK_PING,
219 Capability::DATALINK_META,
220 Capability::DATALINK_INFO,
221 Capability::DATALINK_STATUS,
222 Capability::RELAY_REQUEST,
223 Capability::RELAY_LIST,
224 Capability::RELAY_TEARDOWN,
225 Capability::RELAY_ACCEPT,
226 Capability::TUNNEL_STATUS,
227 Capability::AETHER_QUERY,
228 Capability::AETHER_REPORT,
229 Capability::RPC_INBOX_READ,
231 Capability::WEB_READ,
232 Capability::DATALINK_ESTABLISH,
233 Capability::DATALINK_SPEEDTEST,
234 Capability::RPC_CONFIG_UPDATE,
236 Capability::TERMINAL_RESTRICTED,
237 Capability::WEB_WRITE,
238 Capability::RELAY_REQUEST_PERMANENT,
239 Capability::RELAY_ACCEPT_PERMANENT,
240 Capability::RELAY_PRIORITIZE,
241 Capability::RELAY_BRIDGE,
242 Capability::TUNNEL_ESTABLISH,
243 Capability::TUNNEL_TEARDOWN,
244 Capability::AETHER_DELEGATE,
245 Capability::RPC_EXEC,
247 Capability::RPC_REBOOT,
248 Capability::RPC_SELF_UPDATE,
249 Capability::TERMINAL_FULL,
250 Capability::ADAPTER_PROVISION,
251 Capability::RELAY_ADMIN,
252];
253
254use crate::Role;
255
256pub fn capabilities_for_role(role: Role) -> &'static [&'static str] {
258 match role {
259 Role::Blocked | Role::None => &[],
260 Role::Peer => PEER_CAPS,
261 Role::Monitor => MONITOR_CAPS,
262 Role::Operator => OPERATOR_CAPS,
263 Role::Admin => ADMIN_CAPS,
264 }
265}
266
267pub fn is_valid_capability(cap: &str) -> bool {
269 ALL_CAPABILITIES.contains(&cap)
270}
271
272#[cfg(test)]
273mod tests {
274 use super::*;
275
276 #[test]
277 fn cumulative_inclusion() {
278 for cap in PEER_CAPS {
280 assert!(MONITOR_CAPS.contains(cap), "monitor missing peer cap: {cap}");
281 assert!(OPERATOR_CAPS.contains(cap), "operator missing peer cap: {cap}");
282 assert!(ADMIN_CAPS.contains(cap), "admin missing peer cap: {cap}");
283 }
284 for cap in MONITOR_CAPS {
285 assert!(OPERATOR_CAPS.contains(cap), "operator missing monitor cap: {cap}");
286 assert!(ADMIN_CAPS.contains(cap), "admin missing monitor cap: {cap}");
287 }
288 for cap in OPERATOR_CAPS {
289 assert!(ADMIN_CAPS.contains(cap), "admin missing operator cap: {cap}");
290 }
291 }
292
293 #[test]
294 fn orthogonal_not_in_admin() {
295 assert!(!ADMIN_CAPS.contains(&Capability::VPN_HANDSHAKE));
296 assert!(!ADMIN_CAPS.contains(&Capability::RELAY_REJECT));
297 }
298
299 #[test]
300 fn aether_caps_in_hierarchy() {
301 assert!(PEER_CAPS.contains(&Capability::AETHER_QUERY));
302 assert!(PEER_CAPS.contains(&Capability::AETHER_REPORT));
303 assert!(!PEER_CAPS.contains(&Capability::AETHER_DELEGATE));
304 assert!(OPERATOR_CAPS.contains(&Capability::AETHER_DELEGATE));
305 }
306
307 #[test]
308 fn all_capabilities_contains_everything() {
309 for cap in ADMIN_CAPS {
310 assert!(ALL_CAPABILITIES.contains(cap), "ALL missing admin cap: {cap}");
311 }
312 assert!(ALL_CAPABILITIES.contains(&Capability::VPN_HANDSHAKE));
313 assert!(ALL_CAPABILITIES.contains(&Capability::RELAY_REJECT));
314 }
315
316 #[test]
317 fn tunnel_caps_in_hierarchy() {
318 assert!(PEER_CAPS.contains(&Capability::TUNNEL_STATUS));
320 assert!(MONITOR_CAPS.contains(&Capability::TUNNEL_STATUS));
321 assert!(OPERATOR_CAPS.contains(&Capability::TUNNEL_STATUS));
322 assert!(ADMIN_CAPS.contains(&Capability::TUNNEL_STATUS));
323
324 assert!(!PEER_CAPS.contains(&Capability::TUNNEL_ESTABLISH));
326 assert!(!MONITOR_CAPS.contains(&Capability::TUNNEL_ESTABLISH));
327 assert!(OPERATOR_CAPS.contains(&Capability::TUNNEL_ESTABLISH));
328 assert!(ADMIN_CAPS.contains(&Capability::TUNNEL_ESTABLISH));
329
330 assert!(!PEER_CAPS.contains(&Capability::TUNNEL_TEARDOWN));
331 assert!(OPERATOR_CAPS.contains(&Capability::TUNNEL_TEARDOWN));
332 assert!(ADMIN_CAPS.contains(&Capability::TUNNEL_TEARDOWN));
333 }
334
335 #[test]
336 fn capabilities_for_blocked_is_empty() {
337 assert!(capabilities_for_role(Role::Blocked).is_empty());
338 assert!(capabilities_for_role(Role::None).is_empty());
339 }
340}