151 lines
4.2 KiB
Rust
151 lines
4.2 KiB
Rust
use super::Keyfork;
|
|
use crate::config;
|
|
|
|
use clap::{builder::PossibleValue, Parser, Subcommand, ValueEnum};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Provisioner {
|
|
OpenPGPCard(OpenPGPCard),
|
|
}
|
|
|
|
impl std::fmt::Display for Provisioner {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Provisioner::OpenPGPCard(_) => f.write_str("openpgp-card"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Provisioner {
|
|
fn discover(&self) -> Vec<(String, Option<String>)> {
|
|
match self {
|
|
Provisioner::OpenPGPCard(o) => o.discover(),
|
|
}
|
|
}
|
|
|
|
fn provision(
|
|
&self,
|
|
provisioner: config::Provisioner,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
match self {
|
|
Provisioner::OpenPGPCard(o) => o.provision(provisioner),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ValueEnum for Provisioner {
|
|
fn value_variants<'a>() -> &'a [Self] {
|
|
&[Self::OpenPGPCard(OpenPGPCard)]
|
|
}
|
|
|
|
fn to_possible_value(&self) -> Option<PossibleValue> {
|
|
Some(PossibleValue::new(match self {
|
|
Self::OpenPGPCard(_) => "openpgp-card",
|
|
}))
|
|
}
|
|
}
|
|
|
|
trait ProvisionExec {
|
|
/// Discover all known places the formatted key can be deployed to.
|
|
fn discover(&self) -> Vec<(String, Option<String>)> {
|
|
vec![]
|
|
}
|
|
|
|
/// Derive a key and deploy it to a target.
|
|
fn provision(&self, p: config::Provisioner) -> Result<(), Box<dyn std::error::Error>>;
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct OpenPGPCard;
|
|
|
|
impl ProvisionExec for OpenPGPCard {
|
|
fn discover(&self) -> Vec<(String, Option<String>)> {
|
|
/*
|
|
vec![
|
|
(
|
|
"0006:26144195".to_string(),
|
|
Some("Yubicats Heywood".to_string()),
|
|
),
|
|
(
|
|
"0006:2614419y".to_string(),
|
|
Some("Yubicats Heywood".to_string()),
|
|
),
|
|
]
|
|
*/
|
|
vec![]
|
|
}
|
|
|
|
fn provision(&self, _p: config::Provisioner) -> Result<(), Box<dyn std::error::Error>> {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
#[derive(Subcommand, Clone, Debug)]
|
|
pub enum ProvisionSubcommands {
|
|
/// Discover all available targets on the system.
|
|
Discover,
|
|
}
|
|
|
|
// NOTE: All struct fields are marked as Option so they may be constructed when running a
|
|
// subcommand. This is allowed through marking the parent command subcommand_negates_reqs(true).
|
|
|
|
#[derive(Parser, Debug, Clone)]
|
|
pub struct Provision {
|
|
#[command(subcommand)]
|
|
pub subcommand: Option<ProvisionSubcommands>,
|
|
|
|
provisioner_name: Provisioner,
|
|
|
|
/// Account ID.
|
|
#[arg(long, required(true))]
|
|
account_id: Option<u32>,
|
|
|
|
/// Identifier of the hardware to deploy to, listable by running the `discover` subcommand.
|
|
#[arg(long, required(true))]
|
|
identifier: Option<String>,
|
|
}
|
|
|
|
// NOTE: In the future, this impl will be used by `keyfork recover` to reprovision hardware from
|
|
// the config file, iterating through a [Config::provisioner].
|
|
// TODO: How can metadata be passed in?
|
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
#[error("Missing field: {0}")]
|
|
pub struct MissingField(&'static str);
|
|
|
|
impl TryFrom<Provision> for config::Provisioner {
|
|
type Error = MissingField;
|
|
|
|
fn try_from(value: Provision) -> Result<Self, Self::Error> {
|
|
Ok(Self {
|
|
name: value.provisioner_name.to_string(),
|
|
account: value.account_id.ok_or(MissingField("account_id"))?,
|
|
identifier: value.identifier.ok_or(MissingField("identifier"))?,
|
|
metadata: Default::default(),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Provision {
|
|
pub fn handle(&self, _keyfork: &Keyfork) -> Result<(), Box<dyn std::error::Error>> {
|
|
match self.subcommand {
|
|
Some(ProvisionSubcommands::Discover) => {
|
|
let mut iter = self.provisioner_name.discover().into_iter().peekable();
|
|
while let Some((identifier, context)) = iter.next() {
|
|
println!("Identifier: {identifier}");
|
|
if let Some(context) = context {
|
|
println!("Context: {context}");
|
|
}
|
|
if iter.peek().is_some() {
|
|
println!("---");
|
|
}
|
|
}
|
|
}
|
|
None => {
|
|
self.provisioner_name.provision(self.clone().try_into()?)?;
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|