Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
crypto: shared agent stream
Merged fintohaps opened 1 year ago

The Mutex within AgentSigner did not seem to make sense. The Mutex could never be shared, since the structs could never be cloned.

It would make more sense to have an Arc<Mutex<AgentClient<Stream>>> within Agent, which could then be shared and cloned when constructing the AgentSigner.

2 files changed +30 -23 62d000f7 3b5fac17
modified radicle-crypto/src/ssh/agent.rs
@@ -1,5 +1,4 @@
-
use std::ops::{Deref, DerefMut};
-
use std::sync::Mutex;
+
use std::sync::{Arc, Mutex};

pub use radicle_ssh::agent::client::AgentClient;
pub use radicle_ssh::agent::client::Error;
@@ -12,56 +11,63 @@ pub use std::net::TcpStream as Stream;
#[cfg(unix)]
pub use std::os::unix::net::UnixStream as Stream;

+
#[derive(Clone)]
pub struct Agent {
-
    client: AgentClient<Stream>,
+
    client: Arc<Mutex<AgentClient<Stream>>>,
}

impl Agent {
    /// Connect to a running SSH agent.
    pub fn connect() -> Result<Self, ssh::agent::client::Error> {
-
        Stream::connect_env().map(|client| Self { client })
+
        Stream::connect_env().map(|client| Self {
+
            client: Arc::new(Mutex::new(client)),
+
        })
    }

    /// Register a key with the agent.
    pub fn register(&mut self, key: &SecretKey) -> Result<(), ssh::Error> {
-
        self.client.add_identity(key, &[])
+
        self.client.lock().unwrap().add_identity(key, &[])
    }

-
    /// Get a signer from this agent, given the public key.
-
    pub fn signer(self, key: PublicKey) -> AgentSigner {
-
        AgentSigner::new(self, key)
+
    pub fn unregister(&mut self, key: &PublicKey) -> Result<(), ssh::Error> {
+
        self.client.lock().unwrap().remove_identity(key)
    }
-
}

-
impl Deref for Agent {
-
    type Target = AgentClient<Stream>;
+
    pub fn unregister_all(&mut self) -> Result<(), ssh::Error> {
+
        self.client.lock().unwrap().remove_all_identities()
+
    }

-
    fn deref(&self) -> &Self::Target {
-
        &self.client
+
    pub fn sign(&self, key: &PublicKey, data: &[u8]) -> Result<[u8; 64], ssh::Error> {
+
        self.client.lock().unwrap().sign(key, data)
+
    }
+

+
    /// Get a signer from this agent, given the public key.
+
    pub fn signer(&self, key: PublicKey) -> AgentSigner {
+
        AgentSigner::new(self.clone(), key)
    }
-
}

-
impl DerefMut for Agent {
-
    fn deref_mut(&mut self) -> &mut Self::Target {
-
        &mut self.client
+
    pub fn pid(&self) -> Option<u32> {
+
        self.client.lock().unwrap().pid()
+
    }
+

+
    pub fn request_identities(&self) -> Result<Vec<PublicKey>, ssh::agent::client::Error> {
+
        self.client.lock().unwrap().request_identities()
    }
}

/// A [`Signer`] that uses `ssh-agent`.
pub struct AgentSigner {
-
    agent: Mutex<Agent>,
+
    agent: Agent,
    public: PublicKey,
}

impl AgentSigner {
    pub fn new(agent: Agent, public: PublicKey) -> Self {
-
        let agent = Mutex::new(agent);
-

        Self { agent, public }
    }

    pub fn is_ready(&self) -> Result<bool, Error> {
-
        let ids = self.agent.lock().unwrap().request_identities()?;
+
        let ids = self.agent.client.lock().unwrap().request_identities()?;

        Ok(ids.contains(&self.public))
    }
@@ -84,6 +90,7 @@ impl Signer for AgentSigner {
    fn try_sign(&self, msg: &[u8]) -> Result<Signature, SignerError> {
        let sig = self
            .agent
+
            .client
            .lock()
            // We'll take our chances here; the worse that can happen is the agent returns an error.
            .unwrap_or_else(|e| e.into_inner())
modified radicle-tools/src/rad-agent.rs
@@ -28,11 +28,11 @@ fn main() -> anyhow::Result<()> {
            println!("ok");
        }
        Some("remove") => {
-
            agent.remove_identity(profile.id())?;
+
            agent.unregister(profile.id())?;
            println!("ok");
        }
        Some("remove-all") => {
-
            agent.remove_all_identities()?;
+
            agent.unregister_all()?;
            println!("ok");
        }
        Some("sign") => {