use super::{Error, ErrorKind};
use crate::{
device::SerialNumber,
object, opaque,
uuid::{self, Uuid},
Capability, Client, Domain,
};
use serde::{Deserialize, Serialize};
use std::{env, str::FromStr};
use time::OffsetDateTime as DateTime;
pub const REPORT_OBJECT_LABEL: &str = "yubihsm.rs setup report";
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Version(usize);
impl From<Version> for usize {
fn from(version: Version) -> usize {
version.0
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Report {
pub version: Version,
pub uuid: Uuid,
pub device_serial_number: String,
pub hostname: Option<String>,
pub username: Option<String>,
pub date: DateTime,
pub software: String,
}
impl Report {
pub fn new(serial_number: SerialNumber) -> Self {
Report {
version: Version(1),
uuid: uuid::new_v4(),
device_serial_number: serial_number.to_string(),
username: env::var("LOGNAME").ok(),
hostname: env::var("HOSTNAME").ok(),
date: DateTime::now_utc(),
software: format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
}
}
pub fn to_json(&self) -> String {
serde_json::to_string(self).unwrap()
}
pub fn store(&self, client: &Client, report_object_id: object::Id) -> Result<(), Error> {
client
.put_opaque(
report_object_id,
object::Label::from(REPORT_OBJECT_LABEL),
Domain::all(),
Capability::GET_OPAQUE,
opaque::Algorithm::Data,
self.to_json(),
)
.map_err(|e| format_err!(ErrorKind::ReportFailed, "{}", e))?;
Ok(())
}
}
impl FromStr for Report {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
serde_json::from_str(s).map_err(|e| {
format_err!(
ErrorKind::ReportFailed,
"error parsing yubihsm::setup::Report JSON: {}",
e
)
.into()
})
}
}