auths_cli/commands/id/
claim.rs1use 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 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 ®istry_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}