Skip to main content

auths_cli/commands/id/
claim.rs

1use std::path::Path;
2use std::sync::Arc;
3
4use anyhow::{Context, Result};
5use auths_core::config::EnvironmentConfig;
6use auths_core::signing::PassphraseProvider;
7use auths_infra_http::{HttpGistPublisher, HttpGitHubOAuthProvider, HttpRegistryClaimClient};
8use auths_sdk::workflows::platform::{GitHubClaimConfig, claim_github_identity};
9use chrono::Utc;
10use clap::{Parser, Subcommand};
11use console::style;
12
13use crate::factories::storage::build_auths_context;
14use crate::ux::format::{JsonResponse, is_json_mode};
15
16use super::register::DEFAULT_REGISTRY_URL;
17
18const DEFAULT_GITHUB_CLIENT_ID: &str = "Ov23lio2CiTHBjM2uIL4";
19
20fn github_client_id() -> String {
21    std::env::var("AUTHS_GITHUB_CLIENT_ID").unwrap_or_else(|_| DEFAULT_GITHUB_CLIENT_ID.to_string())
22}
23
24#[derive(Parser, Debug, Clone)]
25#[command(about = "Add a platform claim to an already-registered identity.")]
26pub struct ClaimCommand {
27    #[command(subcommand)]
28    pub platform: ClaimPlatform,
29
30    #[arg(long, default_value = DEFAULT_REGISTRY_URL)]
31    pub registry: String,
32}
33
34#[derive(Subcommand, Debug, Clone)]
35pub enum ClaimPlatform {
36    /// Link your GitHub account to your identity.
37    Github,
38}
39
40pub fn handle_claim(
41    cmd: &ClaimCommand,
42    repo_path: &Path,
43    passphrase_provider: Arc<dyn PassphraseProvider + Send + Sync>,
44    env_config: &EnvironmentConfig,
45) -> Result<()> {
46    let ctx = build_auths_context(repo_path, env_config, Some(passphrase_provider))
47        .context("Failed to build auths context")?;
48
49    let oauth = HttpGitHubOAuthProvider::new();
50    let publisher = HttpGistPublisher::new();
51    let registry_client = HttpRegistryClaimClient::new();
52
53    let config = GitHubClaimConfig {
54        client_id: github_client_id(),
55        registry_url: cmd.registry.clone(),
56        scopes: "read:user gist".to_string(),
57    };
58
59    let on_device_code = |code: &auths_core::ports::platform::DeviceCodeResponse| {
60        println!();
61        println!(
62            "  Enter this code: {}",
63            style(&code.user_code).bold().cyan()
64        );
65        println!("  At: {}", style(&code.verification_uri).cyan());
66        println!();
67        if let Err(e) = open::that(&code.verification_uri) {
68            println!(
69                "  {}",
70                style(format!("Could not open browser: {e}")).yellow()
71            );
72            println!("  Please open the URL above manually.");
73        } else {
74            println!("  Browser opened — waiting for authorization...");
75        }
76    };
77
78    let rt = tokio::runtime::Runtime::new().context("failed to create async runtime")?;
79    let response = rt
80        .block_on(claim_github_identity(
81            &oauth,
82            &publisher,
83            &registry_client,
84            &ctx,
85            config,
86            Utc::now(),
87            &on_device_code,
88        ))
89        .map_err(|e| anyhow::anyhow!("{}", e))?;
90
91    if is_json_mode() {
92        let json_resp = JsonResponse::success("id claim", &response.message);
93        json_resp.print()?;
94    } else {
95        println!("  {}", style(&response.message).green());
96    }
97
98    Ok(())
99}