liminal_server/server/connection/supervisor/
builder.rs1use super::{
2 Arc, AuthConfig, ConnectionNotifier, ConnectionRuntime, ConnectionServices,
3 ConnectionSupervisor, LimitsConfig, PassVerifier, ServerError, SupervisorInner,
4};
5
6pub(super) fn configured_authentication(
12 auth: &AuthConfig,
13) -> Result<(Vec<u8>, Option<PassVerifier>), ServerError> {
14 let pass_verifier = PassVerifier::from_auth(auth)?;
15 Ok((auth.token.clone().into_bytes(), pass_verifier))
16}
17
18#[derive(Debug)]
24pub struct ConnectionSupervisorBuilder {
25 pub(super) services: Arc<dyn ConnectionServices>,
26 pub(super) notifier: Option<Arc<dyn ConnectionNotifier>>,
27 pub(super) auth_token: Option<Vec<u8>>,
28 pub(super) pass_verifier: Option<PassVerifier>,
29 pub(super) lys: Option<LysInstall>,
30 pub(super) limits: LimitsConfig,
31}
32
33#[derive(Debug)]
38pub struct LysInstall {
39 pub(crate) admitter: Arc<dyn crate::auth_lys::session::LysAdmitter>,
41 pub(crate) network_id: String,
43 pub(crate) link_host: Option<Arc<crate::link::LinkHost>>,
45 pub(crate) services: Option<Arc<crate::services::production::ServiceBindings>>,
47 pub(crate) membership: Option<Arc<crate::auth_membership::MembershipGate>>,
50}
51
52pub fn lys_ask_runtime(
61 auth: Option<&AuthConfig>,
62) -> Result<Option<tokio::runtime::Runtime>, ServerError> {
63 if auth.is_none_or(|auth| auth.lys.is_none()) {
64 return Ok(None);
65 }
66 tokio::runtime::Builder::new_multi_thread()
67 .worker_threads(1)
68 .thread_name("liminal-lys-ask")
69 .enable_all()
70 .build()
71 .map(Some)
72 .map_err(|error| ServerError::ConfigValidation {
73 message: format!("the Lys ask runtime could not start: {error}"),
74 })
75}
76
77pub fn configured_lys(
85 auth: &AuthConfig,
86 ask_handle: Option<tokio::runtime::Handle>,
87) -> Result<Option<LysInstall>, ServerError> {
88 let Some(lys) = auth.lys.as_ref() else {
89 return Ok(None);
90 };
91 let keys_json =
92 std::fs::read_to_string(&lys.keys_path).map_err(|error| ServerError::ConfigValidation {
93 message: format!("auth.lys.keys_path {}: {error}", lys.keys_path.display()),
94 })?;
95 let mut adapter = crate::auth_lys::lys_pass_adapter::LysPassAdapter::from_keys_json(
96 &keys_json,
97 lys.issuer.clone(),
98 )
99 .map_err(|error| ServerError::ConfigValidation {
100 message: format!("auth.lys key set refused: {error}"),
101 })?;
102 if lys.live {
103 let Some(handle) = ask_handle.as_ref() else {
106 return Err(ServerError::ConfigValidation {
107 message:
108 "auth.lys.live needs the server's Lys ask runtime at start; none was given"
109 .to_owned(),
110 });
111 };
112 let mut live = crate::auth_lys::live::HttpLysAsk::new(
113 lys.api_url.as_deref().unwrap_or(&lys.issuer),
114 handle.clone(),
115 )
116 .map_err(|error| ServerError::ConfigValidation {
117 message: format!("auth.lys.issuer refused for live asks: {error}"),
118 })?;
119 if let Some(path) = lys.app_credential_path.as_ref() {
123 let credential =
124 std::fs::read_to_string(path).map_err(|error| ServerError::ConfigValidation {
125 message: format!(
126 "auth.lys.app_credential_path '{}' cannot be read: {}",
127 path.display(),
128 error.kind()
129 ),
130 })?;
131 live = live.asking_as(credential.trim().to_owned());
132 }
133 adapter = adapter.with_live(Arc::new(live));
134 }
135 let adapter = Arc::new(adapter);
136 let now = std::time::SystemTime::now()
137 .duration_since(std::time::UNIX_EPOCH)
138 .map_err(|_| ServerError::ConfigValidation {
139 message: "machine pass clock is before the Unix epoch".to_owned(),
140 })?
141 .as_secs();
142 let machine_pass = crate::link_pass::configured(lys, adapter, ask_handle, now)?;
143 let membership = lys
144 .membership
145 .as_ref()
146 .map(|membership| crate::auth_membership::configured_gate(membership, &lys.issuer))
147 .transpose()?;
148 Ok(Some(LysInstall {
149 admitter: machine_pass.admitter,
150 network_id: lys.network_id.clone(),
151 link_host: machine_pass.host,
152 services: None,
153 membership,
154 }))
155}
156
157impl ConnectionSupervisorBuilder {
158 pub fn auth(mut self, auth: &AuthConfig) -> Result<Self, ServerError> {
168 let (auth_token, pass_verifier) = configured_authentication(auth)?;
169 self.auth_token = Some(auth_token);
170 self.pass_verifier = pass_verifier;
171 self.lys = configured_lys(auth, tokio::runtime::Handle::try_current().ok())?;
172 Ok(self)
173 }
174
175 #[cfg(test)]
178 #[must_use]
179 pub(in crate::server::connection) fn lys_for_tests(mut self, lys: LysInstall) -> Self {
180 self.lys = Some(lys);
181 self
182 }
183
184 #[must_use]
187 pub fn notifier(mut self, notifier: Arc<dyn ConnectionNotifier>) -> Self {
188 self.notifier = Some(notifier);
189 self
190 }
191
192 #[must_use]
194 pub const fn limits(mut self, limits: LimitsConfig) -> Self {
195 self.limits = limits;
196 self
197 }
198
199 pub fn build(self) -> Result<ConnectionSupervisor, ServerError> {
205 SupervisorInner::new(
206 self.services,
207 self.notifier,
208 self.auth_token,
209 self.pass_verifier,
210 self.lys,
211 self.limits,
212 None,
213 )
214 .map(|inner| ConnectionSupervisor {
215 inner: Arc::new(inner),
216 })
217 }
218}
219
220pub(super) fn install_lys(runtime: &ConnectionRuntime, lys: LysInstall) -> Result<(), ServerError> {
223 let LysInstall {
224 admitter,
225 network_id,
226 link_host,
227 services: bindings,
228 membership,
229 } = lys;
230 runtime
231 .install_lys_admitter(admitter, network_id)
232 .map_err(|_| ServerError::ConfigValidation {
233 message: "auth.lys admitter was already installed".to_owned(),
234 })?;
235 if let Some(host) = link_host {
236 runtime
237 .install_link_host(host)
238 .map_err(|_| ServerError::ConfigValidation {
239 message: "auth.lys.machine was already installed".to_owned(),
240 })?;
241 }
242 if let Some(gate) = membership {
243 runtime
244 .install_membership_gate(gate)
245 .map_err(|_| ServerError::ConfigValidation {
246 message: "auth.lys.membership was already installed".to_owned(),
247 })?;
248 }
249 if let Some(bindings) = bindings {
250 runtime
251 .install_service_bindings(bindings)
252 .map_err(|_| ServerError::ConfigValidation {
253 message: "auth.lys.services was already installed".to_owned(),
254 })?;
255 }
256 Ok(())
257}