diff --git a/radicle-cli/examples/rad-auth.md b/radicle-cli/examples/rad-auth.md index 6967025b..57984d1c 100644 --- a/radicle-cli/examples/rad-auth.md +++ b/radicle-cli/examples/rad-auth.md @@ -7,6 +7,7 @@ $ rad auth Initializing your 🌱 profile and identity ✓ Creating your 🌱 Ed25519 keypair... +! Adding your radicle key to ssh-agent... ✓ Your Radicle ID is did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi. This identifies your device. 👉 To create a radicle project, run `rad init` from a git repository. diff --git a/radicle-cli/src/commands/auth.rs b/radicle-cli/src/commands/auth.rs index bdea54b7..0595dccb 100644 --- a/radicle-cli/src/commands/auth.rs +++ b/radicle-cli/src/commands/auth.rs @@ -4,6 +4,7 @@ use std::ffi::OsString; use anyhow::anyhow; use radicle::crypto::ssh; +use radicle::crypto::ssh::Passphrase; use radicle::{profile, Profile}; use crate::terminal as term; @@ -86,9 +87,16 @@ pub fn init(options: Options) -> anyhow::Result<()> { term::passphrase_confirm() }?; let spinner = term::spinner("Creating your 🌱 Ed25519 keypair..."); - let profile = Profile::init(home, passphrase)?; + let profile = Profile::init(home, passphrase.clone())?; spinner.finish(); + let spinner = term::spinner("Adding your radicle key to ssh-agent..."); + if register(&profile, passphrase).is_ok() { + spinner.finish(); + } else { + spinner.warn(); + } + term::success!( "Your Radicle ID is {}. This identifies your device.", term::format::highlight(profile.did()) @@ -124,12 +132,7 @@ pub fn authenticate(profile: &Profile, options: Options) -> anyhow::Result<()> { term::passphrase() }?; let spinner = term::spinner("Unlocking..."); - let mut agent = ssh::agent::Agent::connect()?; - let secret = profile - .keystore - .secret_key(passphrase)? - .ok_or_else(|| anyhow!("Key not found in {:?}", profile.keystore.path()))?; - agent.register(&secret)?; + register(profile, passphrase)?; spinner.finish(); term::success!("Radicle key added to ssh-agent"); @@ -139,3 +142,16 @@ pub fn authenticate(profile: &Profile, options: Options) -> anyhow::Result<()> { Ok(()) } + +/// Register key with ssh-agent. +pub fn register(profile: &Profile, passphrase: Passphrase) -> anyhow::Result<()> { + let mut agent = ssh::agent::Agent::connect()?; + let secret = profile + .keystore + .secret_key(passphrase)? + .ok_or_else(|| anyhow!("Key not found in {:?}", profile.keystore.path()))?; + + agent.register(&secret)?; + + Ok(()) +} diff --git a/radicle-cli/src/terminal/io.rs b/radicle-cli/src/terminal/io.rs index 96e72b39..4856ec1d 100644 --- a/radicle-cli/src/terminal/io.rs +++ b/radicle-cli/src/terminal/io.rs @@ -19,6 +19,7 @@ use super::Error; use super::{style, Paint}; pub const ERROR_PREFIX: Paint<&str> = Paint::red("✗"); +pub const WARNING_PREFIX: Paint<&str> = Paint::yellow("!"); pub const TAB: &str = " "; /// Render configuration. @@ -129,7 +130,7 @@ pub fn subcommand(msg: impl fmt::Display) { pub fn warning(warning: &str) { println!( "{} {} {warning}", - Paint::yellow("!"), + WARNING_PREFIX, Paint::yellow("Warning:").bold(), ); } diff --git a/radicle-cli/src/terminal/spinner.rs b/radicle-cli/src/terminal/spinner.rs index 02e3e5db..16d44474 100644 --- a/radicle-cli/src/terminal/spinner.rs +++ b/radicle-cli/src/terminal/spinner.rs @@ -3,7 +3,7 @@ use std::mem::ManuallyDrop; use std::sync::{Arc, Mutex}; use std::{fmt, io, thread, time}; -use crate::terminal::io::ERROR_PREFIX; +use crate::terminal::io::{ERROR_PREFIX, WARNING_PREFIX}; use crate::terminal::Paint; /// How much time to wait between spinner animation updates. @@ -34,6 +34,7 @@ enum State { Running { cursor: usize }, Canceled, Done, + Warn, Error, } @@ -84,6 +85,13 @@ impl Spinner { } } + /// Cancel the spinner with a warning sign. + pub fn warn(self) { + if let Ok(mut progress) = self.progress.lock() { + progress.state = State::Warn; + } + } + /// Set the spinner's message. pub fn message(&mut self, msg: impl fmt::Display) { let msg = msg.to_string(); @@ -150,6 +158,13 @@ pub fn spinner(message: impl ToString) -> Spinner { .ok(); break; } + Progress { + state: State::Warn, + message, + } => { + writeln!(stdout, "{WARNING_PREFIX} {message}").ok(); + break; + } Progress { state: State::Error, message,