From b8b20c412df0485bf395f9aa21e6e34e90d97acd Mon Sep 17 00:00:00 2001 From: Shankar Singh C <83439957+ShankarSinghC@users.noreply.github.com> Date: Thu, 16 Nov 2023 19:02:54 +0530 Subject: [PATCH] feat(router): add api to migrate card from basilisk to rust (#2853) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- config/config.example.toml | 2 + config/development.toml | 2 + config/docker_compose.toml | 2 + crates/api_models/src/enums.rs | 6 + crates/api_models/src/events.rs | 1 + .../api_models/src/events/locker_migration.rs | 9 ++ crates/api_models/src/lib.rs | 1 + crates/api_models/src/locker_migration.rs | 8 ++ crates/common_utils/src/events.rs | 1 + crates/router/src/configs/defaults.rs | 1 + crates/router/src/configs/kms.rs | 2 + crates/router/src/configs/settings.rs | 2 + crates/router/src/core.rs | 1 + crates/router/src/core/locker_migration.rs | 131 ++++++++++++++++++ .../router/src/core/payment_methods/cards.rs | 31 +++-- .../src/core/payment_methods/transformers.rs | 28 +++- crates/router/src/core/payouts/helpers.rs | 12 +- crates/router/src/lib.rs | 1 + crates/router/src/routes.rs | 5 +- crates/router/src/routes/app.rs | 15 +- crates/router/src/routes/lock_utils.rs | 2 + crates/router/src/routes/locker_migration.rs | 27 ++++ crates/router_env/src/logger/types.rs | 2 + loadtest/config/development.toml | 2 + 24 files changed, 274 insertions(+), 20 deletions(-) create mode 100644 crates/api_models/src/events/locker_migration.rs create mode 100644 crates/api_models/src/locker_migration.rs create mode 100644 crates/router/src/core/locker_migration.rs create mode 100644 crates/router/src/routes/locker_migration.rs diff --git a/config/config.example.toml b/config/config.example.toml index f0083bb48b19..40590128a5d4 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -112,6 +112,7 @@ kms_encrypted_recon_admin_api_key = "" # Base64-encoded (KMS encrypted) ciph # like card details [locker] host = "" # Locker host +host_rs = "" # Rust Locker host mock_locker = true # Emulate a locker locally using Postgres basilisk_host = "" # Basilisk host locker_signing_key_id = "1" # Key_id to sign basilisk hs locker @@ -130,6 +131,7 @@ locker_encryption_key2 = "" # public key 2 in pem format, corresponding private locker_decryption_key1 = "" # private key 1 in pem format, corresponding public key in basilisk locker_decryption_key2 = "" # private key 2 in pem format, corresponding public key in basilisk vault_encryption_key = "" # public key in pem format, corresponding private key in basilisk-hs +rust_locker_encryption_key = "" # public key in pem format, corresponding private key in rust locker vault_private_key = "" # private key in pem format, corresponding public key in basilisk-hs diff --git a/config/development.toml b/config/development.toml index 63c1f045d94f..d3cad47a23fc 100644 --- a/config/development.toml +++ b/config/development.toml @@ -48,6 +48,7 @@ applepay_endpoint = "DOMAIN SPECIFIC ENDPOINT" [locker] host = "" +host_rs = "" mock_locker = true basilisk_host = "" @@ -59,6 +60,7 @@ locker_encryption_key2 = "" locker_decryption_key1 = "" locker_decryption_key2 = "" vault_encryption_key = "" +rust_locker_encryption_key = "" vault_private_key = "" tunnel_private_key = "" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index ddda7e7021a4..39e8fad0fcaa 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -44,6 +44,7 @@ recon_admin_api_key = "recon_test_admin" [locker] host = "" +host_rs = "" mock_locker = true basilisk_host = "" @@ -55,6 +56,7 @@ locker_encryption_key2 = "" locker_decryption_key1 = "" locker_decryption_key2 = "" vault_encryption_key = "" +rust_locker_encryption_key = "" vault_private_key = "" [redis] diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index b27e71b9e8f5..100ab21e4099 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -562,3 +562,9 @@ pub enum RetryAction { /// Denotes that the payment is requeued Requeue, } + +#[derive(Clone, Copy)] +pub enum LockerChoice { + Basilisk, + Tartarus, +} diff --git a/crates/api_models/src/events.rs b/crates/api_models/src/events.rs index ad07340615b4..0ce7638b5ed1 100644 --- a/crates/api_models/src/events.rs +++ b/crates/api_models/src/events.rs @@ -1,5 +1,6 @@ pub mod customer; pub mod gsm; +mod locker_migration; pub mod payment; #[cfg(feature = "payouts")] pub mod payouts; diff --git a/crates/api_models/src/events/locker_migration.rs b/crates/api_models/src/events/locker_migration.rs new file mode 100644 index 000000000000..db76a8f760db --- /dev/null +++ b/crates/api_models/src/events/locker_migration.rs @@ -0,0 +1,9 @@ +use common_utils::events::ApiEventMetric; + +use crate::locker_migration::MigrateCardResponse; + +impl ApiEventMetric for MigrateCardResponse { + fn get_api_event_type(&self) -> Option { + Some(common_utils::events::ApiEventsType::RustLocker) + } +} diff --git a/crates/api_models/src/lib.rs b/crates/api_models/src/lib.rs index bcc3913ea824..40faa6b3e81d 100644 --- a/crates/api_models/src/lib.rs +++ b/crates/api_models/src/lib.rs @@ -13,6 +13,7 @@ pub mod errors; pub mod events; pub mod files; pub mod gsm; +pub mod locker_migration; pub mod mandates; pub mod organization; pub mod payment_methods; diff --git a/crates/api_models/src/locker_migration.rs b/crates/api_models/src/locker_migration.rs new file mode 100644 index 000000000000..6e2881cd463e --- /dev/null +++ b/crates/api_models/src/locker_migration.rs @@ -0,0 +1,8 @@ +#[derive(Debug, Clone, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MigrateCardResponse { + pub status_message: String, + pub status_code: String, + pub customers_moved: usize, + pub cards_moved: usize, +} diff --git a/crates/common_utils/src/events.rs b/crates/common_utils/src/events.rs index 753f1deeb676..14b8d4de1c36 100644 --- a/crates/common_utils/src/events.rs +++ b/crates/common_utils/src/events.rs @@ -44,6 +44,7 @@ pub enum ApiEventsType { Gsm, // TODO: This has to be removed once the corresponding apiEventTypes are created Miscellaneous, + RustLocker, } impl ApiEventMetric for serde_json::Value {} diff --git a/crates/router/src/configs/defaults.rs b/crates/router/src/configs/defaults.rs index 8d58037343e0..18a70a8100aa 100644 --- a/crates/router/src/configs/defaults.rs +++ b/crates/router/src/configs/defaults.rs @@ -48,6 +48,7 @@ impl Default for super::settings::Locker { fn default() -> Self { Self { host: "localhost".into(), + host_rs: "localhost".into(), mock_locker: true, basilisk_host: "localhost".into(), locker_signing_key_id: "1".into(), diff --git a/crates/router/src/configs/kms.rs b/crates/router/src/configs/kms.rs index 317ad0608b49..205169fa291b 100644 --- a/crates/router/src/configs/kms.rs +++ b/crates/router/src/configs/kms.rs @@ -18,6 +18,7 @@ impl KmsDecrypt for settings::Jwekey { self.locker_decryption_key1, self.locker_decryption_key2, self.vault_encryption_key, + self.rust_locker_encryption_key, self.vault_private_key, self.tunnel_private_key, ) = tokio::try_join!( @@ -26,6 +27,7 @@ impl KmsDecrypt for settings::Jwekey { kms_client.decrypt(self.locker_decryption_key1), kms_client.decrypt(self.locker_decryption_key2), kms_client.decrypt(self.vault_encryption_key), + kms_client.decrypt(self.rust_locker_encryption_key), kms_client.decrypt(self.vault_private_key), kms_client.decrypt(self.tunnel_private_key), )?; diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index c5b71c6f7341..0007e636926c 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -420,6 +420,7 @@ pub struct Secrets { #[serde(default)] pub struct Locker { pub host: String, + pub host_rs: String, pub mock_locker: bool, pub basilisk_host: String, pub locker_signing_key_id: String, @@ -448,6 +449,7 @@ pub struct Jwekey { pub locker_decryption_key1: String, pub locker_decryption_key2: String, pub vault_encryption_key: String, + pub rust_locker_encryption_key: String, pub vault_private_key: String, pub tunnel_private_key: String, } diff --git a/crates/router/src/core.rs b/crates/router/src/core.rs index b7023fe5ae46..8cc85eef60d6 100644 --- a/crates/router/src/core.rs +++ b/crates/router/src/core.rs @@ -9,6 +9,7 @@ pub mod disputes; pub mod errors; pub mod files; pub mod gsm; +pub mod locker_migration; pub mod mandate; pub mod metrics; pub mod payment_link; diff --git a/crates/router/src/core/locker_migration.rs b/crates/router/src/core/locker_migration.rs new file mode 100644 index 000000000000..aa82b4a3a636 --- /dev/null +++ b/crates/router/src/core/locker_migration.rs @@ -0,0 +1,131 @@ +use api_models::{enums as api_enums, locker_migration::MigrateCardResponse}; +use common_utils::errors::CustomResult; +use diesel_models::PaymentMethod; +use error_stack::{FutureExt, ResultExt}; +use futures::TryFutureExt; + +use super::{errors::StorageErrorExt, payment_methods::cards}; +use crate::{ + errors, + routes::AppState, + services::{self, logger}, + types::{api, domain}, +}; + +pub async fn rust_locker_migration( + state: AppState, + merchant_id: &str, +) -> CustomResult, errors::ApiErrorResponse> { + let db = state.store.as_ref(); + + let key_store = state + .store + .get_merchant_key_store_by_merchant_id( + merchant_id, + &state.store.get_master_key().to_vec().into(), + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError)?; + + let merchant_account = db + .find_merchant_account_by_merchant_id(merchant_id, &key_store) + .await + .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound) + .change_context(errors::ApiErrorResponse::InternalServerError)?; + + let domain_customers = db + .list_customers_by_merchant_id(merchant_id, &key_store) + .await + .change_context(errors::ApiErrorResponse::InternalServerError)?; + + let mut customers_moved = 0; + let mut cards_moved = 0; + + for customer in domain_customers { + let result = db + .find_payment_method_by_customer_id_merchant_id_list(&customer.customer_id, merchant_id) + .change_context(errors::ApiErrorResponse::InternalServerError) + .and_then(|pm| { + call_to_locker( + &state, + pm, + &customer.customer_id, + merchant_id, + &merchant_account, + ) + }) + .await?; + + customers_moved += 1; + cards_moved += result; + } + + Ok(services::api::ApplicationResponse::Json( + MigrateCardResponse { + status_code: "200".to_string(), + status_message: "Card migration completed".to_string(), + customers_moved, + cards_moved, + }, + )) +} + +pub async fn call_to_locker( + state: &AppState, + payment_methods: Vec, + customer_id: &String, + merchant_id: &str, + merchant_account: &domain::MerchantAccount, +) -> CustomResult { + let mut cards_moved = 0; + + for pm in payment_methods { + let card = + cards::get_card_from_locker(state, customer_id, merchant_id, &pm.payment_method_id) + .await?; + + let card_details = api::CardDetail { + card_number: card.card_number, + card_exp_month: card.card_exp_month, + card_exp_year: card.card_exp_year, + card_holder_name: card.name_on_card, + nick_name: card.nick_name.map(masking::Secret::new), + }; + + let pm_create = api::PaymentMethodCreate { + payment_method: pm.payment_method, + payment_method_type: pm.payment_method_type, + payment_method_issuer: pm.payment_method_issuer, + payment_method_issuer_code: pm.payment_method_issuer_code, + card: Some(card_details.clone()), + metadata: pm.metadata, + customer_id: Some(pm.customer_id), + card_network: card.card_brand, + }; + + let (_add_card_rs_resp, _is_duplicate) = cards::add_card_hs( + state, + pm_create, + card_details, + customer_id.to_string(), + merchant_account, + api_enums::LockerChoice::Tartarus, + Some(&pm.payment_method_id), + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable(format!( + "Card migration failed for merchant_id: {merchant_id}, customer_id: {customer_id}, payment_method_id: {} ", + pm.payment_method_id + ))?; + + cards_moved += 1; + + logger::info!( + "Card migrated for merchant_id: {merchant_id}, customer_id: {customer_id}, payment_method_id: {} ", + pm.payment_method_id + ); + } + + Ok(cards_moved) +} diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 38ab03ddcb77..f9c666cbb954 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -214,12 +214,20 @@ pub async fn add_card_to_locker( metrics::STORED_TO_LOCKER.add(&metrics::CONTEXT, 1, &[]); request::record_operation_time( async { - add_card_hs(state, req, card, customer_id, merchant_account) - .await - .map_err(|error| { - metrics::CARD_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); - error - }) + add_card_hs( + state, + req, + card, + customer_id, + merchant_account, + api_enums::LockerChoice::Basilisk, + None, + ) + .await + .map_err(|error| { + metrics::CARD_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); + error + }) }, &metrics::CARD_ADD_TIME, &[], @@ -282,10 +290,13 @@ pub async fn add_card_hs( card: api::CardDetail, customer_id: String, merchant_account: &domain::MerchantAccount, + locker_choice: api_enums::LockerChoice, + card_reference: Option<&str>, ) -> errors::CustomResult<(api::PaymentMethodResponse, bool), errors::VaultError> { let payload = payment_methods::StoreLockerReq::LockerCard(payment_methods::StoreCardReq { merchant_id: &merchant_account.merchant_id, merchant_customer_id: customer_id.to_owned(), + card_reference: card_reference.map(str::to_string), card: payment_methods::Card { card_number: card.card_number.to_owned(), name_on_card: card.card_holder_name.to_owned(), @@ -296,7 +307,8 @@ pub async fn add_card_hs( nick_name: card.nick_name.as_ref().map(masking::Secret::peek).cloned(), }, }); - let store_card_payload = call_to_locker_hs(state, &payload, &customer_id).await?; + let store_card_payload = + call_to_locker_hs(state, &payload, &customer_id, locker_choice).await?; let payment_method_resp = payment_methods::mk_add_card_response_hs( card, @@ -394,6 +406,7 @@ pub async fn call_to_locker_hs<'a>( state: &routes::AppState, payload: &payment_methods::StoreLockerReq<'a>, customer_id: &str, + locker_choice: api_enums::LockerChoice, ) -> errors::CustomResult { let locker = &state.conf.locker; #[cfg(not(feature = "kms"))] @@ -402,7 +415,9 @@ pub async fn call_to_locker_hs<'a>( let jwekey = &state.kms_secrets; let db = &*state.store; let stored_card_response = if !locker.mock_locker { - let request = payment_methods::mk_add_locker_request_hs(jwekey, locker, payload).await?; + let request = + payment_methods::mk_add_locker_request_hs(jwekey, locker, payload, locker_choice) + .await?; let response = services::call_connector_api(state, request) .await .change_context(errors::VaultError::SaveCardFailed); diff --git a/crates/router/src/core/payment_methods/transformers.rs b/crates/router/src/core/payment_methods/transformers.rs index 086133ec78a5..63a0479375e8 100644 --- a/crates/router/src/core/payment_methods/transformers.rs +++ b/crates/router/src/core/payment_methods/transformers.rs @@ -1,5 +1,6 @@ use std::str::FromStr; +use api_models::enums as api_enums; use common_utils::{ext_traits::StringExt, pii::Email}; use error_stack::ResultExt; use josekit::jwe; @@ -26,6 +27,8 @@ pub enum StoreLockerReq<'a> { pub struct StoreCardReq<'a> { pub merchant_id: &'a str, pub merchant_customer_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub card_reference: Option, pub card: Card, } @@ -224,6 +227,7 @@ pub async fn mk_basilisk_req( #[cfg(feature = "kms")] jwekey: &settings::ActiveKmsSecrets, #[cfg(not(feature = "kms"))] jwekey: &settings::Jwekey, jws: &str, + locker_choice: api_enums::LockerChoice, ) -> CustomResult { let jws_payload: Vec<&str> = jws.split('.').collect(); @@ -241,10 +245,18 @@ pub async fn mk_basilisk_req( .change_context(errors::VaultError::SaveCardFailed)?; #[cfg(feature = "kms")] - let public_key = jwekey.jwekey.peek().vault_encryption_key.as_bytes(); + let public_key = match locker_choice { + api_enums::LockerChoice::Basilisk => jwekey.jwekey.peek().vault_encryption_key.as_bytes(), + api_enums::LockerChoice::Tartarus => { + jwekey.jwekey.peek().rust_locker_encryption_key.as_bytes() + } + }; #[cfg(not(feature = "kms"))] - let public_key = jwekey.vault_encryption_key.as_bytes(); + let public_key = match locker_choice { + api_enums::LockerChoice::Basilisk => jwekey.vault_encryption_key.as_bytes(), + api_enums::LockerChoice::Tartarus => jwekey.rust_locker_encryption_key.as_bytes(), + }; let jwe_encrypted = encryption::encrypt_jwe(&payload, public_key) .await @@ -272,6 +284,7 @@ pub async fn mk_add_locker_request_hs<'a>( #[cfg(feature = "kms")] jwekey: &settings::ActiveKmsSecrets, locker: &settings::Locker, payload: &StoreLockerReq<'a>, + locker_choice: api_enums::LockerChoice, ) -> CustomResult { let payload = utils::Encode::>::encode_to_vec(&payload) .change_context(errors::VaultError::RequestEncodingFailed)?; @@ -286,11 +299,14 @@ pub async fn mk_add_locker_request_hs<'a>( .await .change_context(errors::VaultError::RequestEncodingFailed)?; - let jwe_payload = mk_basilisk_req(jwekey, &jws).await?; + let jwe_payload = mk_basilisk_req(jwekey, &jws, locker_choice).await?; let body = utils::Encode::::encode_to_value(&jwe_payload) .change_context(errors::VaultError::RequestEncodingFailed)?; - let mut url = locker.host.to_owned(); + let mut url = match locker_choice { + api_enums::LockerChoice::Basilisk => locker.host.to_owned(), + api_enums::LockerChoice::Tartarus => locker.host_rs.to_owned(), + }; url.push_str("/cards/add"); let mut request = services::Request::new(services::Method::Post, &url); request.add_header(headers::CONTENT_TYPE, "application/json".into()); @@ -432,7 +448,7 @@ pub async fn mk_get_card_request_hs( .await .change_context(errors::VaultError::RequestEncodingFailed)?; - let jwe_payload = mk_basilisk_req(jwekey, &jws).await?; + let jwe_payload = mk_basilisk_req(jwekey, &jws, api_enums::LockerChoice::Basilisk).await?; let body = utils::Encode::::encode_to_value(&jwe_payload) .change_context(errors::VaultError::RequestEncodingFailed)?; @@ -512,7 +528,7 @@ pub async fn mk_delete_card_request_hs( .await .change_context(errors::VaultError::RequestEncodingFailed)?; - let jwe_payload = mk_basilisk_req(jwekey, &jws).await?; + let jwe_payload = mk_basilisk_req(jwekey, &jws, api_enums::LockerChoice::Basilisk).await?; let body = utils::Encode::::encode_to_value(&jwe_payload) .change_context(errors::VaultError::RequestEncodingFailed)?; diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index 39079ea36cd6..c1e00b9b8000 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -152,6 +152,7 @@ pub async fn save_payout_data_to_locker( card_isin: None, nick_name: None, }, + card_reference: None, }); ( payload, @@ -195,9 +196,14 @@ pub async fn save_payout_data_to_locker( } }; // Store payout method in locker - let stored_resp = cards::call_to_locker_hs(state, &locker_req, &payout_attempt.customer_id) - .await - .change_context(errors::ApiErrorResponse::InternalServerError)?; + let stored_resp = cards::call_to_locker_hs( + state, + &locker_req, + &payout_attempt.customer_id, + api_enums::LockerChoice::Basilisk, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError)?; // Store card_reference in payouts table let db = &*state.store; diff --git a/crates/router/src/lib.rs b/crates/router/src/lib.rs index a3ed0b35c785..58d77d9e02f4 100644 --- a/crates/router/src/lib.rs +++ b/crates/router/src/lib.rs @@ -145,6 +145,7 @@ pub fn mk_app( .service(routes::Disputes::server(state.clone())) .service(routes::Analytics::server(state.clone())) .service(routes::Routing::server(state.clone())) + .service(routes::LockerMigrate::server(state.clone())) .service(routes::Gsm::server(state.clone())) .service(routes::User::server(state.clone())) } diff --git a/crates/router/src/routes.rs b/crates/router/src/routes.rs index 745433c2074b..5166e326fb91 100644 --- a/crates/router/src/routes.rs +++ b/crates/router/src/routes.rs @@ -29,6 +29,7 @@ pub mod user; pub mod verification; pub mod webhooks; +pub mod locker_migration; #[cfg(feature = "dummy_connector")] pub use self::app::DummyConnector; #[cfg(feature = "payouts")] @@ -39,8 +40,8 @@ pub use self::app::Routing; pub use self::app::Verify; pub use self::app::{ ApiKeys, AppState, BusinessProfile, Cache, Cards, Configs, Customers, Disputes, EphemeralKey, - Files, Gsm, Health, Mandates, MerchantAccount, MerchantConnectorAccount, PaymentLink, - PaymentMethods, Payments, Refunds, User, Webhooks, + Files, Gsm, Health, LockerMigrate, Mandates, MerchantAccount, MerchantConnectorAccount, + PaymentLink, PaymentMethods, Payments, Refunds, User, Webhooks, }; #[cfg(feature = "stripe")] pub use super::compatibility::stripe::StripeApis; diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 15b6df733489..070f1eb29bf8 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -19,7 +19,7 @@ use super::routing as cloud_routing; #[cfg(all(feature = "olap", feature = "kms"))] use super::verification::{apple_pay_merchant_registration, retrieve_apple_pay_verified_domains}; #[cfg(feature = "olap")] -use super::{admin::*, api_keys::*, disputes::*, files::*, gsm::*, user::*}; +use super::{admin::*, api_keys::*, disputes::*, files::*, gsm::*, locker_migration, user::*}; use super::{cache::*, health::*, payment_link::*}; #[cfg(any(feature = "olap", feature = "oltp"))] use super::{configs::*, customers::*, mandates::*, payments::*, refunds::*}; @@ -743,3 +743,16 @@ impl User { .service(web::resource("/v2/signup").route(web::post().to(user_connect_account))) } } + +pub struct LockerMigrate; + +#[cfg(feature = "olap")] +impl LockerMigrate { + pub fn server(state: AppState) -> Scope { + web::scope("locker_migration/{merchant_id}") + .app_data(web::Data::new(state)) + .service( + web::resource("").route(web::post().to(locker_migration::rust_locker_migration)), + ) + } +} diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs index ae573e871627..c093523d455a 100644 --- a/crates/router/src/routes/lock_utils.rs +++ b/crates/router/src/routes/lock_utils.rs @@ -23,6 +23,7 @@ pub enum ApiIdentifier { ApiKeys, PaymentLink, Routing, + RustLockerMigration, Gsm, User, } @@ -131,6 +132,7 @@ impl From for ApiIdentifier { Flow::Verification => Self::Verification, Flow::PaymentLinkInitiate | Flow::PaymentLinkRetrieve => Self::PaymentLink, + Flow::RustLockerMigration => Self::RustLockerMigration, Flow::GsmRuleCreate | Flow::GsmRuleRetrieve | Flow::GsmRuleUpdate diff --git a/crates/router/src/routes/locker_migration.rs b/crates/router/src/routes/locker_migration.rs new file mode 100644 index 000000000000..892dc5941bd6 --- /dev/null +++ b/crates/router/src/routes/locker_migration.rs @@ -0,0 +1,27 @@ +use actix_web::{web, HttpRequest, HttpResponse}; +use router_env::Flow; + +use super::AppState; +use crate::{ + core::{api_locking, locker_migration}, + services::{api, authentication as auth}, +}; + +pub async fn rust_locker_migration( + state: web::Data, + req: HttpRequest, + path: web::Path, +) -> HttpResponse { + let flow = Flow::RustLockerMigration; + let merchant_id = path.into_inner(); + api::server_wrap( + flow, + state, + &req, + &merchant_id, + |state, _, _| locker_migration::rust_locker_migration(state, &merchant_id), + &auth::AdminApiAuth, + api_locking::LockAction::NotApplicable, + ) + .await +} diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs index 9cd678083959..3bfd1ef7d9f8 100644 --- a/crates/router_env/src/logger/types.rs +++ b/crates/router_env/src/logger/types.rs @@ -235,6 +235,8 @@ pub enum Flow { BusinessProfileList, /// Different verification flows Verification, + /// Rust locker migration + RustLockerMigration, /// Gsm Rule Creation flow GsmRuleCreate, /// Gsm Rule Retrieve flow diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml index f70fc656d8e3..2fb729fb7b90 100644 --- a/loadtest/config/development.toml +++ b/loadtest/config/development.toml @@ -30,6 +30,7 @@ jwt_secret = "secret" [locker] host = "" +host_rs = "" mock_locker = true basilisk_host = "" @@ -48,6 +49,7 @@ locker_encryption_key2 = "" locker_decryption_key1 = "" locker_decryption_key2 = "" vault_encryption_key = "" +rust_locker_encryption_key = "" vault_private_key = "" [webhooks]