reachable_secrets/
server.rs

1// SPDX-FileCopyrightText: 2025 Michael Goldenberg <m@mgoldenberg.net>
2// SPDX-FileCopyrightText: 2025 eaon <eaon@posteo.net>
3// SPDX-License-Identifier: EUPL-1.2
4
5use std::path::{Path, PathBuf};
6use std::sync::Arc;
7
8use redb::Database;
9use tokio::sync::RwLock;
10
11use reach_core::{
12    communication::secrets::*,
13    memory::{ImmutableCell, Key, macros::immutable_cell},
14    wire::{AttestantVerifyingKeys, ReachableVerifyingKeys, Salts},
15};
16use reach_proc_macros::request_handler_macro;
17use reach_signatures::Digestible;
18use reach_websocket::{LocalServerContext, WebSocketServer, macros::*, start as core_start};
19
20use crate::error::Error;
21use crate::memory::ReachableSigningKeys;
22
23pub struct SecretsGlobalContext {
24    data_path: PathBuf,
25    pub db: Database,
26}
27
28impl SecretsGlobalContext {
29    pub fn new(data_path: PathBuf) -> Self {
30        let db = Database::create(data_path.join("database.redb"))
31            .expect("Database path should be writeable.");
32
33        Self { data_path, db }
34    }
35
36    pub fn data_path<P: AsRef<Path>>(&self, path: P) -> PathBuf {
37        self.data_path.join(path)
38    }
39}
40
41pub struct SecretsSessionContext {
42    unlocked_key: ImmutableCell<Key>,
43    attestant_verifying_keys: ImmutableCell<AttestantVerifyingKeys>,
44    salts: ImmutableCell<Salts>,
45    signing_keys: ImmutableCell<ReachableSigningKeys>,
46    pub all_verifying_keys: Option<Vec<ReachableVerifyingKeys>>,
47    pub verifying_keys: Option<usize>,
48}
49
50impl From<SecretsSessionContext> for () {
51    fn from(_: SecretsSessionContext) {}
52}
53
54#[derive(Clone)]
55pub struct SecretsSessionContextInit {}
56
57impl From<SecretsSessionContextInit> for Arc<RwLock<SecretsSessionContext>> {
58    fn from(_: SecretsSessionContextInit) -> Self {
59        Arc::new(RwLock::new(SecretsSessionContext {
60            unlocked_key: ImmutableCell::new(),
61            attestant_verifying_keys: ImmutableCell::new(),
62            salts: ImmutableCell::new(),
63            signing_keys: ImmutableCell::new(),
64            verifying_keys: None,
65            all_verifying_keys: None,
66        }))
67    }
68}
69
70impl SecretsSessionContext {
71    pub fn verifying_keys(&self) -> Result<&ReachableVerifyingKeys, Error> {
72        let all_verifying_keys = self
73            .all_verifying_keys
74            .as_ref()
75            .ok_or(Error::MissingVerifyingKeys)?;
76        let idx = self.verifying_keys.ok_or(Error::MissingVerifyingKeys)?;
77
78        all_verifying_keys
79            .get(idx)
80            .ok_or(Error::MissingVerifyingKeys)
81    }
82
83    immutable_cell!(or: unlocked_key, Key, Error::Internal);
84    immutable_cell!(or: salts, Salts, Error::Internal);
85    immutable_cell!(or: attestant_verifying_keys, AttestantVerifyingKeys, Error::Internal);
86    immutable_cell!(or_init: signing_keys, ReachableSigningKeys, Error);
87}
88
89pub type SecretsConnectionContext = LocalServerContext<Request, Response>;
90pub type SecretsConnection = WebSocketServer<SecretsConnectionContext>;
91
92request_wrapper!(SecretsRequest, Request);
93
94request_delegator!(
95    SecretsDelegator,
96    SecretsCommunication,
97    SecretsGlobalContext,
98    SecretsSessionContext,
99    SecretsRequest,
100    (
101        Hello,
102        Initialize,
103        UnlockKey,
104        GetReachablePublicKeys,
105        AllReachableVerifyingKeys,
106    ),
107);
108
109request_handler_macro!(
110    request_handler,
111    SecretsCommunication,
112    SecretsRequest,
113    SecretsGlobalContext,
114    SecretsSessionContext,
115);
116
117pub async fn start<const B: usize>(
118    socket_path: impl AsRef<Path>,
119    global_context: SecretsGlobalContext,
120    session_context_init: SecretsSessionContextInit,
121) -> std::io::Result<()> {
122    core_start::<B, (), SecretsDelegator, SecretsCommunication, SecretsConnectionContext>(
123        socket_path,
124        (),
125        global_context,
126        session_context_init,
127    )
128    .await
129}
130
131pub(crate) fn populate_verifying_keys(
132    ctx: &mut SecretsSessionContext,
133    all_reachable_verifying_keys: &[ReachableVerifyingKeys],
134    verifying_keys_index: usize,
135) {
136    ctx.all_verifying_keys
137        .replace(all_reachable_verifying_keys.to_vec());
138    ctx.verifying_keys.replace(verifying_keys_index);
139}
140
141pub(crate) fn verifying_keys_index(
142    signing_keys: &ReachableSigningKeys,
143    reachable_verifying_keys: &[ReachableVerifyingKeys],
144) -> Result<usize, Error> {
145    let verifying_keys_digest = signing_keys.unsigned_verifying_keys().finalized_digest();
146
147    reachable_verifying_keys
148        .iter()
149        .enumerate()
150        .fold(None, |acc, (i, vk)| match acc {
151            Some(_) => acc,
152            None => (vk.finalized_digest() == verifying_keys_digest).then_some(i),
153        })
154        .ok_or(Error::MissingVerifyingKeys)
155}