Repository: juspay/hyperswitch
File: crates/router/src/core/payments/helpers.rs (Rust)

Code before:
                    &session_state.into(),
                    type_name!(domain::Address),
                    types::CryptoOperation::BatchEncrypt(
                        domain::FromRequestEncryptableAddress::to_encryptable(
                            domain::FromRequestEncryptableAddress {
                                line1: address.address.as_ref().and_then(|a| a.line1.clone()),
                                line2: address.address.as_ref().and_then(|a| a.line2.clone()),
                                line3: address.address.as_ref().and_then(|a| a.line3.clone()),
                                state: address.address.as_ref().and_then(|a| a.state.clone()),
                                first_name: address
                                    .address
                                    .as_ref()
                                    .and_then(|a| a.first_name.clone()),
                                last_name: address
                                    .address
                                    .as_ref()
                                    .and_then(|a| a.last_name.clone()),
                                zip: address.address.as_ref().and_then(|a| a.zip.clone()),
                                phone_number: address
                                    .phone
                                    .as_ref()
                                    .and_then(|p| p.number.as_ref())
                                    .and_then(|secret| {
                                        let trimmed = secret.clone().expose().trim().to_string();
                                        (!trimmed.is_empty()).then(|| masking::Secret::new(trimmed))
                                    }),
                                email: address
                                    .email
                                    .as_ref()
                                    .map(|a| a.clone().expose().switch_strategy()),
                                origin_zip: address
                                    .address
                                    .as_ref()
                                    .and_then(|a| a.origin_zip.clone()),
                            },
                        ),
                    ),
                    Identifier::Merchant(merchant_key_store.merchant_id.clone()),
                    key,
                )
                .await
                .and_then(|val| val.try_into_batchoperation())
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed while encrypting address")?;
                let encryptable_address =
                    domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Failed while encrypting address")?;
                let address_update = storage::AddressUpdate::Update {
                    city: address
                        .address

Review comment (security):
since the logic is repeated can we have a util trait that does operation such as trimming and have it implemented for both Secret<String> and String. This will reduce repeatation of logic as well as can accomodate new types in future

Code after:
                                    .as_ref()
                                    .and_then(|a| a.last_name.clone()),
                                zip: address.address.as_ref().and_then(|a| a.zip.clone()),
                                phone_number: address
                                    .phone
                                    .as_ref()
                                    .and_then(|phone_details| phone_details.number.clone())
                                    .and_then(utils::trim_secret_string),
                                email: address
                                    .email
                                    .as_ref()
                                    .map(|a| a.clone().expose().switch_strategy()),
                                origin_zip: address
                                    .address
                                    .as_ref()
                                    .and_then(|a| a.origin_zip.clone()),
                            },
                        ),
                    ),
                    Identifier::Merchant(merchant_key_store.merchant_id.clone()),
                    key,
                )
                .await
                .and_then(|val| val.try_into_batchoperation())
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed while encrypting address")?;
                let encryptable_address =
                    domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Failed while encrypting address")?;
                let address_update = storage::AddressUpdate::Update {
                    city: address
                        .address
                        .as_ref()
                        .and_then(|value| value.city.clone()),
                    country: address.address.as_ref().and_then(|value| value.country),
                    line1: encryptable_address.line1,
                    line2: encryptable_address.line2,
                    line3: encryptable_address.line3,
                    state: encryptable_address.state,
                    zip: encryptable_address.zip,
                    first_name: encryptable_address.first_name,
                    last_name: encryptable_address.last_name,
                    phone_number: encryptable_address.phone_number,
                    country_code: address
                        .phone
                        .as_ref()
                        .and_then(|phone_details| phone_details.country_code.clone())
                        .and_then(utils::trim_string),
                    updated_by: storage_scheme.to_string(),
                    email: encryptable_address.email.map(|email| {