cli: `rad self` improvements

* Add `--home` flag
* Organize the information better

Now looks like this:

    DID             did🔑z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
    └╴Node ID (NID) z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
    SSH             running (823)
    ├╴Key (hash)    SHA256:UIedaL6Cxm6OUErh9GQUzzglSk7VpQlVTI1TAFB/HWA
    └╴Key (full)    ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2YNH1
    Home            [..]
    ├╴Storage       [..]/storage
    ├╴Keys          [..]/keys
    └╴Node          [..]/node
This commit is contained in:
Alexis Sellier 2023-06-30 14:02:44 +02:00
parent 613e3e5269
commit 0f3212a1b2
No known key found for this signature in database
6 changed files with 62 additions and 28 deletions

View File

@ -7,7 +7,7 @@ $ rad auth
Initializing your radicle 👾 identity Initializing your radicle 👾 identity
✓ Creating your Ed25519 keypair... ✓ Creating your Ed25519 keypair...
✓ Your Radicle ID is did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi. This identifies your device. ✓ Your Radicle DID is did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi. This identifies your device.
To create a radicle project, run `rad init` from a git repository. To create a radicle project, run `rad init` from a git repository.
``` ```
@ -15,12 +15,6 @@ To create a radicle project, run `rad init` from a git repository.
You can get the above information at all times using the `self` command: You can get the above information at all times using the `self` command:
``` ```
$ rad self $ rad self --did
DID did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
Node ID (NID) z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
Key (hash) SHA256:UIedaL6Cxm6OUErh9GQUzzglSk7VpQlVTI1TAFB/HWA
Key (full) ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2YNH1
Storage (git) [..]/storage
Storage (keys) [..]/keys
Node (socket) [..]/node/control.sock
``` ```

View File

@ -3,13 +3,15 @@ device and node.
``` ```
$ rad self $ rad self
DID did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi DID did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
Node ID (NID) z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi └╴Node ID (NID) z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
Key (hash) SHA256:UIedaL6Cxm6OUErh9GQUzzglSk7VpQlVTI1TAFB/HWA SSH not running
Key (full) ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2YNH1 ├╴Key (hash) SHA256:UIedaL6Cxm6OUErh9GQUzzglSk7VpQlVTI1TAFB/HWA
Storage (git) [..] └╴Key (full) ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2YNH1
Storage (keys) [..] Home [..]/home/alice/.radicle
Node (socket) [..] ├╴Storage [..]/home/alice/.radicle/storage
├╴Keys [..]/home/alice/.radicle/keys
└╴Node [..]/home/alice/.radicle/node
``` ```
If you need to display only your DID, Node ID, or SSH Public Key, you can use If you need to display only your DID, Node ID, or SSH Public Key, you can use
@ -29,3 +31,8 @@ z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
$ rad self --ssh-key $ rad self --ssh-key
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2YNH1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2YNH1
``` ```
```
$ rad self --home
[..]/home/alice/.radicle
```

View File

@ -106,7 +106,7 @@ pub fn init(options: Options) -> anyhow::Result<()> {
} }
term::success!( term::success!(
"Your Radicle ID is {}. This identifies your device.", "Your Radicle DID is {}. This identifies your device.",
term::format::highlight(profile.did()) term::format::highlight(profile.did())
); );

View File

@ -20,6 +20,7 @@ Options
--nid Show your Node ID (NID) --nid Show your Node ID (NID)
--did Show your DID --did Show your DID
--home Show your Radicle home
--ssh-key Show your public key in OpenSSH format --ssh-key Show your public key in OpenSSH format
--ssh-fingerprint Show your public key fingerprint in OpenSSH format --ssh-fingerprint Show your public key fingerprint in OpenSSH format
--help Show help --help Show help
@ -30,6 +31,7 @@ Options
enum Show { enum Show {
NodeId, NodeId,
Did, Did,
Home,
SshKey, SshKey,
SshFingerprint, SshFingerprint,
All, All,
@ -55,6 +57,9 @@ impl Args for Options {
Long("did") if show.is_none() => { Long("did") if show.is_none() => {
show = Some(Show::Did); show = Some(Show::Did);
} }
Long("home") if show.is_none() => {
show = Some(Show::Home);
}
Long("ssh-key") if show.is_none() => { Long("ssh-key") if show.is_none() => {
show = Some(Show::SshKey); show = Some(Show::SshKey);
} }
@ -87,6 +92,9 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
Show::Did => { Show::Did => {
term::print(profile.did()); term::print(profile.did());
} }
Show::Home => {
term::print(profile.home().display());
}
Show::SshKey => { Show::SshKey => {
term::print(ssh::fmt::key(profile.id())); term::print(ssh::fmt::key(profile.id()));
} }
@ -110,38 +118,56 @@ fn all(profile: &Profile) -> anyhow::Result<()> {
let node_id = profile.id(); let node_id = profile.id();
table.push([ table.push([
term::format::style("Node ID (NID)").to_string(), term::format::style("└╴Node ID (NID)").to_string(),
term::format::tertiary(node_id).to_string(), term::format::tertiary(node_id).to_string(),
]); ]);
let ssh_agent = match ssh::agent::Agent::connect() {
Ok(c) => term::format::positive(format!(
"running ({})",
c.pid().map(|p| p.to_string()).unwrap_or(String::from("?"))
)),
Err(e) if e.is_not_running() => term::format::yellow(String::from("not running")),
Err(e) => term::format::negative(format!("error: {e}")),
};
table.push([
term::format::style("SSH").to_string(),
ssh_agent.to_string(),
]);
let ssh_short = ssh::fmt::fingerprint(node_id); let ssh_short = ssh::fmt::fingerprint(node_id);
table.push([ table.push([
term::format::style("Key (hash)").to_string(), term::format::style("├╴Key (hash)").to_string(),
term::format::tertiary(ssh_short).to_string(), term::format::tertiary(ssh_short).to_string(),
]); ]);
let ssh_long = ssh::fmt::key(node_id); let ssh_long = ssh::fmt::key(node_id);
table.push([ table.push([
term::format::style("Key (full)").to_string(), term::format::style("└╴Key (full)").to_string(),
term::format::tertiary(ssh_long).to_string(), term::format::tertiary(ssh_long).to_string(),
]); ]);
let home = profile.home();
table.push([
term::format::style("Home").to_string(),
term::format::tertiary(home.display()).to_string(),
]);
let storage_path = profile.home.storage(); let storage_path = profile.home.storage();
table.push([ table.push([
term::format::style("Storage (git)").to_string(), term::format::style("├╴Storage").to_string(),
term::format::tertiary(storage_path.display()).to_string(), term::format::tertiary(storage_path.display()).to_string(),
]); ]);
let keys_path = profile.home.keys(); let keys_path = profile.home.keys();
table.push([ table.push([
term::format::style("Storage (keys)").to_string(), term::format::style("├╴Keys").to_string(),
term::format::tertiary(keys_path.display()).to_string(), term::format::tertiary(keys_path.display()).to_string(),
]); ]);
let socket_path = profile.socket();
table.push([ table.push([
term::format::style("Node (socket)").to_string(), term::format::style("└╴Node").to_string(),
term::format::tertiary(socket_path.display()).to_string(), term::format::tertiary(profile.home.node().display()).to_string(),
]); ]);
table.print(); table.print();

View File

@ -90,7 +90,7 @@ impl Environment {
/// Create a new profile in this environment. /// Create a new profile in this environment.
/// This should be used when a running node is not required. /// This should be used when a running node is not required.
pub fn profile(&mut self, name: &str) -> Profile { pub fn profile(&mut self, name: &str) -> Profile {
let home = Home::new(self.tmp().join("home").join(name)).unwrap(); let home = Home::new(self.tmp().join("home").join(name).join(".radicle")).unwrap();
let storage = Storage::open(home.storage()).unwrap(); let storage = Storage::open(home.storage()).unwrap();
let keystore = Keystore::new(&home.keys()); let keystore = Keystore::new(&home.keys());
let keypair = KeyPair::from_seed(Seed::from([!(self.users as u8); 32])); let keypair = KeyPair::from_seed(Seed::from([!(self.users as u8); 32]));

View File

@ -3,6 +3,7 @@ use std::io::{Read, Write};
use std::ops::DerefMut; use std::ops::DerefMut;
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
use std::path::Path; use std::path::Path;
use std::str::FromStr;
use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
use log::*; use log::*;
@ -51,12 +52,18 @@ pub struct AgentClient<S> {
stream: S, stream: S,
} }
// https://tools.ietf.org/html/draft-miller-ssh-agent-00#section-4.1
impl<S> AgentClient<S> { impl<S> AgentClient<S> {
/// Connect to an SSH agent via the provided stream (on Unix, usually a Unix-domain socket). /// Connect to an SSH agent via the provided stream (on Unix, usually a Unix-domain socket).
pub fn connect(stream: S) -> Self { pub fn connect(stream: S) -> Self {
AgentClient { stream } AgentClient { stream }
} }
/// Get the agent PID.
pub fn pid(&self) -> Option<u32> {
std::env::var("SSH_AGENT_PID")
.ok()
.and_then(|v| u32::from_str(&v).ok())
}
} }
pub trait ClientStream: Sized + Send + Sync { pub trait ClientStream: Sized + Send + Sync {
@ -76,7 +83,7 @@ pub trait ClientStream: Sized + Send + Sync {
Err(Error::Io(io_err)) if io_err.kind() == std::io::ErrorKind::NotFound => { Err(Error::Io(io_err)) if io_err.kind() == std::io::ErrorKind::NotFound => {
Err(Error::BadAuthSock) Err(Error::BadAuthSock)
} }
err => err, other => other,
} }
} }
} }