use std::{fmt, io, string::FromUtf8Error};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum KpxError {
#[error("I/O error: {0}")]
Io(#[from] io::Error),
#[error("JSON serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("base64 error: {0}")]
Base64(#[from] base64::DecodeError),
#[error("encryption error")]
Crypto,
#[error("UTF-8 error: {0}")]
Utf8(#[from] FromUtf8Error),
#[error("unexpected empty response from KeePassXC")]
EmptyResponse,
#[error("missing field '{0}' in response")]
MissingField(&'static str),
#[error("unexpected action in response, expected '{expected}', got '{received}'")]
UnexpectedAction { expected: String, received: String },
#[error("association rejected: {reason}")]
AssociationRejected { reason: String },
#[error("KeePassXC returned an error{code}: {message}", code = DisplayRemoteErrorCode(*.code))]
RemoteError { code: Option<i32>, message: String },
#[error("KeePassXC host key unavailable; call `change_public_keys` first")]
MissingHostKey,
}
impl From<crypto_box::aead::Error> for KpxError {
fn from(_: crypto_box::aead::Error) -> Self {
KpxError::Crypto
}
}
#[derive(Copy, Clone, Debug)]
struct DisplayRemoteErrorCode(Option<i32>);
impl fmt::Display for DisplayRemoteErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(code) = self.0 {
write!(f, " ({code})")
} else {
Ok(())
}
}
}