use std::path::Path;
use anyhow::Result;
use cdk::mint_url::MintUrl;
use cdk::nuts::MintInfo;
use cdk::wallet::WalletRepository;
use cdk::OidcClient;
use clap::Args;
use serde::{Deserialize, Serialize};
use crate::token_storage;
#[derive(Args, Serialize, Deserialize)]
pub struct CatLoginSubCommand {
mint_url: MintUrl,
username: String,
password: String,
}
pub async fn cat_login(
wallet_repository: &WalletRepository,
sub_command_args: &CatLoginSubCommand,
work_dir: &Path,
) -> Result<()> {
let mint_url = sub_command_args.mint_url.clone();
if !wallet_repository.has_mint(&mint_url).await {
wallet_repository.add_wallet(mint_url.clone()).await?;
}
let mint_info = wallet_repository.fetch_mint_info(&mint_url).await?;
let (access_token, refresh_token) = get_access_token(
&mint_info,
&sub_command_args.username,
&sub_command_args.password,
)
.await;
if let Err(e) =
token_storage::save_tokens(work_dir, &mint_url, &access_token, &refresh_token).await
{
println!("Warning: Failed to save tokens to file: {e}");
} else {
println!("Tokens saved to work directory");
}
println!("\nAuthentication successful! 🎉\n");
println!("\nYour tokens:");
println!("access_token: {access_token}");
println!("refresh_token: {refresh_token}");
Ok(())
}
async fn get_access_token(mint_info: &MintInfo, user: &str, password: &str) -> (String, String) {
let openid_discovery = mint_info
.nuts
.nut21
.clone()
.expect("Nut21 defined")
.openid_discovery;
let client_id = mint_info
.nuts
.nut21
.clone()
.expect("Nut21 defined")
.client_id;
let oidc_client = OidcClient::new(openid_discovery, None);
let token_url = oidc_client
.get_oidc_config()
.await
.expect("Failed to get OIDC config")
.token_endpoint;
let params = [
("grant_type", "password"),
("client_id", &client_id),
("scope", "openid offline_access"),
("username", user),
("password", password),
];
let client = cdk_common::HttpClient::new();
let token_response: serde_json::Value = client
.post_form(&token_url, ¶ms)
.await
.expect("Failed to send token request");
let access_token = token_response["access_token"]
.as_str()
.expect("No access token in response")
.to_string();
let refresh_token = token_response["refresh_token"]
.as_str()
.expect("No refresh token in response")
.to_string();
(access_token, refresh_token)
}