mod commands;
mod ui;
use clap::{Parser, Subcommand};
use colored::Colorize;
use syntarq_core::IdentityBuilder;
#[derive(Parser)]
#[command(name = "syntarq")]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
struct Cli {
#[command(subcommand)]
command: Commands,
#[arg(short, long, global = true)]
verbose: bool,
}
#[derive(Subcommand)]
enum Commands {
Init,
Info,
TestCrypto,
#[command(alias = "new")]
Create {
#[arg(short, long)]
name: Option<String>,
},
#[command(alias = "ls")]
List,
Show {
identity: String,
},
Link {
identity: String,
#[arg(short, long)]
service: String,
identifier: String,
},
Verify {
identity: String,
service: String,
},
Export {
identity: String,
#[arg(short, long)]
output: Option<String>,
},
Import {
file: String,
},
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let cli = Cli::parse();
init_logging(cli.verbose);
match cli.command {
Commands::Init => commands::init::run().await?,
Commands::Info => commands::info::run().await?,
Commands::TestCrypto => commands::test_crypto::run().await?,
Commands::Create { name } => create_identity(name).await?,
Commands::List => list_identities().await?,
Commands::Show { identity } => show_identity(&identity).await?,
Commands::Link {
identity,
service,
identifier,
} => link_service(&identity, &service, &identifier).await?,
Commands::Verify { identity, service } => verify_service(&identity, &service).await?,
Commands::Export { identity, output } => {
export_identity(&identity, output.as_deref()).await?
}
Commands::Import { file } => import_identity(&file).await?,
}
Ok(())
}
fn init_logging(verbose: bool) {
use tracing_subscriber::{fmt, EnvFilter};
let level = if verbose { "debug" } else { "info" };
fmt()
.with_env_filter(
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(level)),
)
.with_target(false)
.without_time()
.init();
}
async fn create_identity(name: Option<String>) -> anyhow::Result<()> {
println!("{}", "Creating new identity...".cyan().bold());
let name = if let Some(n) = name {
n
} else {
dialoguer::Input::new()
.with_prompt("Identity name")
.allow_empty(true)
.interact_text()?
};
let mut builder = IdentityBuilder::new();
if !name.is_empty() {
builder = builder.with_name(name);
}
let identity = builder.build()?;
println!("\n{}", "Identity created successfully!".green().bold());
println!("ID: {}", identity.id().to_string().yellow());
if let Some(name) = identity.name() {
println!("Name: {}", name.yellow());
}
println!(
"\nPublic key: {}",
hex::encode(identity.public_key().as_bytes()).dimmed()
);
Ok(())
}
async fn list_identities() -> anyhow::Result<()> {
println!("{}", "Listing identities...".cyan().bold());
println!(
"\n{}",
"No identities found. Use 'syntarq create' to create one.".dimmed()
);
Ok(())
}
async fn show_identity(identity: &str) -> anyhow::Result<()> {
println!(
"{} {}",
"Showing identity:".cyan().bold(),
identity.yellow()
);
println!("\n{}", "Identity not found.".red());
Ok(())
}
async fn link_service(_identity: &str, service: &str, identifier: &str) -> anyhow::Result<()> {
println!(
"{} {} {} {} {}",
"Linking".cyan().bold(),
service.yellow(),
"service".cyan(),
identifier.yellow(),
"to identity...".cyan()
);
println!("\n{}", "Feature not yet implemented.".dimmed());
Ok(())
}
async fn verify_service(identity: &str, service: &str) -> anyhow::Result<()> {
println!(
"{} {} {} {}",
"Verifying".cyan().bold(),
service.yellow(),
"service for identity".cyan(),
identity.yellow()
);
println!("\n{}", "Feature not yet implemented.".dimmed());
Ok(())
}
async fn export_identity(identity: &str, output: Option<&str>) -> anyhow::Result<()> {
println!(
"{} {}",
"Exporting identity:".cyan().bold(),
identity.yellow()
);
if let Some(path) = output {
println!("Output: {}", path.dimmed());
}
println!("\n{}", "Feature not yet implemented.".dimmed());
Ok(())
}
async fn import_identity(file: &str) -> anyhow::Result<()> {
println!(
"{} {}",
"Importing identity from:".cyan().bold(),
file.yellow()
);
println!("\n{}", "Feature not yet implemented.".dimmed());
Ok(())
}