#![allow(missing_docs)]
use std::fmt;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum EncryptionError {
#[error("Invalid key: {message}")]
InvalidKey { message: String },
#[error("Invalid nonce: {message}")]
InvalidNonce { message: String },
#[error("Authentication failed: {message}")]
AuthenticationFailed { message: String },
#[error("Invalid ciphertext: {message}")]
InvalidCiphertext { message: String },
#[error("Key derivation failed: {message}")]
KeyDerivationFailed { message: String },
#[error("Key not found: {key_id}")]
KeyNotFound { key_id: String },
#[error("Access denied: {message}")]
AccessDenied { message: String },
#[error("Key store error: {message}")]
KeyStoreError { message: String },
#[error("Random generation failed: {message}")]
RandomGenerationFailed { message: String },
#[error("Invalid algorithm: {message}")]
InvalidAlgorithm { message: String },
#[error("Cipher operation failed: {message}")]
CipherOperationFailed { message: String },
#[error("Base64 operation failed: {message}")]
Base64Error { message: String },
#[error("Serialization failed: {message}")]
SerializationError { message: String },
#[error("Template processing failed: {message}")]
TemplateError { message: String },
#[error("Auto-encryption configuration error: {message}")]
AutoEncryptionConfigError { message: String },
#[error("Workspace encryption error: {message}")]
Workspace { message: String },
#[error("Encryption error: {message}")]
Generic { message: String },
}
impl EncryptionError {
pub fn invalid_key(message: impl Into<String>) -> Self {
Self::InvalidKey {
message: message.into(),
}
}
pub fn invalid_nonce(message: impl Into<String>) -> Self {
Self::InvalidNonce {
message: message.into(),
}
}
pub fn authentication_failed(message: impl Into<String>) -> Self {
Self::AuthenticationFailed {
message: message.into(),
}
}
pub fn invalid_ciphertext(message: impl Into<String>) -> Self {
Self::InvalidCiphertext {
message: message.into(),
}
}
pub fn key_derivation_failed(message: impl Into<String>) -> Self {
Self::KeyDerivationFailed {
message: message.into(),
}
}
pub fn key_not_found(key_id: impl Into<String>) -> Self {
Self::KeyNotFound {
key_id: key_id.into(),
}
}
pub fn access_denied(message: impl Into<String>) -> Self {
Self::AccessDenied {
message: message.into(),
}
}
pub fn key_store_error(message: impl Into<String>) -> Self {
Self::KeyStoreError {
message: message.into(),
}
}
pub fn random_generation_failed(message: impl Into<String>) -> Self {
Self::RandomGenerationFailed {
message: message.into(),
}
}
pub fn invalid_algorithm(message: impl Into<String>) -> Self {
Self::InvalidAlgorithm {
message: message.into(),
}
}
pub fn cipher_operation_failed(message: impl Into<String>) -> Self {
Self::CipherOperationFailed {
message: message.into(),
}
}
pub fn base64_error(message: impl Into<String>) -> Self {
Self::Base64Error {
message: message.into(),
}
}
pub fn serialization_error(message: impl Into<String>) -> Self {
Self::SerializationError {
message: message.into(),
}
}
pub fn template_error(message: impl Into<String>) -> Self {
Self::TemplateError {
message: message.into(),
}
}
pub fn auto_encryption_config_error(message: impl Into<String>) -> Self {
Self::AutoEncryptionConfigError {
message: message.into(),
}
}
pub fn workspace_encryption_error(message: impl Into<String>) -> Self {
Self::Workspace {
message: message.into(),
}
}
pub fn generic(message: impl Into<String>) -> Self {
Self::Generic {
message: message.into(),
}
}
pub fn is_recoverable(&self) -> bool {
match self {
Self::InvalidKey { .. }
| Self::InvalidNonce { .. }
| Self::AuthenticationFailed { .. }
| Self::InvalidCiphertext { .. }
| Self::KeyNotFound { .. }
| Self::InvalidAlgorithm { .. }
| Self::Base64Error { .. }
| Self::SerializationError { .. }
| Self::TemplateError { .. }
| Self::AutoEncryptionConfigError { .. } => false,
Self::KeyDerivationFailed { .. }
| Self::AccessDenied { .. }
| Self::KeyStoreError { .. }
| Self::RandomGenerationFailed { .. }
| Self::CipherOperationFailed { .. }
| Self::Workspace { .. }
| Self::Generic { .. } => true,
}
}
pub fn severity(&self) -> ErrorSeverity {
match self {
Self::AuthenticationFailed { .. } | Self::AccessDenied { .. } => {
ErrorSeverity::Critical
}
Self::InvalidKey { .. }
| Self::InvalidNonce { .. }
| Self::InvalidCiphertext { .. }
| Self::InvalidAlgorithm { .. } => ErrorSeverity::High,
Self::KeyDerivationFailed { .. }
| Self::KeyStoreError { .. }
| Self::RandomGenerationFailed { .. }
| Self::CipherOperationFailed { .. } => ErrorSeverity::Medium,
Self::Base64Error { .. }
| Self::SerializationError { .. }
| Self::TemplateError { .. }
| Self::AutoEncryptionConfigError { .. }
| Self::Workspace { .. }
| Self::Generic { .. } => ErrorSeverity::Low,
Self::KeyNotFound { .. } => ErrorSeverity::Info,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ErrorSeverity {
Info,
Low,
Medium,
High,
Critical,
}
pub type EncryptionResult<T> = Result<T, EncryptionError>;
#[derive(Debug, Clone)]
pub struct ErrorContext {
pub operation: String,
pub context: HashMap<String, String>,
pub timestamp: chrono::DateTime<chrono::Utc>,
}
impl ErrorContext {
pub fn new(operation: impl Into<String>) -> Self {
Self {
operation: operation.into(),
context: HashMap::new(),
timestamp: chrono::Utc::now(),
}
}
pub fn with_context(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.context.insert(key.into(), value.into());
self
}
}
#[derive(Debug)]
pub struct ContextualError {
pub error: EncryptionError,
pub context: ErrorContext,
}
impl fmt::Display for ContextualError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Encryption error in {} at {}: {} (context: {:?})",
self.context.operation, self.context.timestamp, self.error, self.context.context
)
}
}
impl std::error::Error for ContextualError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.error)
}
}
#[derive(Debug, Clone)]
pub enum ErrorRecoveryStrategy {
RetryWithBackoff {
max_attempts: usize,
base_delay_ms: u64,
},
FallbackMethod,
SkipEncryption,
ManualIntervention,
FailFast,
}
impl EncryptionError {
pub fn suggested_recovery(&self) -> ErrorRecoveryStrategy {
match self {
Self::RandomGenerationFailed { .. } => ErrorRecoveryStrategy::RetryWithBackoff {
max_attempts: 3,
base_delay_ms: 100,
},
Self::KeyStoreError { .. } | Self::KeyDerivationFailed { .. } => {
ErrorRecoveryStrategy::ManualIntervention
}
Self::AuthenticationFailed { .. } | Self::AccessDenied { .. } => {
ErrorRecoveryStrategy::FailFast
}
Self::InvalidKey { .. } | Self::InvalidNonce { .. } => {
ErrorRecoveryStrategy::FallbackMethod
}
_ => ErrorRecoveryStrategy::RetryWithBackoff {
max_attempts: 2,
base_delay_ms: 50,
},
}
}
pub fn with_context(self, context: ErrorContext) -> ContextualError {
ContextualError {
error: self,
context,
}
}
}
use std::collections::HashMap;