use crate::{utils::wrap_err, KeyId, TinkError};
use rand::Rng;
use std::convert::TryFrom;
use tink_proto::{KeyStatusType, OutputPrefixType};
#[derive(Default)]
pub struct Manager {
ks: tink_proto::Keyset,
}
impl Manager {
pub fn new() -> Self {
Self {
ks: tink_proto::Keyset::default(),
}
}
pub fn new_from_handle(kh: super::Handle) -> Self {
Self {
ks: kh.into_inner(),
}
}
pub fn rotate(&mut self, kt: &tink_proto::KeyTemplate) -> Result<KeyId, TinkError> {
self.add(kt, true)
}
pub fn add(
&mut self,
kt: &tink_proto::KeyTemplate,
as_primary: bool,
) -> Result<KeyId, TinkError> {
let key_data = crate::registry::new_key_data(kt)
.map_err(|e| wrap_err("keyset::Manager: cannot create KeyData", e))?;
let key_id = self.new_key_id();
let output_prefix_type = match OutputPrefixType::try_from(kt.output_prefix_type) {
Err(_) | Ok(OutputPrefixType::UnknownPrefix) => {
return Err("keyset::Manager: unknown output prefix type".into())
}
Ok(p) => p,
};
let key = tink_proto::keyset::Key {
key_data: Some(key_data),
status: tink_proto::KeyStatusType::Enabled as i32,
key_id,
output_prefix_type: output_prefix_type as i32,
};
self.ks.key.push(key);
if as_primary {
self.ks.primary_key_id = key_id;
}
Ok(key_id)
}
pub fn handle(&self) -> Result<super::Handle, TinkError> {
super::Handle::from_keyset(self.ks.clone())
}
pub fn enable(&mut self, key_id: KeyId) -> Result<(), TinkError> {
for key in &mut self.ks.key {
if key.key_id == key_id {
return match KeyStatusType::try_from(key.status) {
Ok(KeyStatusType::Enabled) | Ok(KeyStatusType::Disabled) => {
key.status = KeyStatusType::Enabled as i32;
Ok(())
}
_ => Err(format!(
"Cannot enable key with key_id {} and status {}",
key_id, key.status
)
.into()),
};
}
}
Err(format!("Key {key_id} not found").into())
}
pub fn disable(&mut self, key_id: KeyId) -> Result<(), TinkError> {
if self.ks.primary_key_id == key_id {
return Err(format!("Cannot disable primary key (key_id {key_id})").into());
}
for key in &mut self.ks.key {
if key.key_id == key_id {
return match KeyStatusType::try_from(key.status) {
Ok(KeyStatusType::Enabled) | Ok(KeyStatusType::Disabled) => {
key.status = KeyStatusType::Disabled as i32;
Ok(())
}
_ => Err(format!(
"Cannot disable key with key_id {} and status {}",
key_id, key.status
)
.into()),
};
}
}
Err(format!("Key {key_id} not found").into())
}
pub fn destroy(&mut self, key_id: KeyId) -> Result<(), TinkError> {
if self.ks.primary_key_id == key_id {
return Err(format!("Cannot destroy primary key (key_id {key_id})").into());
}
for key in &mut self.ks.key {
if key.key_id == key_id {
return match KeyStatusType::try_from(key.status) {
Ok(KeyStatusType::Enabled)
| Ok(KeyStatusType::Disabled)
| Ok(KeyStatusType::Destroyed) => {
key.key_data = None;
key.status = KeyStatusType::Destroyed as i32;
Ok(())
}
_ => Err(format!(
"Cannot destroy key with key_id {} and status {}",
key_id, key.status
)
.into()),
};
}
}
Err(format!("Key {key_id} not found").into())
}
pub fn delete(&mut self, key_id: KeyId) -> Result<(), TinkError> {
if self.ks.primary_key_id == key_id {
return Err(format!("Cannot delete primary key (key_id {key_id})").into());
}
let mut idx: Option<usize> = None;
for (i, key) in self.ks.key.iter().enumerate() {
if key.key_id == key_id {
idx = Some(i);
break;
}
}
match idx {
Some(i) => {
self.ks.key.remove(i);
Ok(())
}
None => Err(format!("Key {key_id} not found").into()),
}
}
pub fn set_primary(&mut self, key_id: KeyId) -> Result<(), TinkError> {
for key in &self.ks.key {
if key.key_id == key_id {
return match KeyStatusType::try_from(key.status) {
Ok(KeyStatusType::Enabled) => {
self.ks.primary_key_id = key_id;
Ok(())
}
_ => Err(format!(
"The candidate (key_id {}) for the primary key must be Enabled (status {})",
key_id, key.status
)
.into()),
};
}
}
Err(format!("Key {key_id} not found").into())
}
pub fn key_count(&self) -> usize {
self.ks.key.len()
}
fn new_key_id(&self) -> KeyId {
let mut rng = rand::thread_rng();
loop {
let ret = rng.gen::<u32>();
if self.ks.key.iter().any(|x| x.key_id == ret) {
continue;
}
return ret;
}
}
}