Skip to content

Commit

Permalink
feature flagged
Browse files Browse the repository at this point in the history
  • Loading branch information
racnan committed Dec 18, 2024
1 parent 00a063f commit 1624383
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 12 deletions.
3 changes: 2 additions & 1 deletion crates/router/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ license.workspace = true

[features]
default = ["common_default", "v1"]
common_default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"]
common_default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id","platform"]
olap = ["hyperswitch_domain_models/olap", "storage_impl/olap", "scheduler/olap", "api_models/olap", "dep:analytics"]
tls = ["actix-web/rustls-0_22"]
email = ["external_services/email", "scheduler/email", "olap"]
Expand Down Expand Up @@ -38,6 +38,7 @@ v1 = ["common_default", "api_models/v1", "diesel_models/v1", "hyperswitch_domain
customer_v2 = ["api_models/customer_v2", "diesel_models/customer_v2", "hyperswitch_domain_models/customer_v2", "storage_impl/customer_v2"]
payment_methods_v2 = ["api_models/payment_methods_v2", "diesel_models/payment_methods_v2", "hyperswitch_domain_models/payment_methods_v2", "storage_impl/payment_methods_v2", "common_utils/payment_methods_v2"]
dynamic_routing = ["external_services/dynamic_routing", "storage_impl/dynamic_routing", "api_models/dynamic_routing"]
platform = []

# Partial Auth
# The feature reduces the overhead of the router authenticating the merchant for every request, and trusts on `x-merchant-id` header to be present in the request.
Expand Down
1 change: 1 addition & 0 deletions crates/router/src/core/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4767,6 +4767,7 @@ async fn locker_recipient_create_call(
Ok(store_resp.card_reference)
}

#[cfg(feature = "platform")]
pub async fn enable_platform_account(
state: SessionState,
merchant_id: id_type::MerchantId,
Expand Down
3 changes: 2 additions & 1 deletion crates/router/src/routes/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,7 @@ pub async fn merchant_account_transfer_keys(
/// Merchant Account - Platform Account
///
/// Enable platform account
#[cfg(feature = "platform")]
#[instrument(skip_all)]
pub async fn merchant_account_enable_platform_account(
state: web::Data<AppState>,
Expand All @@ -927,7 +928,7 @@ pub async fn merchant_account_enable_platform_account(
state,
&req,
merchant_id,
|state, _, req, _| enable_platform_account(state, req),
|state, _, req, _| enable_platform_account(state, req),
&auth::AdminApiAuth,
api_locking::LockAction::NotApplicable,
))
Expand Down
12 changes: 10 additions & 2 deletions crates/router/src/routes/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1315,7 +1315,8 @@ impl MerchantAccount {
#[cfg(all(feature = "olap", feature = "v1"))]
impl MerchantAccount {
pub fn server(state: AppState) -> Scope {
web::scope("/accounts")
#[allow(unused_mut)]
let mut routes = web::scope("/accounts")
.app_data(web::Data::new(state))
.service(web::resource("").route(web::post().to(admin::merchant_account_create)))
.service(web::resource("/list").route(web::get().to(admin::merchant_account_list)))
Expand All @@ -1324,7 +1325,6 @@ impl MerchantAccount {
.route(web::post().to(admin::merchant_account_toggle_kv))
.route(web::get().to(admin::merchant_account_kv_status)),
)
.service(web::resource("/{id}/platform").route(web::post().to(admin::merchant_account_enable_platform_account)))
.service(
web::resource("/transfer")
.route(web::post().to(admin::merchant_account_transfer_keys)),
Expand All @@ -1337,7 +1337,15 @@ impl MerchantAccount {
.route(web::get().to(admin::retrieve_merchant_account))
.route(web::post().to(admin::update_merchant_account))
.route(web::delete().to(admin::delete_merchant_account)),
);
#[cfg(feature = "platform")]
{
routes = routes.service(
web::resource("/{id}/platform")
.route(web::post().to(admin::merchant_account_enable_platform_account)),
)
}
routes
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/routes/lock_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl From<Flow> for ApiIdentifier {
| Flow::MerchantsAccountDelete
| Flow::MerchantTransferKey
| Flow::MerchantAccountList
| Flow::EnablePlatformAccount=> Self::MerchantAccount,
| Flow::EnablePlatformAccount => Self::MerchantAccount,

Flow::OrganizationCreate | Flow::OrganizationRetrieve | Flow::OrganizationUpdate => {
Self::Organization
Expand Down
61 changes: 54 additions & 7 deletions crates/router/src/services/authentication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use api_models::payouts;
use api_models::{payment_methods::PaymentMethodListRequest, payments};
use async_trait::async_trait;
use common_enums::TokenPurpose;
use common_utils::{date_time, ext_traits::AsyncExt, id_type};
#[cfg(feature = "platform")]
use common_utils::ext_traits::AsyncExt;
use common_utils::{date_time, id_type};
use error_stack::{report, ResultExt};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use masking::PeekInterface;
Expand Down Expand Up @@ -463,8 +465,16 @@ where
.to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

// Get connected merchant account if API call is done by Platform merchant account on behalf of connected merchant account
let (merchant, platform_merchant_account) =
get_platform_merchant_account(state, request_headers, merchant).await?;
let (merchant, platform_merchant_account) = {
#[cfg(feature = "platform")]
{
get_platform_merchant_account(state, request_headers, merchant).await?
}
#[cfg(not(feature = "platform"))]
{
(merchant, None)
}
};

let key_store = {
if platform_merchant_account.is_some() {
Expand Down Expand Up @@ -573,8 +583,16 @@ where
.to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

// Get connected merchant account if API call is done by Platform merchant account on behalf of connected merchant account
let (merchant, platform_merchant_account) =
get_platform_merchant_account(state, request_headers, merchant).await?;
let (merchant, platform_merchant_account) = {
#[cfg(feature = "platform")]
{
get_platform_merchant_account(state, request_headers, merchant).await?
}
#[cfg(not(feature = "platform"))]
{
(merchant, None)
}
};

let auth = AuthenticationData {
merchant_account: merchant,
Expand Down Expand Up @@ -741,6 +759,7 @@ where
}

#[cfg(all(feature = "partial-auth", feature = "v1"))]
#[allow(unused)]
async fn construct_authentication_data<A>(
state: &A,
merchant_id: &id_type::MerchantId,
Expand Down Expand Up @@ -771,8 +790,16 @@ where
.to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

// Get connected merchant account if API call is done by Platform merchant account on behalf of connected merchant account
let (merchant, platform_merchant_account) =
get_platform_merchant_account(state, request_headers, merchant).await?;
let (merchant, platform_merchant_account) = {
#[cfg(feature = "platform")]
{
get_platform_merchant_account(state, request_headers, merchant).await?
}
#[cfg(not(feature = "platform"))]
{
(merchant, None)
}
};

let auth = AuthenticationData {
merchant_account: merchant,
Expand Down Expand Up @@ -1049,7 +1076,9 @@ where
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
#[cfg(feature = "platform")]
throw_error_if_platform_merchant_authentication_required(request_headers)?;

AdminApiAuth
.authenticate_and_fetch(request_headers, state)
.await?;
Expand Down Expand Up @@ -1110,7 +1139,9 @@ where
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(AuthenticationDataWithoutProfile, AuthenticationType)> {
#[cfg(feature = "platform")]
throw_error_if_platform_merchant_authentication_required(request_headers)?;

AdminApiAuth
.authenticate_and_fetch(request_headers, state)
.await?;
Expand Down Expand Up @@ -1210,6 +1241,8 @@ impl<'a> HeaderMapStruct<'a> {
})
}

// Remove feature flag if required.
#[cfg(feature = "platform")]
pub fn get_id_type_from_header_if_present<T>(&self, key: &str) -> RouterResult<Option<T>>
where
T: TryFrom<
Expand Down Expand Up @@ -1302,7 +1335,9 @@ where
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
#[cfg(feature = "platform")]
throw_error_if_platform_merchant_authentication_required(request_headers)?;

AdminApiAuth
.authenticate_and_fetch(request_headers, state)
.await?;
Expand Down Expand Up @@ -1364,7 +1399,9 @@ where
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(AuthenticationDataWithoutProfile, AuthenticationType)> {
#[cfg(feature = "platform")]
throw_error_if_platform_merchant_authentication_required(request_headers)?;

AdminApiAuth
.authenticate_and_fetch(request_headers, state)
.await?;
Expand Down Expand Up @@ -1431,6 +1468,7 @@ pub struct MerchantIdAuth(pub id_type::MerchantId);

#[cfg(feature = "v1")]
#[async_trait]
#[allow(unused)]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for MerchantIdAuth
where
A: SessionStateInfo + Sync,
Expand All @@ -1440,6 +1478,7 @@ where
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
#[cfg(feature = "platform")]
throw_error_if_platform_merchant_authentication_required(request_headers)?;

let key_manager_state = &(&state.session_state()).into();
Expand Down Expand Up @@ -1485,7 +1524,9 @@ where
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
#[cfg(feature = "platform")]
throw_error_if_platform_merchant_authentication_required(request_headers)?;

let key_manager_state = &(&state.session_state()).into();
let profile_id =
get_id_type_by_key_from_headers(headers::X_PROFILE_ID.to_string(), request_headers)?
Expand Down Expand Up @@ -1549,7 +1590,9 @@ where
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
#[cfg(feature = "platform")]
throw_error_if_platform_merchant_authentication_required(request_headers)?;

let key_manager_state = &(&state.session_state()).into();
let key_store = state
.store()
Expand Down Expand Up @@ -1669,6 +1712,7 @@ where
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
#[cfg(feature = "platform")]
throw_error_if_platform_merchant_authentication_required(request_headers)?;

let publishable_key =
Expand Down Expand Up @@ -3332,6 +3376,7 @@ where
}
}

#[cfg(feature = "platform")]
async fn get_connected_merchant_account<A>(
state: &A,
connected_merchant_id: id_type::MerchantId,
Expand Down Expand Up @@ -3367,6 +3412,7 @@ where
Ok(connected_merchant_account)
}

#[cfg(feature = "platform")]
async fn get_platform_merchant_account<A>(
state: &A,
request_headers: &HeaderMap,
Expand Down Expand Up @@ -3404,6 +3450,7 @@ where
}
}

#[cfg(feature = "platform")]
fn throw_error_if_platform_merchant_authentication_required(
request_headers: &HeaderMap,
) -> RouterResult<()> {
Expand Down

0 comments on commit 1624383

Please sign in to comment.