use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum KmsErrorCode {
#[default]
AlreadyExistsException,
CloudHsmClusterInvalidConfigurationException,
CustomKeyStoreInvalidStateException,
CustomKeyStoreNotFoundException,
DependencyTimeoutException,
DisabledException,
DryRunOperationException,
IncorrectKeyException,
InvalidAction,
InvalidAliasNameException,
InvalidArnException,
InvalidCiphertextException,
InvalidGrantIdException,
InvalidGrantTokenException,
InvalidKeyUsageException,
InvalidMarkerException,
KMSInternalException,
KMSInvalidMacException,
KMSInvalidSignatureException,
KMSInvalidStateException,
KeyUnavailableException,
LimitExceededException,
MalformedPolicyDocumentException,
MissingAction,
NotFoundException,
TagException,
UnsupportedOperationException,
XksKeyAlreadyInUseException,
XksKeyInvalidConfigurationException,
XksKeyNotFoundException,
}
impl KmsErrorCode {
#[must_use]
pub fn error_type(&self) -> &'static str {
self.as_str()
}
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::AlreadyExistsException => "AlreadyExistsException",
Self::CloudHsmClusterInvalidConfigurationException => {
"CloudHsmClusterInvalidConfigurationException"
}
Self::CustomKeyStoreInvalidStateException => "CustomKeyStoreInvalidStateException",
Self::CustomKeyStoreNotFoundException => "CustomKeyStoreNotFoundException",
Self::DependencyTimeoutException => "DependencyTimeoutException",
Self::DisabledException => "DisabledException",
Self::DryRunOperationException => "DryRunOperationException",
Self::IncorrectKeyException => "IncorrectKeyException",
Self::InvalidAction => "InvalidAction",
Self::InvalidAliasNameException => "InvalidAliasNameException",
Self::InvalidArnException => "InvalidArnException",
Self::InvalidCiphertextException => "InvalidCiphertextException",
Self::InvalidGrantIdException => "InvalidGrantIdException",
Self::InvalidGrantTokenException => "InvalidGrantTokenException",
Self::InvalidKeyUsageException => "InvalidKeyUsageException",
Self::InvalidMarkerException => "InvalidMarkerException",
Self::KMSInternalException => "KMSInternalException",
Self::KMSInvalidMacException => "KMSInvalidMacException",
Self::KMSInvalidSignatureException => "KMSInvalidSignatureException",
Self::KMSInvalidStateException => "KMSInvalidStateException",
Self::KeyUnavailableException => "KeyUnavailableException",
Self::LimitExceededException => "LimitExceededException",
Self::MalformedPolicyDocumentException => "MalformedPolicyDocumentException",
Self::MissingAction => "MissingAction",
Self::NotFoundException => "NotFoundException",
Self::TagException => "TagException",
Self::UnsupportedOperationException => "UnsupportedOperationException",
Self::XksKeyAlreadyInUseException => "XksKeyAlreadyInUseException",
Self::XksKeyInvalidConfigurationException => "XksKeyInvalidConfigurationException",
Self::XksKeyNotFoundException => "XksKeyNotFoundException",
}
}
#[must_use]
pub fn default_status_code(&self) -> http::StatusCode {
match self {
Self::CloudHsmClusterInvalidConfigurationException
| Self::CustomKeyStoreInvalidStateException
| Self::CustomKeyStoreNotFoundException
| Self::IncorrectKeyException
| Self::InvalidAction
| Self::InvalidAliasNameException
| Self::InvalidArnException
| Self::InvalidCiphertextException
| Self::InvalidGrantIdException
| Self::InvalidGrantTokenException
| Self::InvalidKeyUsageException
| Self::InvalidMarkerException
| Self::KMSInvalidMacException
| Self::KMSInvalidSignatureException
| Self::LimitExceededException
| Self::MalformedPolicyDocumentException
| Self::MissingAction
| Self::TagException
| Self::UnsupportedOperationException
| Self::XksKeyAlreadyInUseException
| Self::XksKeyInvalidConfigurationException
| Self::XksKeyNotFoundException => http::StatusCode::BAD_REQUEST,
Self::NotFoundException => http::StatusCode::NOT_FOUND,
Self::AlreadyExistsException
| Self::DisabledException
| Self::KMSInvalidStateException => http::StatusCode::CONFLICT,
Self::DryRunOperationException => http::StatusCode::PRECONDITION_FAILED,
Self::KMSInternalException | Self::KeyUnavailableException => {
http::StatusCode::INTERNAL_SERVER_ERROR
}
Self::DependencyTimeoutException => http::StatusCode::SERVICE_UNAVAILABLE,
}
}
}
impl fmt::Display for KmsErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug)]
pub struct KmsError {
pub code: KmsErrorCode,
pub message: String,
pub status_code: http::StatusCode,
pub source: Option<Box<dyn std::error::Error + Send + Sync>>,
}
impl fmt::Display for KmsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "KmsError({}): {}", self.code, self.message)
}
}
impl std::error::Error for KmsError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source
.as_ref()
.map(|e| e.as_ref() as &(dyn std::error::Error + 'static))
}
}
impl KmsError {
#[must_use]
pub fn new(code: KmsErrorCode) -> Self {
Self {
status_code: code.default_status_code(),
message: code.as_str().to_owned(),
code,
source: None,
}
}
#[must_use]
pub fn with_message(code: KmsErrorCode, message: impl Into<String>) -> Self {
Self {
status_code: code.default_status_code(),
message: message.into(),
code,
source: None,
}
}
#[must_use]
pub fn error_type(&self) -> &'static str {
self.code.error_type()
}
#[must_use]
pub fn internal_error(message: impl Into<String>) -> Self {
Self::with_message(KmsErrorCode::KMSInternalException, message)
}
#[must_use]
pub fn validation(message: impl Into<String>) -> Self {
Self::with_message(KmsErrorCode::InvalidArnException, message)
}
#[must_use]
pub fn missing_action() -> Self {
Self::with_message(
KmsErrorCode::MissingAction,
"Missing required header: X-Amz-Target",
)
}
#[must_use]
pub fn unknown_operation(target: &str) -> Self {
Self::with_message(
KmsErrorCode::InvalidAction,
format!("Operation {target} is not supported."),
)
}
#[must_use]
pub fn not_implemented(operation: &str) -> Self {
Self::with_message(
KmsErrorCode::KMSInternalException,
format!("Operation {operation} is not yet implemented"),
)
}
}
#[macro_export]
macro_rules! kms_error {
($code:ident) => {
$crate::error::KmsError::new($crate::error::KmsErrorCode::$code)
};
($code:ident, $msg:expr) => {
$crate::error::KmsError::with_message($crate::error::KmsErrorCode::$code, $msg)
};
}