feat: v1.10.7, add --json for piv-summary
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -487,7 +487,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.10.6"
|
version = "1.10.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"authenticator 0.3.1",
|
"authenticator 0.3.1",
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.10.6"
|
version = "1.10.7"
|
||||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||||
use rust_util::util_clap::{Command, CommandError};
|
use rust_util::util_clap::{Command, CommandError};
|
||||||
use rust_util::XResult;
|
use rust_util::{util_msg, XResult};
|
||||||
|
use serde::Serialize;
|
||||||
|
use serde_json::{Map, Value};
|
||||||
use spki::der::Encode;
|
use spki::der::Encode;
|
||||||
use tabled::{Table, Tabled};
|
|
||||||
use tabled::settings::Style;
|
use tabled::settings::Style;
|
||||||
|
use tabled::{Table, Tabled};
|
||||||
use x509_parser::parse_x509_certificate;
|
use x509_parser::parse_x509_certificate;
|
||||||
use yubikey::{Certificate, YubiKey};
|
|
||||||
use yubikey::piv::{metadata, SlotId};
|
use yubikey::piv::{metadata, SlotId};
|
||||||
|
use yubikey::{Certificate, YubiKey};
|
||||||
|
|
||||||
use crate::pivutil::{get_algorithm_id_by_certificate, ORDERED_SLOTS, ToStr};
|
use crate::pivutil::{get_algorithm_id_by_certificate, ToStr, ORDERED_SLOTS};
|
||||||
|
|
||||||
const NA: &str = "N/A";
|
const NA: &str = "N/A";
|
||||||
|
|
||||||
#[derive(Tabled)]
|
#[derive(Tabled, Serialize)]
|
||||||
struct PivSlot {
|
struct PivSlot {
|
||||||
name: String,
|
name: String,
|
||||||
id: String,
|
id: String,
|
||||||
@@ -33,6 +35,7 @@ impl Command for CommandImpl {
|
|||||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||||
SubCommand::with_name(self.name()).about("PIV subcommand")
|
SubCommand::with_name(self.name()).about("PIV subcommand")
|
||||||
.arg(Arg::with_name("table").long("table").help("Show table"))
|
.arg(Arg::with_name("table").long("table").help("Show table"))
|
||||||
|
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
||||||
.arg(Arg::with_name("all").long("all").help("Show all"))
|
.arg(Arg::with_name("all").long("all").help("Show all"))
|
||||||
.arg(Arg::with_name("ordered").long("ordered").help("Show ordered"))
|
.arg(Arg::with_name("ordered").long("ordered").help("Show ordered"))
|
||||||
}
|
}
|
||||||
@@ -41,45 +44,69 @@ impl Command for CommandImpl {
|
|||||||
let show_table = sub_arg_matches.is_present("table");
|
let show_table = sub_arg_matches.is_present("table");
|
||||||
let show_all = sub_arg_matches.is_present("all");
|
let show_all = sub_arg_matches.is_present("all");
|
||||||
let show_ordered = sub_arg_matches.is_present("ordered");
|
let show_ordered = sub_arg_matches.is_present("ordered");
|
||||||
|
let json_output = sub_arg_matches.is_present("json");
|
||||||
|
if json_output { util_msg::set_logger_std_out(false); }
|
||||||
|
|
||||||
|
let mut output = Map::new();
|
||||||
let mut yk = opt_result!(YubiKey::open(), "YubiKey not found: {}");
|
let mut yk = opt_result!(YubiKey::open(), "YubiKey not found: {}");
|
||||||
|
|
||||||
success!("Name: {}", yk.name());
|
success!("Name: {}", yk.name());
|
||||||
information!("Version: {}", yk.version());
|
information!("Version: {}", yk.version());
|
||||||
information!("Serial: {}", yk.serial());
|
information!("Serial: {}", yk.serial());
|
||||||
|
output.insert("name".to_string(), Value::String(yk.name().to_string()));
|
||||||
|
output.insert("version".to_string(), Value::String(yk.version().to_string()));
|
||||||
|
output.insert("serial".to_string(), Value::String(yk.serial().to_string()));
|
||||||
|
|
||||||
match yk.chuid() {
|
match yk.chuid() {
|
||||||
Ok(chuid) => information!("CHUID: {}",chuid.to_string()),
|
Ok(chuid) => {
|
||||||
|
information!("CHUID: {}",chuid.to_string());
|
||||||
|
output.insert("chuid".to_string(), Value::String(chuid.to_string()));
|
||||||
|
}
|
||||||
Err(e) => warning!("CHUID: <none> {}", e),
|
Err(e) => warning!("CHUID: <none> {}", e),
|
||||||
}
|
}
|
||||||
match yk.cccid() {
|
match yk.cccid() {
|
||||||
Ok(cccid) => information!("CCCID: {}",cccid.to_string()),
|
Ok(cccid) => {
|
||||||
|
information!("CCCID: {}",cccid.to_string());
|
||||||
|
output.insert("cccid".to_string(), Value::String(cccid.to_string()));
|
||||||
|
}
|
||||||
Err(e) => warning!("CCCID: <none> {}", e),
|
Err(e) => warning!("CCCID: <none> {}", e),
|
||||||
}
|
}
|
||||||
match yk.get_pin_retries() {
|
match yk.get_pin_retries() {
|
||||||
Ok(pin_retries) => information!("PIN retries: {}",pin_retries),
|
Ok(pin_retries) => {
|
||||||
|
information!("PIN retries: {}",pin_retries);
|
||||||
|
output.insert("pin_retries".to_string(), Value::String(pin_retries.to_string()));
|
||||||
|
}
|
||||||
Err(e) => warning!("PIN retries: <none> {}", e),
|
Err(e) => warning!("PIN retries: <none> {}", e),
|
||||||
}
|
}
|
||||||
|
|
||||||
match yk.piv_keys() {
|
match yk.piv_keys() {
|
||||||
Ok(keys) => {
|
Ok(keys) => information!("Found {} PIV keys of {}", keys.len(), ORDERED_SLOTS.len()),
|
||||||
information!("Found {} PIV keys of {}", keys.len(), ORDERED_SLOTS.len());
|
|
||||||
}
|
|
||||||
Err(e) => failure!("Get PIV keys failed: {}", e)
|
Err(e) => failure!("Get PIV keys failed: {}", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut piv_slots = vec![];
|
let mut piv_slots = vec![];
|
||||||
for slot in iff!(show_ordered, ORDERED_SLOTS, yubikey::piv::SLOTS) {
|
for slot in iff!(show_ordered, ORDERED_SLOTS, yubikey::piv::SLOTS) {
|
||||||
print_summary_info(&mut yk, slot, &mut piv_slots, show_all, show_table).ok();
|
print_summary_info(&mut yk, slot, &mut piv_slots, show_all, show_table, json_output).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
if show_table {
|
if show_table {
|
||||||
let mut table = Table::new(piv_slots);
|
let mut table = Table::new(piv_slots);
|
||||||
table.with(Style::rounded());
|
table.with(Style::rounded());
|
||||||
println!("{}", table);
|
println!("{}", table);
|
||||||
|
} else if json_output {
|
||||||
|
let piv_slots_json = serde_json::to_string(&piv_slots).unwrap();
|
||||||
|
let piv_slots_values: Vec<Value> = serde_json::from_str(&piv_slots_json).unwrap();
|
||||||
|
output.insert("piv_slots".to_string(), Value::Array(piv_slots_values));
|
||||||
}
|
}
|
||||||
|
if json_output {
|
||||||
|
println!("{}", serde_json::to_string_pretty(&output).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_summary_info(yubikey: &mut YubiKey, slot: SlotId, piv_slots: &mut Vec<PivSlot>, show_all: bool, show_table: bool) -> XResult<()> {
|
fn print_summary_info(yubikey: &mut YubiKey, slot: SlotId, piv_slots: &mut Vec<PivSlot>, show_all: bool, show_table: bool, json_output: bool) -> XResult<()> {
|
||||||
let slot_id: u8 = slot.into();
|
let slot_id: u8 = slot.into();
|
||||||
let mut origin = NA.to_string();
|
let mut origin = NA.to_string();
|
||||||
let mut retries = NA.to_string();
|
let mut retries = NA.to_string();
|
||||||
@@ -101,7 +128,7 @@ fn print_summary_info(yubikey: &mut YubiKey, slot: SlotId, piv_slots: &mut Vec<P
|
|||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if show_all {
|
if show_all {
|
||||||
if show_table {
|
if show_table || json_output {
|
||||||
piv_slots.push(PivSlot {
|
piv_slots.push(PivSlot {
|
||||||
name: slot.to_string(),
|
name: slot.to_string(),
|
||||||
id: format!("{:x}", slot_id),
|
id: format!("{:x}", slot_id),
|
||||||
@@ -127,7 +154,7 @@ fn print_summary_info(yubikey: &mut YubiKey, slot: SlotId, piv_slots: &mut Vec<P
|
|||||||
Ok((_rem, cert)) => cert.subject.to_string(),
|
Ok((_rem, cert)) => cert.subject.to_string(),
|
||||||
_ => cert.cert.tbs_certificate.subject.to_string(),
|
_ => cert.cert.tbs_certificate.subject.to_string(),
|
||||||
};
|
};
|
||||||
if show_table {
|
if show_table || json_output {
|
||||||
piv_slots.push(PivSlot {
|
piv_slots.push(PivSlot {
|
||||||
name: slot.to_string(),
|
name: slot.to_string(),
|
||||||
id: format!("{:x}", slot_id),
|
id: format!("{:x}", slot_id),
|
||||||
|
|||||||
Reference in New Issue
Block a user