Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
rad-remote-helper: honor RAD_PASSPHRASE
Slack Coder committed 3 years ago
commit 03bc9d84d692f2957eddf3baaf83ef328b83d597
parent 3682ef195b349c7752eb025f562f459284def238
2 files changed +34 -26
modified radicle-cli/src/terminal/io.rs
@@ -7,7 +7,7 @@ use radicle::cob::issue::Issue;
use radicle::cob::thread::CommentId;
use radicle::crypto::ssh::keystore::Passphrase;
use radicle::crypto::Signer;
-
use radicle::profile::env::RAD_PASSPHRASE;
+
use radicle::profile;
use radicle::profile::Profile;

use radicle_crypto::ssh::keystore::MemorySigner;
@@ -177,19 +177,16 @@ pub fn abort<D: fmt::Display>(prompt: D) -> bool {

/// Get the signer. First we try getting it from ssh-agent, otherwise we prompt the user.
pub fn signer(profile: &Profile) -> anyhow::Result<Box<dyn Signer>> {
-
    let signer = if let Ok(passphrase) = read_passphrase_from_env_var() {
-
        MemorySigner::load(&profile.keystore, passphrase)?.boxed()
-
    } else if let Ok(signer) = profile.signer() {
-
        signer.boxed()
-
    } else {
-
        let passphrase = secret_input();
-
        let spinner = spinner("Unsealing key...");
-
        let signer = MemorySigner::load(&profile.keystore, passphrase)?;
+
    if let Ok(signer) = profile.signer() {
+
        return Ok(signer);
+
    }

-
        spinner.finish();
-
        signer.boxed()
-
    };
-
    Ok(signer)
+
    let passphrase = secret_input();
+
    let spinner = spinner("Unsealing key...");
+
    let signer = MemorySigner::load(&profile.keystore, passphrase)?;
+

+
    spinner.finish();
+
    Ok(signer.boxed())
}

pub fn theme() -> ColorfulTheme {
@@ -313,9 +310,9 @@ pub fn secret_stdin() -> Result<Passphrase, anyhow::Error> {
}

pub fn read_passphrase(stdin: bool, confirm: bool) -> Result<Passphrase, anyhow::Error> {
-
    let passphrase = match read_passphrase_from_env_var() {
-
        Ok(input) => input,
-
        _ => {
+
    let passphrase = match profile::env::read_passphrase() {
+
        Some(input) => input,
+
        None => {
            if stdin {
                secret_stdin()?
            } else if confirm {
@@ -329,12 +326,6 @@ pub fn read_passphrase(stdin: bool, confirm: bool) -> Result<Passphrase, anyhow:
    Ok(passphrase)
}

-
pub fn read_passphrase_from_env_var() -> Result<Passphrase, anyhow::Error> {
-
    let passphrase = std::env::var(RAD_PASSPHRASE)?;
-

-
    Ok(Passphrase::from(passphrase.trim_end().to_owned()))
-
}
-

pub fn select<'a, T>(options: &'a [T], active: &'a T) -> Option<&'a T>
where
    T: fmt::Display + Eq + PartialEq,
modified radicle/src/profile.rs
@@ -15,13 +15,15 @@ use std::path::{Path, PathBuf};

use thiserror::Error;

-
use crate::crypto::ssh::agent::{Agent, AgentSigner};
+
use crate::crypto::ssh::agent::Agent;
use crate::crypto::ssh::{Keystore, Passphrase};
-
use crate::crypto::PublicKey;
+
use crate::crypto::{PublicKey, Signer};
use crate::node;
use crate::storage::git::transport;
use crate::storage::git::Storage;

+
use radicle_crypto::ssh::keystore;
+

/// Environment variables used by radicle.
pub mod env {
    pub use std::env::*;
@@ -32,6 +34,14 @@ pub mod env {
    pub const RAD_SOCKET: &str = "RAD_SOCKET";
    /// Passphrase for the encrypted radicle secret key.
    pub const RAD_PASSPHRASE: &str = "RAD_PASSPHRASE";
+

+
    pub fn read_passphrase() -> Option<super::Passphrase> {
+
        let Ok(passphrase) = std::env::var(RAD_PASSPHRASE) else {
+
            return None;
+
        };
+

+
        Some(super::Passphrase::from(passphrase.trim_end().to_owned()))
+
    }
}

#[derive(Debug, Error)]
@@ -40,6 +50,8 @@ pub enum Error {
    Io(#[from] io::Error),
    #[error(transparent)]
    Keystore(#[from] crate::crypto::ssh::keystore::Error),
+
    #[error(transparent)]
+
    MemorySigner(#[from] keystore::MemorySignerError),
    #[error("no profile found at the filepath '{0}'")]
    NotFound(PathBuf),
    #[error("error connecting to ssh-agent: {0}")]
@@ -95,12 +107,17 @@ impl Profile {
        &self.public_key
    }

-
    pub fn signer(&self) -> Result<AgentSigner, Error> {
+
    pub fn signer(&self) -> Result<Box<dyn Signer>, Error> {
+
        if let Some(passphrase) = env::read_passphrase() {
+
            let signer = keystore::MemorySigner::load(&self.keystore, passphrase)?;
+
            return Ok(signer.boxed());
+
        }
+

        match Agent::connect() {
            Ok(agent) => {
                let signer = agent.signer(self.public_key);
                if signer.is_ready()? {
-
                    Ok(signer)
+
                    Ok(signer.boxed())
                } else {
                    Err(Error::KeyNotRegistered(self.public_key))
                }