use crate::Entry;
pub type PlatformError = Box<dyn std::error::Error + Send + Sync>;
#[non_exhaustive]
#[derive(Debug)]
pub enum Error {
PlatformFailure(PlatformError),
NoStorageAccess(PlatformError),
NoEntry,
BadEncoding(Vec<u8>),
BadDataFormat(Vec<u8>, PlatformError),
BadStoreFormat(String),
TooLong(String, u32),
Invalid(String, String),
Ambiguous(Vec<Entry>),
NoDefaultStore,
NotSupportedByStore(String),
}
pub type Result<T> = std::result::Result<T, Error>;
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Error::PlatformFailure(err) => write!(f, "Platform failure: {err}"),
Error::NoStorageAccess(err) => {
write!(f, "Couldn't access platform storage: {err}")
}
Error::NoEntry => write!(f, "No matching credential found"),
Error::BadEncoding(_) => write!(f, "Password data is not valid UTF-8"),
Error::BadDataFormat(_, err) => {
write!(f, "Secret data is malformed: {err:?}")
}
Error::BadStoreFormat(reason) => write!(f, "Store data is malformed: {reason}"),
Error::TooLong(name, len) => write!(
f,
"Value of '{name}' is longer than the platform limit of {len} chars"
),
Error::Invalid(attr, reason) => {
write!(f, "Value of '{attr}' is invalid: {reason}")
}
Error::Ambiguous(items) => {
write!(
f,
"Entry is matched by {} credentials: {items:?}",
items.len(),
)
}
Error::NoDefaultStore => {
write!(
f,
"No default store has been set, so cannot search or create entries"
)
}
Error::NotSupportedByStore(issue) => write!(f, "Unsupported: {issue}"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::PlatformFailure(err) => Some(err.as_ref()),
Error::NoStorageAccess(err) => Some(err.as_ref()),
Error::BadDataFormat(_, err) => Some(err.as_ref()),
_ => None,
}
}
}
pub fn decode_password(bytes: Vec<u8>) -> Result<String> {
String::from_utf8(bytes).map_err(|err| Error::BadEncoding(err.into_bytes()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bad_password() {
for bytes in [b"\x80".to_vec(), b"\xbf".to_vec(), b"\xed\xa0\xa0".to_vec()] {
match decode_password(bytes.clone()) {
Err(Error::BadEncoding(str)) => assert_eq!(str, bytes),
Err(other) => panic!("Bad password ({bytes:?}) decode gave wrong error: {other}"),
Ok(s) => panic!("Bad password ({bytes:?}) decode gave results: {s:?}"),
}
}
}
}