Skip to main content

auths_cli/commands/id/
register.rs

1use std::path::Path;
2use std::sync::Arc;
3
4use anyhow::{Result, bail};
5use serde::Serialize;
6
7use auths_id::ports::registry::RegistryBackend;
8use auths_id::storage::attestation::AttestationSource;
9use auths_id::storage::identity::IdentityStorage;
10use auths_infra_http::HttpRegistryClient;
11use auths_sdk::error::RegistrationError;
12pub use auths_sdk::registration::DEFAULT_REGISTRY_URL;
13use auths_sdk::result::RegistrationOutcome;
14use auths_storage::git::{
15    GitRegistryBackend, RegistryAttestationStorage, RegistryConfig, RegistryIdentityStorage,
16};
17
18use crate::ux::format::{JsonResponse, Output, is_json_mode};
19
20#[derive(Serialize)]
21struct RegisterJsonResponse {
22    did_prefix: String,
23    registry: String,
24    platform_claims_indexed: usize,
25}
26
27/// Publishes a local identity to a registry for public discovery.
28///
29/// Args:
30/// * `repo_path`: Path to the local identity repository.
31/// * `registry`: Base URL of the target registry.
32///
33/// Usage:
34/// ```ignore
35/// handle_register(&repo_path, "https://public.auths.dev")?;
36/// ```
37pub fn handle_register(repo_path: &Path, registry: &str) -> Result<()> {
38    let rt = tokio::runtime::Runtime::new()?;
39
40    let backend: Arc<dyn RegistryBackend + Send + Sync> = Arc::new(
41        GitRegistryBackend::from_config_unchecked(RegistryConfig::single_tenant(repo_path)),
42    );
43    let identity_storage: Arc<dyn IdentityStorage + Send + Sync> =
44        Arc::new(RegistryIdentityStorage::new(repo_path.to_path_buf()));
45    let attestation_store = Arc::new(RegistryAttestationStorage::new(repo_path));
46    let attestation_source: Arc<dyn AttestationSource + Send + Sync> = attestation_store;
47
48    let registry_client = HttpRegistryClient::new();
49
50    match rt.block_on(auths_sdk::registration::register_identity(
51        identity_storage,
52        backend,
53        attestation_source,
54        registry,
55        None,
56        &registry_client,
57    )) {
58        Ok(outcome) => display_registration_result(&outcome),
59        Err(RegistrationError::AlreadyRegistered) => {
60            bail!("Identity already registered at this registry.");
61        }
62        Err(RegistrationError::QuotaExceeded) => {
63            bail!("Registration quota exceeded. Try again next month or use a paid tier.");
64        }
65        Err(RegistrationError::NetworkError(e)) => {
66            bail!("Failed to connect to registry server: {e}");
67        }
68        Err(RegistrationError::LocalDataError(e)) => {
69            bail!("{e}");
70        }
71        Err(e) => {
72            bail!("Registration failed: {e}");
73        }
74    }
75}
76
77fn display_registration_result(outcome: &RegistrationOutcome) -> Result<()> {
78    if is_json_mode() {
79        let json_resp = JsonResponse::success(
80            "id register",
81            RegisterJsonResponse {
82                did_prefix: outcome.did_prefix.clone(),
83                registry: outcome.registry.clone(),
84                platform_claims_indexed: outcome.platform_claims_indexed,
85            },
86        );
87        json_resp.print()?;
88    } else {
89        let out = Output::stdout();
90        println!(
91            "{} Identity registered at {}",
92            out.success("Success!"),
93            out.bold(&outcome.registry)
94        );
95        println!("DID: {}", out.info(&outcome.did_prefix));
96        if outcome.platform_claims_indexed > 0 {
97            println!(
98                "Platform claims indexed: {}",
99                outcome.platform_claims_indexed
100            );
101        }
102        println!();
103        println!(
104            "{}",
105            out.bold("Next step: Anchor a cryptographic attestation for your code")
106        );
107        println!(
108            "Run: {}",
109            out.dim(
110                "auths artifact publish --signature <path-to.auths.json> --package <ecosystem:name>"
111            )
112        );
113    }
114    Ok(())
115}