rad-remote-helper: honor RAD_PASSPHRASE

Make testing more convenient by reducing rad-remote-helper's dependency
on SSH Agent.  It may be opted out of by setting the `RAD_PASSPHRASE`
environment variable.

Signed-off-by: Slack Coder <slackcoder@server.ky>
This commit is contained in:
Slack Coder 2023-01-03 15:27:50 -05:00 committed by Alexis Sellier
parent 3682ef195b
commit 03bc9d84d6
No known key found for this signature in database
2 changed files with 34 additions and 26 deletions

View File

@ -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,

View File

@ -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))
}