feat: v1.10.7, add --json for piv-summary

This commit is contained in:
2024-09-14 23:19:39 +08:00
parent 0cfe26e238
commit 8031fca7e7
3 changed files with 44 additions and 17 deletions

2
Cargo.lock generated
View File

@@ -487,7 +487,7 @@ dependencies = [
[[package]]
name = "card-cli"
version = "1.10.6"
version = "1.10.7"
dependencies = [
"authenticator 0.3.1",
"base64 0.21.7",

View File

@@ -1,6 +1,6 @@
[package]
name = "card-cli"
version = "1.10.6"
version = "1.10.7"
authors = ["Hatter Jiang <jht5945@gmail.com>"]
edition = "2018"

View File

@@ -1,18 +1,20 @@
use clap::{App, Arg, ArgMatches, SubCommand};
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 tabled::{Table, Tabled};
use tabled::settings::Style;
use tabled::{Table, Tabled};
use x509_parser::parse_x509_certificate;
use yubikey::{Certificate, YubiKey};
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";
#[derive(Tabled)]
#[derive(Tabled, Serialize)]
struct PivSlot {
name: String,
id: String,
@@ -33,6 +35,7 @@ impl Command for CommandImpl {
fn subcommand<'a>(&self) -> App<'a, 'a> {
SubCommand::with_name(self.name()).about("PIV subcommand")
.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("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_all = sub_arg_matches.is_present("all");
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: {}");
success!("Name: {}", yk.name());
information!("Version: {}", yk.version());
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() {
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),
}
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),
}
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),
}
match yk.piv_keys() {
Ok(keys) => {
information!("Found {} PIV keys of {}", keys.len(), ORDERED_SLOTS.len());
}
Ok(keys) => information!("Found {} PIV keys of {}", keys.len(), ORDERED_SLOTS.len()),
Err(e) => failure!("Get PIV keys failed: {}", e)
}
let mut piv_slots = vec![];
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 {
let mut table = Table::new(piv_slots);
table.with(Style::rounded());
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)
}
}
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 mut origin = 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,
Err(e) => {
if show_all {
if show_table {
if show_table || json_output {
piv_slots.push(PivSlot {
name: slot.to_string(),
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(),
_ => cert.cert.tbs_certificate.subject.to_string(),
};
if show_table {
if show_table || json_output {
piv_slots.push(PivSlot {
name: slot.to_string(),
id: format!("{:x}", slot_id),