mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
pvsecret: Support retrieving a secret by index
Allow users to retrieve a secret by its index. This allows users to extract a specific secret in case of multiple ids. Reviewed-by: Finn Callies <fcallies@linux.ibm.com> Tested-by: Finn Callies <fcallies@linux.ibm.com> Signed-off-by: Steffen Eiden <seiden@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
e62cdf9a6e
commit
1fefdecbe7
@@ -351,6 +351,8 @@ pub enum RetrInpFmt {
|
||||
Hex,
|
||||
/// Use a name-string. Will hash it if no secret with the name found.
|
||||
Name,
|
||||
/// Use the secret-index (base 10) instead of the secret-ID
|
||||
Idx,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Default)]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::{collections::VecDeque, fmt::Display};
|
||||
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use log::{debug, info, warn};
|
||||
@@ -17,6 +17,42 @@ use utils::get_writer_from_cli_file_arg;
|
||||
use super::list::list_uvc;
|
||||
use crate::cli::{RetrInpFmt, RetrOutFmt, RetrSecretOptions};
|
||||
|
||||
enum Value {
|
||||
Id(SecretId),
|
||||
Idx(u16),
|
||||
}
|
||||
|
||||
impl Display for Value {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Value::Id(id) => write!(f, "ID {id}"),
|
||||
Value::Idx(idx) => write!(f, "index {idx}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&RetrSecretOptions> for Value {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(opt: &RetrSecretOptions) -> Result<Self> {
|
||||
match opt.inform {
|
||||
RetrInpFmt::Yaml => match serde_yaml::from_reader(&mut open_file(&opt.input)?)? {
|
||||
GuestSecret::Retrievable { id, .. } => Ok(Self::Id(id)),
|
||||
gs => bail!("The file contains a {gs}-secret, which is not retrievable."),
|
||||
},
|
||||
RetrInpFmt::Hex => serde_yaml::from_str(&opt.input)
|
||||
.context("Cannot parse SecretId information")
|
||||
.map(Self::Id),
|
||||
RetrInpFmt::Name => Ok(Self::Id(SecretId::from_string(&opt.input))),
|
||||
RetrInpFmt::Idx => opt
|
||||
.input
|
||||
.parse()
|
||||
.context("Invalid index value")
|
||||
.map(Self::Idx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_secret_by_id(secrets: &SecretList, id: &SecretId) -> Option<SecretEntry> {
|
||||
let mut secrets: VecDeque<_> = secrets
|
||||
.into_iter()
|
||||
@@ -37,26 +73,31 @@ fn find_secret_by_id(secrets: &SecretList, id: &SecretId) -> Option<SecretEntry>
|
||||
secret.cloned()
|
||||
}
|
||||
|
||||
fn retrieve(id: &SecretId) -> Result<RetrievedSecret> {
|
||||
fn retrieve(value: Value) -> Result<RetrievedSecret> {
|
||||
let uv = UvDevice::open()?;
|
||||
let secrets = list_uvc(&uv)?;
|
||||
|
||||
let secret = match find_secret_by_id(&secrets, id) {
|
||||
Some(s) => s,
|
||||
// hash it + try again if it is ASCII-representable
|
||||
None => match id.as_ascii() {
|
||||
Some(s) => find_secret_by_id(&secrets, &GuestSecret::name_to_id(s)?),
|
||||
None => None,
|
||||
let entry = match &value {
|
||||
Value::Id(id) => {
|
||||
match find_secret_by_id(&secrets, id) {
|
||||
Some(s) => Some(s),
|
||||
// hash it + try again if it is ASCII-representable
|
||||
None => match id.as_ascii() {
|
||||
Some(s) => find_secret_by_id(&secrets, &GuestSecret::name_to_id(s)?),
|
||||
None => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
.ok_or(anyhow!(
|
||||
"The UV secret-store has no secret with the ID {id}"
|
||||
))?,
|
||||
};
|
||||
Value::Idx(idx) => secrets.into_iter().find(|e| &e.index() == idx),
|
||||
}
|
||||
.ok_or(anyhow!(
|
||||
"The UV secret-store has no secret with the {value}"
|
||||
))?;
|
||||
|
||||
info!("Try to retrieve secret at index: {}", secret.index());
|
||||
debug!("Try to retrieve: {secret:?}");
|
||||
info!("Try to retrieve secret at index: {}", entry.index());
|
||||
debug!("Try to retrieve: {entry:?}");
|
||||
|
||||
let mut uv_cmd = RetrieveCmd::from_entry(secret)?;
|
||||
let mut uv_cmd = RetrieveCmd::from_entry(entry)?;
|
||||
uv.send_cmd(&mut uv_cmd)?;
|
||||
|
||||
Ok(RetrievedSecret::from_cmd(uv_cmd))
|
||||
@@ -64,19 +105,8 @@ fn retrieve(id: &SecretId) -> Result<RetrievedSecret> {
|
||||
|
||||
pub fn retr(opt: &RetrSecretOptions) -> Result<()> {
|
||||
let mut output = get_writer_from_cli_file_arg(&opt.output)?;
|
||||
let id = match &opt.inform {
|
||||
RetrInpFmt::Yaml => match serde_yaml::from_reader(&mut open_file(&opt.input)?)? {
|
||||
GuestSecret::Retrievable { id, .. } => id,
|
||||
gs => bail!("The file contains a {gs}-secret, which is not retrievable."),
|
||||
},
|
||||
RetrInpFmt::Hex => {
|
||||
serde_yaml::from_str(&opt.input).context("Cannot parse SecretId information")?
|
||||
}
|
||||
RetrInpFmt::Name => SecretId::from_string(&opt.input),
|
||||
};
|
||||
|
||||
let retr_secret =
|
||||
retrieve(&id).context("Could not retrieve the secret from the UV secret store.")?;
|
||||
let retr_secret = retrieve(opt.try_into()?)
|
||||
.context("Could not retrieve the secret from the UV secret store.")?;
|
||||
|
||||
let out_data = match opt.outform {
|
||||
RetrOutFmt::Bin => retr_secret.into_bytes(),
|
||||
|
||||
Reference in New Issue
Block a user