Repository: juspay/hyperswitch
File: crates/external_services/src/aws_kms/core.rs (Rust)

Code before:

        let output = decrypt_output
            .plaintext
            .ok_or(report!(AwsKmsError::MissingPlaintextDecryptionOutput))
            .and_then(|blob| {
                String::from_utf8(blob.into_inner()).change_context(AwsKmsError::Utf8DecodingFailed)
            })?;

        let time_taken = start.elapsed();
        metrics::AWS_KMS_DECRYPT_TIME.record(time_taken.as_secs_f64(), &[]);

        Ok(output)
    }

    /// Encrypts the provided String data using the AWS KMS SDK. We assume that
    /// the SDK has the values required to interact with the AWS KMS APIs (`AWS_ACCESS_KEY_ID` and
    /// `AWS_SECRET_ACCESS_KEY`) either set in environment variables, or that the SDK is running in
    /// a machine that is able to assume an IAM role.
    pub async fn encrypt(&self, data: impl AsRef<[u8]>) -> CustomResult<String, AwsKmsError> {
        let start = Instant::now();
        let plaintext_blob = Blob::new(data.as_ref());

        let encrypted_output = self
            .inner_client
            .encrypt()
            .key_id(&self.key_id)
            .plaintext(plaintext_blob)
            .send()
            .await
            .inspect_err(|error| {
                // Logging using `Debug` representation of the error as the `Display`
                // representation does not hold sufficient information.
                logger::error!(aws_kms_sdk_error=?error, "Failed to AWS KMS encrypt data");
                metrics::AWS_KMS_ENCRYPTION_FAILURES.add(1, &[]);
            })
            .change_context(AwsKmsError::EncryptionFailed)?;

        let output = encrypted_output
            .ciphertext_blob
            .ok_or(AwsKmsError::MissingCiphertextEncryptionOutput)
            .map(|blob| consts::BASE64_ENGINE.encode(blob.into_inner()))?;
        let time_taken = start.elapsed();
        metrics::AWS_KMS_ENCRYPT_TIME.record(time_taken.as_secs_f64(), &[]);

        Ok(output)
    }
}

/// Errors that could occur during KMS operations.
#[derive(Debug, thiserror::Error)]
pub enum AwsKmsError {

Review comment (suggestion):
I was wondering if we even need an `encrypt` interface function. I believe application has no use case for encrypting using AWS KMS. @SanchithHegde 

Code after:
                metrics::AWS_KMS_DECRYPTION_FAILURES.add(1, &[]);
            })
            .change_context(AwsKmsError::DecryptionFailed)?;

        let output = decrypt_output
            .plaintext
            .ok_or(report!(AwsKmsError::MissingPlaintextDecryptionOutput))
            .and_then(|blob| {
                String::from_utf8(blob.into_inner()).change_context(AwsKmsError::Utf8DecodingFailed)
            })?;

        let time_taken = start.elapsed();
        metrics::AWS_KMS_DECRYPT_TIME.record(time_taken.as_secs_f64(), &[]);

        Ok(output)
    }

    /// Encrypts the provided String data using the AWS KMS SDK. We assume that
    /// the SDK has the values required to interact with the AWS KMS APIs (`AWS_ACCESS_KEY_ID` and
    /// `AWS_SECRET_ACCESS_KEY`) either set in environment variables, or that the SDK is running in
    /// a machine that is able to assume an IAM role.
    pub async fn encrypt(&self, data: impl AsRef<[u8]>) -> CustomResult<String, AwsKmsError> {
        let start = Instant::now();
        let plaintext_blob = Blob::new(data.as_ref());

        let mut encryption_builder = self.inner_client.encrypt();

        match &self.key_id {
            Some(key_id) => encryption_builder = encryption_builder.key_id(key_id),
            None => {
                return Err(report!(AwsKmsError::MissingKeyId));
            }
        };
        let encrypted_output = encryption_builder
            .plaintext(plaintext_blob)
            .send()
            .await
            .inspect_err(|error| {
                // Logging using `Debug` representation of the error as the `Display`
                // representation does not hold sufficient information.
                logger::error!(aws_kms_sdk_error=?error, "Failed to AWS KMS encrypt data");
                metrics::AWS_KMS_ENCRYPTION_FAILURES.add(1, &[]);
            })
            .change_context(AwsKmsError::EncryptionFailed)?;

        let output = encrypted_output
            .ciphertext_blob
            .ok_or(AwsKmsError::MissingCiphertextEncryptionOutput)
            .map(|blob| consts::BASE64_ENGINE.encode(blob.into_inner()))?;
        let time_taken = start.elapsed();
        metrics::AWS_KMS_ENCRYPT_TIME.record(time_taken.as_secs_f64(), &[]);