use {
crate::{
error::Error,
secret_store::SecretLookup,
session::Session,
wiggle_abi::{
fastly_secret_store::FastlySecretStore,
types::{FastlyStatus, SecretHandle, SecretStoreHandle},
},
},
std::convert::TryFrom,
wiggle::{GuestMemory, GuestPtr},
};
#[derive(Debug, thiserror::Error)]
pub enum SecretStoreError {
#[error("Unknown secret store: {0}")]
UnknownSecretStore(String),
#[error("Unknown secret: {0}")]
UnknownSecret(String),
#[error("Invalid secret store handle: {0}")]
InvalidSecretStoreHandle(SecretStoreHandle),
#[error("Invalid secret handle: {0}")]
InvalidSecretHandle(SecretHandle),
}
impl From<&SecretStoreError> for FastlyStatus {
fn from(err: &SecretStoreError) -> Self {
use SecretStoreError::*;
match err {
UnknownSecretStore(_) => FastlyStatus::None,
UnknownSecret(_) => FastlyStatus::None,
InvalidSecretStoreHandle(_) => FastlyStatus::Badf,
InvalidSecretHandle(_) => FastlyStatus::Badf,
}
}
}
impl FastlySecretStore for Session {
fn open(
&mut self,
memory: &mut GuestMemory<'_>,
name: GuestPtr<str>,
) -> Result<SecretStoreHandle, Error> {
let name = memory.as_str(name)?.ok_or(Error::SharedMemory)?;
self.secret_store_handle(name)
.ok_or(Error::SecretStoreError(
SecretStoreError::UnknownSecretStore(name.to_string()),
))
}
fn get(
&mut self,
memory: &mut GuestMemory<'_>,
secret_store_handle: SecretStoreHandle,
secret_name: GuestPtr<str>,
) -> Result<SecretHandle, Error> {
let store_name =
self.secret_store_name(secret_store_handle)
.ok_or(Error::SecretStoreError(
SecretStoreError::InvalidSecretStoreHandle(secret_store_handle),
))?;
let secret_name = memory.as_str(secret_name)?.ok_or(Error::SharedMemory)?;
self.secret_handle(store_name.as_str(), secret_name)
.ok_or(Error::SecretStoreError(SecretStoreError::UnknownSecret(
secret_name.to_string(),
)))
}
fn plaintext(
&mut self,
memory: &mut GuestMemory<'_>,
secret_handle: SecretHandle,
plaintext_buf: GuestPtr<u8>,
plaintext_max_len: u32,
nwritten_out: GuestPtr<u32>,
) -> Result<(), Error> {
let lookup = self
.secret_lookup(secret_handle)
.ok_or(Error::SecretStoreError(
SecretStoreError::InvalidSecretHandle(secret_handle),
))?;
let plaintext = match &lookup {
SecretLookup::Standard {
store_name,
secret_name,
} => self
.secret_stores()
.get_store(store_name)
.ok_or(Error::SecretStoreError(
SecretStoreError::InvalidSecretHandle(secret_handle),
))?
.get_secret(secret_name)
.ok_or(Error::SecretStoreError(
SecretStoreError::InvalidSecretHandle(secret_handle),
))?
.plaintext(),
SecretLookup::Injected { plaintext } => plaintext,
};
if plaintext.len() > plaintext_max_len as usize {
memory.write(nwritten_out, plaintext.len() as u32)?;
return Err(Error::BufferLengthError {
buf: "plaintext_buf",
len: "plaintext_max_len",
});
}
let plaintext_len = u32::try_from(plaintext.len())
.expect("smaller than plaintext_max_len means it must fit");
memory.copy_from_slice(plaintext, plaintext_buf.as_array(plaintext_len))?;
memory.write(nwritten_out, plaintext_len)?;
Ok(())
}
fn from_bytes(
&mut self,
memory: &mut GuestMemory<'_>,
plaintext_buf: GuestPtr<u8>,
plaintext_len: u32,
) -> Result<SecretHandle, Error> {
let plaintext = memory.to_vec(plaintext_buf.as_array(plaintext_len))?;
Ok(self.add_secret(plaintext))
}
}