1use std::fmt;
8use std::sync::Arc;
9
10use auths_core::ports::clock::ClockProvider;
11use auths_core::ports::id::{SystemUuidProvider, UuidProvider};
12use auths_core::signing::PassphraseProvider;
13use auths_core::storage::keychain::KeyStorage;
14use auths_id::attestation::export::AttestationSink;
15use auths_id::ports::registry::RegistryBackend;
16use auths_id::storage::attestation::AttestationSource;
17use auths_id::storage::identity::IdentityStorage;
18
19use crate::ports::agent::{AgentSigningPort, NoopAgentProvider};
20
21#[derive(Debug, Clone)]
23pub struct BuilderError(pub &'static str);
24
25impl fmt::Display for BuilderError {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 write!(f, "missing required builder field: {}", self.0)
28 }
29}
30
31impl std::error::Error for BuilderError {}
32
33pub trait EventSink: Send + Sync + 'static {
47 fn emit(&self, payload: &str);
49
50 fn flush(&self);
52}
53
54struct NoopSink;
55
56impl EventSink for NoopSink {
57 fn emit(&self, _payload: &str) {}
58 fn flush(&self) {}
59}
60
61struct NoopPassphraseProvider;
62
63impl PassphraseProvider for NoopPassphraseProvider {
64 fn get_passphrase(
65 &self,
66 _prompt: &str,
67 ) -> Result<zeroize::Zeroizing<String>, auths_core::AgentError> {
68 Err(auths_core::AgentError::SigningFailed(
69 "no passphrase provider configured — call .passphrase_provider(...) on AuthsContextBuilder".into(),
70 ))
71 }
72}
73
74pub struct AuthsContext {
95 pub registry: Arc<dyn RegistryBackend + Send + Sync>,
97 pub key_storage: Arc<dyn KeyStorage + Send + Sync>,
99 pub clock: Arc<dyn ClockProvider + Send + Sync>,
101 pub event_sink: Arc<dyn EventSink>,
103 pub identity_storage: Arc<dyn IdentityStorage + Send + Sync>,
105 pub attestation_sink: Arc<dyn AttestationSink + Send + Sync>,
107 pub attestation_source: Arc<dyn AttestationSource + Send + Sync>,
109 pub passphrase_provider: Arc<dyn PassphraseProvider + Send + Sync>,
113 pub uuid_provider: Arc<dyn UuidProvider + Send + Sync>,
116 pub agent_signing: Arc<dyn AgentSigningPort + Send + Sync>,
120}
121
122impl AuthsContext {
123 pub fn builder() -> AuthsContextBuilder<Missing, Missing, Missing> {
138 AuthsContextBuilder {
139 registry: Missing,
140 key_storage: Missing,
141 clock: Missing,
142 event_sink: None,
143 identity_storage: None,
144 attestation_sink: None,
145 attestation_source: None,
146 passphrase_provider: None,
147 uuid_provider: None,
148 agent_signing: None,
149 }
150 }
151}
152
153pub struct Missing;
155
156pub struct Set<T>(T);
158
159pub struct AuthsContextBuilder<R, K, C> {
165 registry: R,
166 key_storage: K,
167 clock: C,
168 event_sink: Option<Arc<dyn EventSink>>,
169 identity_storage: Option<Arc<dyn IdentityStorage + Send + Sync>>,
170 attestation_sink: Option<Arc<dyn AttestationSink + Send + Sync>>,
171 attestation_source: Option<Arc<dyn AttestationSource + Send + Sync>>,
172 passphrase_provider: Option<Arc<dyn PassphraseProvider + Send + Sync>>,
173 uuid_provider: Option<Arc<dyn UuidProvider + Send + Sync>>,
174 agent_signing: Option<Arc<dyn AgentSigningPort + Send + Sync>>,
175}
176
177impl<K, C> AuthsContextBuilder<Missing, K, C> {
178 pub fn registry(
188 self,
189 registry: Arc<dyn RegistryBackend + Send + Sync>,
190 ) -> AuthsContextBuilder<Set<Arc<dyn RegistryBackend + Send + Sync>>, K, C> {
191 AuthsContextBuilder {
192 registry: Set(registry),
193 key_storage: self.key_storage,
194 clock: self.clock,
195 event_sink: self.event_sink,
196 identity_storage: self.identity_storage,
197 attestation_sink: self.attestation_sink,
198 attestation_source: self.attestation_source,
199 passphrase_provider: self.passphrase_provider,
200 uuid_provider: self.uuid_provider,
201 agent_signing: self.agent_signing,
202 }
203 }
204}
205
206impl<R, C> AuthsContextBuilder<R, Missing, C> {
207 pub fn key_storage(
217 self,
218 key_storage: Arc<dyn KeyStorage + Send + Sync>,
219 ) -> AuthsContextBuilder<R, Set<Arc<dyn KeyStorage + Send + Sync>>, C> {
220 AuthsContextBuilder {
221 registry: self.registry,
222 key_storage: Set(key_storage),
223 clock: self.clock,
224 event_sink: self.event_sink,
225 identity_storage: self.identity_storage,
226 attestation_sink: self.attestation_sink,
227 attestation_source: self.attestation_source,
228 passphrase_provider: self.passphrase_provider,
229 uuid_provider: self.uuid_provider,
230 agent_signing: self.agent_signing,
231 }
232 }
233}
234
235impl<R, K> AuthsContextBuilder<R, K, Missing> {
236 pub fn clock(
247 self,
248 clock: Arc<dyn ClockProvider + Send + Sync>,
249 ) -> AuthsContextBuilder<R, K, Set<Arc<dyn ClockProvider + Send + Sync>>> {
250 AuthsContextBuilder {
251 registry: self.registry,
252 key_storage: self.key_storage,
253 clock: Set(clock),
254 event_sink: self.event_sink,
255 identity_storage: self.identity_storage,
256 attestation_sink: self.attestation_sink,
257 attestation_source: self.attestation_source,
258 passphrase_provider: self.passphrase_provider,
259 uuid_provider: self.uuid_provider,
260 agent_signing: self.agent_signing,
261 }
262 }
263}
264
265impl<R, K, C> AuthsContextBuilder<R, K, C> {
266 pub fn event_sink(self, sink: Arc<dyn EventSink>) -> AuthsContextBuilder<R, K, C> {
278 AuthsContextBuilder {
279 registry: self.registry,
280 key_storage: self.key_storage,
281 clock: self.clock,
282 event_sink: Some(sink),
283 identity_storage: self.identity_storage,
284 attestation_sink: self.attestation_sink,
285 attestation_source: self.attestation_source,
286 passphrase_provider: self.passphrase_provider,
287 uuid_provider: self.uuid_provider,
288 agent_signing: self.agent_signing,
289 }
290 }
291
292 pub fn identity_storage(
302 self,
303 storage: Arc<dyn IdentityStorage + Send + Sync>,
304 ) -> AuthsContextBuilder<R, K, C> {
305 AuthsContextBuilder {
306 registry: self.registry,
307 key_storage: self.key_storage,
308 clock: self.clock,
309 event_sink: self.event_sink,
310 identity_storage: Some(storage),
311 attestation_sink: self.attestation_sink,
312 attestation_source: self.attestation_source,
313 passphrase_provider: self.passphrase_provider,
314 uuid_provider: self.uuid_provider,
315 agent_signing: self.agent_signing,
316 }
317 }
318
319 pub fn attestation_sink(
329 self,
330 sink: Arc<dyn AttestationSink + Send + Sync>,
331 ) -> AuthsContextBuilder<R, K, C> {
332 AuthsContextBuilder {
333 registry: self.registry,
334 key_storage: self.key_storage,
335 clock: self.clock,
336 event_sink: self.event_sink,
337 identity_storage: self.identity_storage,
338 attestation_sink: Some(sink),
339 attestation_source: self.attestation_source,
340 passphrase_provider: self.passphrase_provider,
341 uuid_provider: self.uuid_provider,
342 agent_signing: self.agent_signing,
343 }
344 }
345
346 pub fn attestation_source(
356 self,
357 source: Arc<dyn AttestationSource + Send + Sync>,
358 ) -> AuthsContextBuilder<R, K, C> {
359 AuthsContextBuilder {
360 registry: self.registry,
361 key_storage: self.key_storage,
362 clock: self.clock,
363 event_sink: self.event_sink,
364 identity_storage: self.identity_storage,
365 attestation_sink: self.attestation_sink,
366 attestation_source: Some(source),
367 passphrase_provider: self.passphrase_provider,
368 uuid_provider: self.uuid_provider,
369 agent_signing: self.agent_signing,
370 }
371 }
372
373 pub fn passphrase_provider(
386 self,
387 provider: Arc<dyn PassphraseProvider + Send + Sync>,
388 ) -> AuthsContextBuilder<R, K, C> {
389 AuthsContextBuilder {
390 registry: self.registry,
391 key_storage: self.key_storage,
392 clock: self.clock,
393 event_sink: self.event_sink,
394 identity_storage: self.identity_storage,
395 attestation_sink: self.attestation_sink,
396 attestation_source: self.attestation_source,
397 passphrase_provider: Some(provider),
398 uuid_provider: self.uuid_provider,
399 agent_signing: self.agent_signing,
400 }
401 }
402
403 pub fn uuid_provider(
416 self,
417 provider: Arc<dyn UuidProvider + Send + Sync>,
418 ) -> AuthsContextBuilder<R, K, C> {
419 AuthsContextBuilder {
420 registry: self.registry,
421 key_storage: self.key_storage,
422 clock: self.clock,
423 event_sink: self.event_sink,
424 identity_storage: self.identity_storage,
425 attestation_sink: self.attestation_sink,
426 attestation_source: self.attestation_source,
427 passphrase_provider: self.passphrase_provider,
428 uuid_provider: Some(provider),
429 agent_signing: self.agent_signing,
430 }
431 }
432
433 pub fn agent_signing(
447 self,
448 provider: Arc<dyn AgentSigningPort + Send + Sync>,
449 ) -> AuthsContextBuilder<R, K, C> {
450 AuthsContextBuilder {
451 registry: self.registry,
452 key_storage: self.key_storage,
453 clock: self.clock,
454 event_sink: self.event_sink,
455 identity_storage: self.identity_storage,
456 attestation_sink: self.attestation_sink,
457 attestation_source: self.attestation_source,
458 passphrase_provider: self.passphrase_provider,
459 uuid_provider: self.uuid_provider,
460 agent_signing: Some(provider),
461 }
462 }
463}
464
465impl
466 AuthsContextBuilder<
467 Set<Arc<dyn RegistryBackend + Send + Sync>>,
468 Set<Arc<dyn KeyStorage + Send + Sync>>,
469 Set<Arc<dyn ClockProvider + Send + Sync>>,
470 >
471{
472 pub fn build(self) -> Result<AuthsContext, BuilderError> {
486 Ok(AuthsContext {
487 registry: self.registry.0,
488 key_storage: self.key_storage.0,
489 clock: self.clock.0,
490 event_sink: self.event_sink.unwrap_or_else(|| Arc::new(NoopSink)),
491 identity_storage: self
492 .identity_storage
493 .ok_or(BuilderError("identity_storage"))?,
494 attestation_sink: self
495 .attestation_sink
496 .ok_or(BuilderError("attestation_sink"))?,
497 attestation_source: self
498 .attestation_source
499 .ok_or(BuilderError("attestation_source"))?,
500 passphrase_provider: self
501 .passphrase_provider
502 .unwrap_or_else(|| Arc::new(NoopPassphraseProvider)),
503 uuid_provider: self
504 .uuid_provider
505 .unwrap_or_else(|| Arc::new(SystemUuidProvider)),
506 agent_signing: self
507 .agent_signing
508 .unwrap_or_else(|| Arc::new(NoopAgentProvider)),
509 })
510 }
511}