use crate::abi;
use bytes::{Bytes, BytesMut};
use fastly_shared::FastlyStatus;
#[derive(Debug, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct SecretStoreHandle {
handle: u32,
}
impl SecretStoreHandle {
#[cfg_attr(
not(target_env = "p1"),
deprecated(
since = "0.11.6",
note = "This code will need to be updated for wasip2."
)
)]
pub const INVALID: Self = SecretStoreHandle {
handle: fastly_shared::INVALID_SECRET_STORE_HANDLE,
};
pub fn open(secret_store_name: &str) -> Result<Self, OpenError> {
use OpenError::*;
let mut handle = Self::INVALID;
unsafe {
abi::fastly_secret_store::open(
secret_store_name.as_ptr(),
secret_store_name.len(),
handle.as_u32_mut(),
)
}
.result()
.map(|_| handle)
.map_err(|s| match s {
FastlyStatus::NONE => SecretStoreDoesNotExist(secret_store_name.to_string()),
FastlyStatus::INVAL => InvalidSecretStoreName(secret_store_name.to_string()),
_ => Unexpected(s),
})
}
pub fn get(&self, secret_name: &str) -> Result<Option<SecretHandle>, LookupError> {
use LookupError::*;
let mut handle = fastly_shared::INVALID_SECRET_HANDLE;
let status = unsafe {
abi::fastly_secret_store::get(
self.as_u32(),
secret_name.as_ptr(),
secret_name.len(),
&mut handle,
)
};
match status {
FastlyStatus::OK => Ok(Some(SecretHandle { handle })),
FastlyStatus::NONE => Ok(None),
FastlyStatus::BADF => Err(InvalidSecretStoreHandle),
FastlyStatus::INVAL => Err(InvalidSecretName(secret_name.to_string())),
_ => Err(Unexpected(status)),
}
}
pub fn contains(&self, name: &str) -> Result<bool, LookupError> {
match self.get(name) {
Ok(Some(_)) => Ok(true),
Ok(None) => Ok(false),
Err(e) => Err(e),
}
}
pub(crate) fn as_u32(&self) -> u32 {
self.handle
}
pub(crate) fn as_u32_mut(&mut self) -> &mut u32 {
&mut self.handle
}
}
#[derive(Debug, Eq, Hash, PartialEq)]
#[repr(transparent)]
pub struct SecretHandle {
handle: u32,
}
impl SecretHandle {
pub const INVALID: Self = SecretHandle {
handle: fastly_shared::INVALID_SECRET_HANDLE,
};
pub fn plaintext(&self) -> Result<Bytes, DecryptError> {
const INITIAL_SECRET_PLAINTEXT_BUF_SIZE: usize = 1024;
if self.is_invalid() {
panic!("cannot lookup plaintext with invalid secret handle");
}
let mut plaintext_buf = BytesMut::zeroed(INITIAL_SECRET_PLAINTEXT_BUF_SIZE);
let mut nwritten = 0usize;
let status = unsafe {
abi::fastly_secret_store::plaintext(
self.as_u32(),
plaintext_buf.as_mut_ptr(),
plaintext_buf.len(),
&mut nwritten,
)
};
let status = match status {
FastlyStatus::BUFLEN if nwritten != 0 => {
plaintext_buf.resize(nwritten, 0);
nwritten = 0;
unsafe {
abi::fastly_secret_store::plaintext(
self.as_u32(),
plaintext_buf.as_mut_ptr(),
plaintext_buf.len(),
&mut nwritten,
)
}
}
s => s,
};
match status.result() {
Ok(()) => {
unsafe {
plaintext_buf.set_len(nwritten);
}
Ok(plaintext_buf.freeze())
}
Err(status) => Err(DecryptError::Unexpected(status)),
}
}
pub fn new(secret: &[u8]) -> Result<SecretHandle, FastlyStatus> {
let len = secret.len();
if len > (64 * 1024) {
return Err(FastlyStatus::INVAL);
}
let ptr = secret.as_ptr();
let mut handle = fastly_shared::INVALID_SECRET_HANDLE;
let res = unsafe { fastly_sys::fastly_secret_store::from_bytes(ptr, len, &mut handle) };
if res != FastlyStatus::OK {
return Err(res);
}
if handle == fastly_shared::INVALID_SECRET_HANDLE {
return Err(FastlyStatus::ERROR);
}
Ok(SecretHandle { handle })
}
#[cfg_attr(
not(target_env = "p1"),
deprecated(
since = "0.11.6",
note = "This code will need to be updated for wasip2."
)
)]
pub fn is_invalid(&self) -> bool {
self.handle == Self::INVALID.handle
}
pub(crate) fn as_u32(&self) -> u32 {
self.handle
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum OpenError {
#[error("secret store could not be found: {0}")]
SecretStoreDoesNotExist(String),
#[error("invalid secret store name: {0}")]
InvalidSecretStoreName(String),
#[error("unexpected error: {0:?}")]
Unexpected(FastlyStatus),
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum LookupError {
#[error("invalid secret store handle")]
InvalidSecretStoreHandle,
#[error("invalid secret name: {0}")]
InvalidSecretName(String),
#[error("invalid secret handle")]
InvalidSecretHandle,
#[error("unexpected error: {0:?}")]
Unexpected(FastlyStatus),
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum DecryptError {
#[error("unexpected error: {0:?}")]
Unexpected(FastlyStatus),
}