mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 04:04:43 +08:00
feat(api_keys): add api keys route to api v2 (#5709)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -2705,7 +2705,8 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate {
|
||||
pub async fn create_connector(
|
||||
state: SessionState,
|
||||
req: api::MerchantConnectorCreate,
|
||||
merchant_id: &id_type::MerchantId,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
) -> RouterResponse<api_models::admin::MerchantConnectorResponse> {
|
||||
let store = state.store.as_ref();
|
||||
let key_manager_state = &(&state).into();
|
||||
@ -2716,27 +2717,13 @@ pub async fn create_connector(
|
||||
.change_context(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: "Invalid connector name".to_string(),
|
||||
})?;
|
||||
|
||||
let key_store = store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
merchant_id,
|
||||
&state.store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
let connector_metadata = ConnectorMetadata {
|
||||
connector_metadata: &req.metadata,
|
||||
};
|
||||
|
||||
connector_metadata.validate_apple_pay_certificates_in_mca_metadata()?;
|
||||
let merchant_id = merchant_account.get_id();
|
||||
|
||||
let merchant_account = state
|
||||
.store
|
||||
.find_merchant_account_by_merchant_id(key_manager_state, merchant_id, &key_store)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
connector_metadata.validate_apple_pay_certificates_in_mca_metadata()?;
|
||||
|
||||
#[cfg(all(
|
||||
any(feature = "v1", feature = "v2"),
|
||||
@ -2956,19 +2943,14 @@ pub async fn retrieve_connector(
|
||||
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
|
||||
pub async fn retrieve_connector(
|
||||
state: SessionState,
|
||||
merchant_id: id_type::MerchantId,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
id: id_type::MerchantConnectorAccountId,
|
||||
) -> RouterResponse<api_models::admin::MerchantConnectorResponse> {
|
||||
let store = state.store.as_ref();
|
||||
let key_manager_state = &(&state).into();
|
||||
let key_store = store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&merchant_id,
|
||||
&store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
let merchant_id = merchant_account.get_id();
|
||||
|
||||
let mca = store
|
||||
.find_merchant_connector_account_by_id(key_manager_state, &id, &key_store)
|
||||
@ -2978,7 +2960,7 @@ pub async fn retrieve_connector(
|
||||
})?;
|
||||
|
||||
// Validate if the merchant_id sent in the request is valid
|
||||
if mca.merchant_id != merchant_id {
|
||||
if mca.merchant_id != *merchant_id {
|
||||
return Err(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: format!(
|
||||
"Invalid merchant_id {} provided for merchant_connector_account {:?}",
|
||||
@ -3174,19 +3156,14 @@ pub async fn delete_connector(
|
||||
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
|
||||
pub async fn delete_connector(
|
||||
state: SessionState,
|
||||
merchant_id: id_type::MerchantId,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
id: id_type::MerchantConnectorAccountId,
|
||||
) -> RouterResponse<api::MerchantConnectorDeleteResponse> {
|
||||
let db = state.store.as_ref();
|
||||
let key_manager_state = &(&state).into();
|
||||
let key_store = db
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&merchant_id,
|
||||
&db.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
let merchant_id = merchant_account.get_id();
|
||||
|
||||
let mca = db
|
||||
.find_merchant_connector_account_by_id(key_manager_state, &id, &key_store)
|
||||
@ -3196,7 +3173,7 @@ pub async fn delete_connector(
|
||||
})?;
|
||||
|
||||
// Validate if the merchant_id sent in the request is valid
|
||||
if mca.merchant_id != merchant_id {
|
||||
if mca.merchant_id != *merchant_id {
|
||||
return Err(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: format!(
|
||||
"Invalid merchant_id {} provided for merchant_connector_account {:?}",
|
||||
@ -3215,7 +3192,7 @@ pub async fn delete_connector(
|
||||
})?;
|
||||
|
||||
let response = api::MerchantConnectorDeleteResponse {
|
||||
merchant_id,
|
||||
merchant_id: merchant_id.clone(),
|
||||
id,
|
||||
deleted: is_deleted,
|
||||
};
|
||||
@ -3678,25 +3655,11 @@ impl BusinessProfileCreateBridge for api::BusinessProfileCreate {
|
||||
pub async fn create_business_profile(
|
||||
state: SessionState,
|
||||
request: api::BusinessProfileCreate,
|
||||
merchant_id: &id_type::MerchantId,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
) -> RouterResponse<api_models::admin::BusinessProfileResponse> {
|
||||
let db = state.store.as_ref();
|
||||
let key_manager_state = &(&state).into();
|
||||
let key_store = db
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
merchant_id,
|
||||
&db.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
// Get the merchant account, if few fields are not passed, then they will be inherited from
|
||||
// merchant account
|
||||
let merchant_account = db
|
||||
.find_merchant_account_by_merchant_id(key_manager_state, merchant_id, &key_store)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
#[cfg(all(
|
||||
any(feature = "v1", feature = "v2"),
|
||||
@ -3780,17 +3743,10 @@ pub async fn list_business_profile(
|
||||
pub async fn retrieve_business_profile(
|
||||
state: SessionState,
|
||||
profile_id: id_type::ProfileId,
|
||||
merchant_id: id_type::MerchantId,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
) -> RouterResponse<api_models::admin::BusinessProfileResponse> {
|
||||
let db = state.store.as_ref();
|
||||
let key_store = db
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
&(&state).into(),
|
||||
&merchant_id,
|
||||
&db.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
let business_profile = db
|
||||
.find_business_profile_by_profile_id(&(&state).into(), &key_store, &profile_id)
|
||||
.await
|
||||
@ -4042,19 +3998,10 @@ impl BusinessProfileUpdateBridge for api::BusinessProfileUpdate {
|
||||
pub async fn update_business_profile(
|
||||
state: SessionState,
|
||||
profile_id: &id_type::ProfileId,
|
||||
merchant_id: &id_type::MerchantId,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
request: api::BusinessProfileUpdate,
|
||||
) -> RouterResponse<api::BusinessProfileResponse> {
|
||||
let db = state.store.as_ref();
|
||||
let key_store = db
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
&(&state).into(),
|
||||
merchant_id,
|
||||
&state.store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)
|
||||
.attach_printable("Error while fetching the key store by merchant_id")?;
|
||||
let key_manager_state = &(&state).into();
|
||||
|
||||
let business_profile = db
|
||||
@ -4064,12 +4011,6 @@ pub async fn update_business_profile(
|
||||
id: profile_id.get_string_repr().to_owned(),
|
||||
})?;
|
||||
|
||||
if business_profile.merchant_id != *merchant_id {
|
||||
Err(errors::ApiErrorResponse::AccessForbidden {
|
||||
resource: profile_id.get_string_repr().to_owned(),
|
||||
})?
|
||||
}
|
||||
|
||||
let business_profile_update = request
|
||||
.get_update_business_profile_object(&state, &key_store)
|
||||
.await?;
|
||||
|
||||
@ -9,6 +9,7 @@ use crate::{
|
||||
configs::settings,
|
||||
consts,
|
||||
core::errors::{self, RouterResponse, StorageErrorExt},
|
||||
db::domain,
|
||||
routes::{metrics, SessionState},
|
||||
services::{authentication, ApplicationResponse},
|
||||
types::{api, storage, transformers::ForeignInto},
|
||||
@ -112,22 +113,12 @@ impl PlaintextApiKey {
|
||||
pub async fn create_api_key(
|
||||
state: SessionState,
|
||||
api_key: api::CreateApiKeyRequest,
|
||||
merchant_id: common_utils::id_type::MerchantId,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
) -> RouterResponse<api::CreateApiKeyResponse> {
|
||||
let api_key_config = state.conf.api_keys.get_inner();
|
||||
let store = state.store.as_ref();
|
||||
// We are not fetching merchant account as the merchant key store is needed to search for a
|
||||
// merchant account.
|
||||
// Instead, we're only fetching merchant key store, as it is sufficient to identify
|
||||
// non-existence of a merchant account.
|
||||
store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
&(&state).into(),
|
||||
&merchant_id,
|
||||
&store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
let merchant_id = key_store.merchant_id.clone();
|
||||
|
||||
let hash_key = api_key_config.get_hash_key()?;
|
||||
let plaintext_api_key = PlaintextApiKey::new(consts::API_KEY_LENGTH);
|
||||
@ -266,12 +257,12 @@ pub async fn add_api_key_expiry_task(
|
||||
#[instrument(skip_all)]
|
||||
pub async fn retrieve_api_key(
|
||||
state: SessionState,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
merchant_id: common_utils::id_type::MerchantId,
|
||||
key_id: &str,
|
||||
) -> RouterResponse<api::RetrieveApiKeyResponse> {
|
||||
let store = state.store.as_ref();
|
||||
let api_key = store
|
||||
.find_api_key_by_merchant_id_key_id_optional(merchant_id, key_id)
|
||||
.find_api_key_by_merchant_id_key_id_optional(&merchant_id, key_id)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError) // If retrieve failed
|
||||
.attach_printable("Failed to retrieve API key")?
|
||||
|
||||
@ -1,13 +1,7 @@
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
|
||||
use error_stack::ResultExt;
|
||||
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
|
||||
use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse;
|
||||
use router_env::{instrument, tracing, Flow};
|
||||
|
||||
use super::app::AppState;
|
||||
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
|
||||
use crate::headers;
|
||||
use crate::{
|
||||
core::{admin::*, api_locking},
|
||||
services::{api, authentication as auth, authorization::permissions::Permission},
|
||||
@ -102,18 +96,6 @@ pub async fn merchant_account_create(
|
||||
/// Merchant Account - Retrieve
|
||||
///
|
||||
/// Retrieve a merchant account details.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/accounts/{account_id}",
|
||||
params (("account_id" = String, Path, description = "The unique identifier for the merchant account")),
|
||||
responses(
|
||||
(status = 200, description = "Merchant Account Retrieved", body = MerchantAccountResponse),
|
||||
(status = 404, description = "Merchant account not found")
|
||||
),
|
||||
tag = "Merchant Account",
|
||||
operation_id = "Retrieve a Merchant Account",
|
||||
security(("admin_api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountRetrieve))]
|
||||
pub async fn retrieve_merchant_account(
|
||||
state: web::Data<AppState>,
|
||||
@ -168,19 +150,6 @@ pub async fn merchant_account_list(
|
||||
/// Merchant Account - Update
|
||||
///
|
||||
/// To update an existing merchant account. Helpful in updating merchant details such as email, contact details, or other configuration details like webhook, routing algorithm etc
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/accounts/{account_id}",
|
||||
request_body = MerchantAccountUpdate,
|
||||
params (("account_id" = String, Path, description = "The unique identifier for the merchant account")),
|
||||
responses(
|
||||
(status = 200, description = "Merchant Account Updated", body = MerchantAccountResponse),
|
||||
(status = 404, description = "Merchant account not found")
|
||||
),
|
||||
tag = "Merchant Account",
|
||||
operation_id = "Update a Merchant Account",
|
||||
security(("admin_api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountUpdate))]
|
||||
pub async fn update_merchant_account(
|
||||
state: web::Data<AppState>,
|
||||
@ -212,20 +181,7 @@ pub async fn update_merchant_account(
|
||||
/// Merchant Account - Delete
|
||||
///
|
||||
/// To delete a merchant account
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/accounts/{account_id}",
|
||||
params (("account_id" = String, Path, description = "The unique identifier for the merchant account")),
|
||||
responses(
|
||||
(status = 200, description = "Merchant Account Deleted", body = MerchantAccountDeleteResponse),
|
||||
(status = 404, description = "Merchant account not found")
|
||||
),
|
||||
tag = "Merchant Account",
|
||||
operation_id = "Delete a Merchant Account",
|
||||
security(("admin_api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::MerchantsAccountDelete))]
|
||||
// #[delete("/{id}")]
|
||||
pub async fn delete_merchant_account(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
@ -247,52 +203,6 @@ pub async fn delete_merchant_account(
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
|
||||
struct HeaderMapStruct<'a> {
|
||||
headers: &'a actix_http::header::HeaderMap,
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
|
||||
impl<'a> HeaderMapStruct<'a> {
|
||||
pub fn from(request: &'a HttpRequest) -> Self {
|
||||
HeaderMapStruct {
|
||||
headers: request.headers(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mandatory_header_value_by_key(
|
||||
&self,
|
||||
key: String,
|
||||
) -> Result<&str, error_stack::Report<ApiErrorResponse>> {
|
||||
self.headers
|
||||
.get(&key)
|
||||
.ok_or(ApiErrorResponse::InvalidRequestData {
|
||||
message: format!("Missing header key: {}", key),
|
||||
})
|
||||
.attach_printable(format!("Failed to find header key: {}", key))?
|
||||
.to_str()
|
||||
.change_context(ApiErrorResponse::InternalServerError)
|
||||
.attach_printable(format!(
|
||||
"Failed to convert header value to string for header key: {}",
|
||||
key
|
||||
))
|
||||
}
|
||||
|
||||
pub fn get_merchant_id_from_header(
|
||||
&self,
|
||||
) -> crate::errors::RouterResult<common_utils::id_type::MerchantId> {
|
||||
self.get_mandatory_header_value_by_key(headers::X_MERCHANT_ID.into())
|
||||
.map(|val| val.to_owned())
|
||||
.and_then(|merchant_id| {
|
||||
common_utils::id_type::MerchantId::wrap(merchant_id)
|
||||
.change_context(ApiErrorResponse::InternalServerError)
|
||||
.attach_printable(
|
||||
"Error while converting MerchantId from `x-merchant-id` string header",
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Merchant Connector - Create
|
||||
///
|
||||
/// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc."
|
||||
@ -300,18 +210,6 @@ impl<'a> HeaderMapStruct<'a> {
|
||||
any(feature = "v1", feature = "v2"),
|
||||
not(feature = "merchant_connector_account_v2")
|
||||
))]
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/accounts/{account_id}/connectors",
|
||||
request_body = MerchantConnectorCreate,
|
||||
responses(
|
||||
(status = 200, description = "Merchant Connector Created", body = MerchantConnectorResponse),
|
||||
(status = 400, description = "Missing Mandatory fields"),
|
||||
),
|
||||
tag = "Merchant Connector Account",
|
||||
operation_id = "Create a Merchant Connector",
|
||||
security(("admin_api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::MerchantConnectorsCreate))]
|
||||
pub async fn connector_create(
|
||||
state: web::Data<AppState>,
|
||||
@ -327,9 +225,11 @@ pub async fn connector_create(
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, _, req, _| create_connector(state, req, &merchant_id),
|
||||
|state, auth_data, req, _| {
|
||||
create_connector(state, req, auth_data.merchant_account, auth_data.key_store)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::AdminApiAuthWithMerchantIdFromRoute(merchant_id.clone()),
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
required_permission: Permission::MerchantConnectorAccountWrite,
|
||||
@ -344,18 +244,6 @@ pub async fn connector_create(
|
||||
///
|
||||
/// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc."
|
||||
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/connector_accounts",
|
||||
request_body = MerchantConnectorCreate,
|
||||
responses(
|
||||
(status = 200, description = "Merchant Connector Created", body = MerchantConnectorResponse),
|
||||
(status = 400, description = "Missing Mandatory fields"),
|
||||
),
|
||||
tag = "Merchant Connector Account",
|
||||
operation_id = "Create a Merchant Connector",
|
||||
security(("admin_api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::MerchantConnectorsCreate))]
|
||||
pub async fn connector_create(
|
||||
state: web::Data<AppState>,
|
||||
@ -364,17 +252,17 @@ pub async fn connector_create(
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::MerchantConnectorsCreate;
|
||||
let payload = json_payload.into_inner();
|
||||
let merchant_id = payload.merchant_id.clone();
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, _, req, _| create_connector(state, req, &merchant_id),
|
||||
|state, auth_data, req, _| {
|
||||
create_connector(state, req, auth_data.merchant_account, auth_data.key_store)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromHeader {
|
||||
required_permission: Permission::MerchantConnectorAccountWrite,
|
||||
},
|
||||
req.headers(),
|
||||
@ -437,7 +325,7 @@ pub async fn connector_retrieve(
|
||||
)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuthWithMerchantId::default(),
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id,
|
||||
required_permission: Permission::MerchantConnectorAccountRead,
|
||||
@ -452,21 +340,6 @@ pub async fn connector_retrieve(
|
||||
///
|
||||
/// Retrieve Merchant Connector Details
|
||||
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/connector_accounts/{id}",
|
||||
params(
|
||||
("id" = i32, Path, description = "The unique identifier for the Merchant Connector")
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Merchant Connector retrieved successfully", body = MerchantConnectorResponse),
|
||||
(status = 404, description = "Merchant Connector does not exist in records"),
|
||||
(status = 401, description = "Unauthorized request")
|
||||
),
|
||||
tag = "Merchant Connector Account",
|
||||
operation_id = "Retrieve a Merchant Connector",
|
||||
security(("admin_api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::MerchantConnectorsRetrieve))]
|
||||
pub async fn connector_retrieve(
|
||||
state: web::Data<AppState>,
|
||||
@ -477,23 +350,22 @@ pub async fn connector_retrieve(
|
||||
let id = path.into_inner();
|
||||
let payload = web::Json(admin::MerchantConnectorId { id: id.clone() }).into_inner();
|
||||
|
||||
let merchant_id = match HeaderMapStruct::from(&req).get_merchant_id_from_header() {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
return api::log_and_return_error_response(err);
|
||||
}
|
||||
};
|
||||
|
||||
api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, _, req, _| retrieve_connector(state, merchant_id.clone(), req.id.clone()),
|
||||
|state, auth_data, req, _| {
|
||||
retrieve_connector(
|
||||
state,
|
||||
auth_data.merchant_account,
|
||||
auth_data.key_store,
|
||||
req.id.clone(),
|
||||
)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromHeader {
|
||||
required_permission: Permission::MerchantConnectorAccountRead,
|
||||
},
|
||||
req.headers(),
|
||||
@ -536,7 +408,7 @@ pub async fn payment_connector_list(
|
||||
merchant_id.to_owned(),
|
||||
|state, _auth, merchant_id, _| list_payment_connectors(state, merchant_id, None),
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuthWithMerchantId::default(),
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id,
|
||||
required_permission: Permission::MerchantConnectorAccountRead,
|
||||
@ -587,7 +459,7 @@ pub async fn payment_connector_list_profile(
|
||||
)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuthWithMerchantId::default(),
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id,
|
||||
required_permission: Permission::MerchantConnectorAccountRead,
|
||||
@ -650,7 +522,7 @@ pub async fn connector_update(
|
||||
)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuthWithMerchantId::default(),
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
required_permission: Permission::MerchantConnectorAccountWrite,
|
||||
@ -774,21 +646,6 @@ pub async fn connector_delete(
|
||||
///
|
||||
/// Delete or Detach a Merchant Connector from Merchant Account
|
||||
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/connector_accounts/{id}",
|
||||
params(
|
||||
("id" = i32, Path, description = "The unique identifier for the Merchant Connector")
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Merchant Connector Deleted", body = MerchantConnectorDeleteResponse),
|
||||
(status = 404, description = "Merchant Connector does not exist in records"),
|
||||
(status = 401, description = "Unauthorized request")
|
||||
),
|
||||
tag = "Merchant Connector Account",
|
||||
operation_id = "Delete a Merchant Connector",
|
||||
security(("admin_api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::MerchantConnectorsDelete))]
|
||||
pub async fn connector_delete(
|
||||
state: web::Data<AppState>,
|
||||
@ -799,25 +656,22 @@ pub async fn connector_delete(
|
||||
let id = path.into_inner();
|
||||
|
||||
let payload = web::Json(admin::MerchantConnectorId { id: id.clone() }).into_inner();
|
||||
let header_map = HeaderMapStruct {
|
||||
headers: req.headers(),
|
||||
};
|
||||
let merchant_id = match header_map.get_merchant_id_from_header() {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
return api::log_and_return_error_response(err);
|
||||
}
|
||||
};
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, _, req, _| delete_connector(state, merchant_id.clone(), req.id),
|
||||
|state, auth_data, req, _| {
|
||||
delete_connector(
|
||||
state,
|
||||
auth_data.merchant_account,
|
||||
auth_data.key_store,
|
||||
req.id,
|
||||
)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromHeader {
|
||||
required_permission: Permission::MerchantConnectorAccountWrite,
|
||||
},
|
||||
req.headers(),
|
||||
@ -897,11 +751,13 @@ pub async fn business_profile_create(
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, _, req, _| create_business_profile(state, req, &merchant_id),
|
||||
|state, auth_data, req, _| {
|
||||
create_business_profile(state, req, auth_data.merchant_account, auth_data.key_store)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::AdminApiAuthWithMerchantIdFromRoute(merchant_id.clone()),
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
merchant_id,
|
||||
required_permission: Permission::MerchantAccountWrite,
|
||||
},
|
||||
req.headers(),
|
||||
@ -921,23 +777,17 @@ pub async fn business_profile_create(
|
||||
let flow = Flow::BusinessProfileCreate;
|
||||
let payload = json_payload.into_inner();
|
||||
|
||||
let merchant_id = match HeaderMapStruct::from(&req).get_merchant_id_from_header() {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
return api::log_and_return_error_response(err);
|
||||
}
|
||||
};
|
||||
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, _, req, _| create_business_profile(state, req, &merchant_id),
|
||||
|state, auth_data, req, _| {
|
||||
create_business_profile(state, req, auth_data.merchant_account, auth_data.key_store)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromHeader {
|
||||
required_permission: Permission::MerchantAccountWrite,
|
||||
},
|
||||
req.headers(),
|
||||
@ -968,9 +818,11 @@ pub async fn business_profile_retrieve(
|
||||
state,
|
||||
&req,
|
||||
profile_id,
|
||||
|state, _, profile_id, _| retrieve_business_profile(state, profile_id, merchant_id.clone()),
|
||||
|state, auth_data, profile_id, _| {
|
||||
retrieve_business_profile(state, profile_id, auth_data.key_store)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::AdminApiAuthWithMerchantIdFromRoute(merchant_id.clone()),
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
required_permission: Permission::MerchantAccountRead,
|
||||
@ -992,23 +844,17 @@ pub async fn business_profile_retrieve(
|
||||
let flow = Flow::BusinessProfileRetrieve;
|
||||
let profile_id = path.into_inner();
|
||||
|
||||
let merchant_id = match HeaderMapStruct::from(&req).get_merchant_id_from_header() {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
return api::log_and_return_error_response(err);
|
||||
}
|
||||
};
|
||||
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
profile_id,
|
||||
|state, _, profile_id, _| retrieve_business_profile(state, profile_id, merchant_id.clone()),
|
||||
|state, auth_data, profile_id, _| {
|
||||
retrieve_business_profile(state, profile_id, auth_data.key_store)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromHeader {
|
||||
required_permission: Permission::MerchantAccountRead,
|
||||
},
|
||||
req.headers(),
|
||||
@ -1041,9 +887,11 @@ pub async fn business_profile_update(
|
||||
state,
|
||||
&req,
|
||||
json_payload.into_inner(),
|
||||
|state, _, req, _| update_business_profile(state, &profile_id, &merchant_id, req),
|
||||
|state, auth_data, req, _| {
|
||||
update_business_profile(state, &profile_id, auth_data.key_store, req)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::AdminApiAuthWithMerchantIdFromRoute(merchant_id.clone()),
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
required_permission: Permission::MerchantAccountWrite,
|
||||
@ -1066,23 +914,17 @@ pub async fn business_profile_update(
|
||||
let flow = Flow::BusinessProfileUpdate;
|
||||
let profile_id = path.into_inner();
|
||||
|
||||
let merchant_id = match HeaderMapStruct::from(&req).get_merchant_id_from_header() {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
return api::log_and_return_error_response(err);
|
||||
}
|
||||
};
|
||||
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
json_payload.into_inner(),
|
||||
|state, _, req, _| update_business_profile(state, &profile_id, &merchant_id, req),
|
||||
|state, auth_data, req, _| {
|
||||
update_business_profile(state, &profile_id, auth_data.key_store, req)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromHeader {
|
||||
required_permission: Permission::MerchantAccountWrite,
|
||||
},
|
||||
req.headers(),
|
||||
|
||||
@ -12,19 +12,10 @@ use crate::{
|
||||
///
|
||||
/// Create a new API Key for accessing our APIs from your servers. The plaintext API Key will be
|
||||
/// displayed only once on creation, so ensure you store it securely.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/api_keys/{merchant_id)",
|
||||
params(("merchant_id" = String, Path, description = "The unique identifier for the merchant account")),
|
||||
request_body= CreateApiKeyRequest,
|
||||
responses(
|
||||
(status = 200, description = "API Key created", body = CreateApiKeyResponse),
|
||||
(status = 400, description = "Invalid data")
|
||||
),
|
||||
tag = "API Key",
|
||||
operation_id = "Create an API Key",
|
||||
security(("admin_api_key" = []))
|
||||
)]
|
||||
#[cfg(all(
|
||||
any(feature = "v1", feature = "v2"),
|
||||
not(feature = "merchant_account_v2")
|
||||
))]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::ApiKeyCreate))]
|
||||
pub async fn api_key_create(
|
||||
state: web::Data<AppState>,
|
||||
@ -41,11 +32,11 @@ pub async fn api_key_create(
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, _, payload, _| async {
|
||||
api_keys::create_api_key(state, payload, merchant_id.clone()).await
|
||||
|state, auth_data, payload, _| async {
|
||||
api_keys::create_api_key(state, payload, auth_data.key_store).await
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::AdminApiAuthWithMerchantIdFromRoute(merchant_id.clone()),
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
required_permission: Permission::ApiKeyWrite,
|
||||
@ -56,24 +47,81 @@ pub async fn api_key_create(
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "merchant_account_v2"))]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::ApiKeyCreate))]
|
||||
pub async fn api_key_create(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
json_payload: web::Json<api_types::CreateApiKeyRequest>,
|
||||
) -> impl Responder {
|
||||
let flow = Flow::ApiKeyCreate;
|
||||
let payload = json_payload.into_inner();
|
||||
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, auth_data, payload, _| async {
|
||||
api_keys::create_api_key(state, payload, auth_data.key_store).await
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromHeader {
|
||||
required_permission: Permission::ApiKeyWrite,
|
||||
},
|
||||
req.headers(),
|
||||
),
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
/// API Key - Retrieve
|
||||
///
|
||||
/// Retrieve information about the specified API Key.
|
||||
#[cfg(all(feature = "v2", feature = "merchant_account_v2"))]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::ApiKeyRetrieve))]
|
||||
pub async fn api_key_retrieve(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
path: web::Path<String>,
|
||||
) -> impl Responder {
|
||||
let flow = Flow::ApiKeyRetrieve;
|
||||
let key_id = path.into_inner();
|
||||
|
||||
api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
&key_id,
|
||||
|state, auth_data, key_id, _| {
|
||||
api_keys::retrieve_api_key(
|
||||
state,
|
||||
auth_data.merchant_account.get_id().to_owned(),
|
||||
key_id,
|
||||
)
|
||||
},
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
&auth::JWTAuthMerchantFromHeader {
|
||||
required_permission: Permission::ApiKeyRead,
|
||||
},
|
||||
req.headers(),
|
||||
),
|
||||
api_locking::LockAction::NotApplicable,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
any(feature = "v1", feature = "v2"),
|
||||
not(feature = "merchant_account_v2")
|
||||
))]
|
||||
/// API Key - Retrieve
|
||||
///
|
||||
/// Retrieve information about the specified API Key.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api_keys/{merchant_id}/{key_id}",
|
||||
params (
|
||||
("merchant_id" = String, Path, description = "The unique identifier for the merchant account"),
|
||||
("key_id" = String, Path, description = "The unique identifier for the API Key")
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "API Key retrieved", body = RetrieveApiKeyResponse),
|
||||
(status = 404, description = "API Key not found")
|
||||
),
|
||||
tag = "API Key",
|
||||
operation_id = "Retrieve an API Key",
|
||||
security(("admin_api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::ApiKeyRetrieve))]
|
||||
pub async fn api_key_retrieve(
|
||||
state: web::Data<AppState>,
|
||||
@ -87,7 +135,7 @@ pub async fn api_key_retrieve(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
(&merchant_id, &key_id),
|
||||
(merchant_id.clone(), &key_id),
|
||||
|state, _, (merchant_id, key_id), _| api_keys::retrieve_api_key(state, merchant_id, key_id),
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
@ -101,25 +149,14 @@ pub async fn api_key_retrieve(
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
any(feature = "v1", feature = "v2"),
|
||||
not(feature = "merchant_account_v2")
|
||||
))]
|
||||
/// API Key - Update
|
||||
///
|
||||
/// Update information for the specified API Key.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/api_keys/{merchant_id}/{key_id}",
|
||||
request_body = UpdateApiKeyRequest,
|
||||
params (
|
||||
("merchant_id" = String, Path, description = "The unique identifier for the merchant account"),
|
||||
("key_id" = String, Path, description = "The unique identifier for the API Key")
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "API Key updated", body = RetrieveApiKeyResponse),
|
||||
(status = 404, description = "API Key not found")
|
||||
),
|
||||
tag = "API Key",
|
||||
operation_id = "Update an API Key",
|
||||
security(("admin_api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::ApiKeyUpdate))]
|
||||
pub async fn api_key_update(
|
||||
state: web::Data<AppState>,
|
||||
@ -151,25 +188,47 @@ pub async fn api_key_update(
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "merchant_account_v2"))]
|
||||
pub async fn api_key_update(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
path: web::Path<(common_utils::id_type::MerchantId, String)>,
|
||||
json_payload: web::Json<api_types::UpdateApiKeyRequest>,
|
||||
) -> impl Responder {
|
||||
let flow = Flow::ApiKeyUpdate;
|
||||
let (merchant_id, key_id) = path.into_inner();
|
||||
let mut payload = json_payload.into_inner();
|
||||
payload.key_id = key_id;
|
||||
payload.merchant_id.clone_from(&merchant_id);
|
||||
|
||||
api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, _, payload, _| api_keys::update_api_key(state, payload),
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id,
|
||||
required_permission: Permission::ApiKeyWrite,
|
||||
},
|
||||
req.headers(),
|
||||
),
|
||||
api_locking::LockAction::NotApplicable,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
any(feature = "v1", feature = "v2"),
|
||||
not(feature = "merchant_account_v2")
|
||||
))]
|
||||
/// API Key - Revoke
|
||||
///
|
||||
/// Revoke the specified API Key. Once revoked, the API Key can no longer be used for
|
||||
/// authenticating with our APIs.
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/api_keys/{merchant_id)/{key_id}",
|
||||
params (
|
||||
("merchant_id" = String, Path, description = "The unique identifier for the merchant account"),
|
||||
("key_id" = String, Path, description = "The unique identifier for the API Key")
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "API Key revoked", body = RevokeApiKeyResponse),
|
||||
(status = 404, description = "API Key not found")
|
||||
),
|
||||
tag = "API Key",
|
||||
operation_id = "Revoke an API Key",
|
||||
security(("admin_api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::ApiKeyRevoke))]
|
||||
pub async fn api_key_revoke(
|
||||
state: web::Data<AppState>,
|
||||
@ -197,6 +256,36 @@ pub async fn api_key_revoke(
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "merchant_account_v2"))]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::ApiKeyRevoke))]
|
||||
pub async fn api_key_revoke(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
path: web::Path<(common_utils::id_type::MerchantId, String)>,
|
||||
) -> impl Responder {
|
||||
let flow = Flow::ApiKeyRevoke;
|
||||
let (merchant_id, key_id) = path.into_inner();
|
||||
|
||||
api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
(&merchant_id, &key_id),
|
||||
|state, _, (merchant_id, key_id), _| api_keys::revoke_api_key(state, merchant_id, key_id),
|
||||
auth::auth_type(
|
||||
&auth::AdminApiAuth,
|
||||
&auth::JWTAuthMerchantFromRoute {
|
||||
merchant_id: merchant_id.clone(),
|
||||
required_permission: Permission::ApiKeyWrite,
|
||||
},
|
||||
req.headers(),
|
||||
),
|
||||
api_locking::LockAction::NotApplicable,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// API Key - List
|
||||
///
|
||||
/// List all API Keys associated with your merchant account.
|
||||
|
||||
@ -1405,7 +1405,27 @@ impl Poll {
|
||||
|
||||
pub struct ApiKeys;
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
#[cfg(all(feature = "v2", feature = "olap", feature = "merchant_account_v2"))]
|
||||
impl ApiKeys {
|
||||
pub fn server(state: AppState) -> Scope {
|
||||
web::scope("/v2/api_keys")
|
||||
.app_data(web::Data::new(state))
|
||||
.service(web::resource("").route(web::post().to(api_key_create)))
|
||||
.service(web::resource("/list").route(web::get().to(api_key_list)))
|
||||
.service(
|
||||
web::resource("/{key_id}")
|
||||
.route(web::get().to(api_key_retrieve))
|
||||
.route(web::put().to(api_key_update))
|
||||
.route(web::delete().to(api_key_revoke)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
feature = "olap",
|
||||
any(feature = "v1", feature = "v2"),
|
||||
not(feature = "merchant_account_v2")
|
||||
))]
|
||||
impl ApiKeys {
|
||||
pub fn server(state: AppState) -> Scope {
|
||||
web::scope("/api_keys/{merchant_id}")
|
||||
|
||||
@ -1598,7 +1598,7 @@ pub async fn payments_manual_update(
|
||||
&req,
|
||||
payload,
|
||||
|state, _auth, req, _req_state| payments::payments_manual_update(state, req),
|
||||
&auth::AdminApiAuthWithMerchantId::default(),
|
||||
&auth::AdminApiAuthWithMerchantIdFromHeader,
|
||||
locking_action,
|
||||
))
|
||||
.await
|
||||
|
||||
@ -692,11 +692,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AdminApiAuthWithMerchantId(AdminApiAuth);
|
||||
#[derive(Debug)]
|
||||
pub struct AdminApiAuthWithMerchantIdFromRoute(pub id_type::MerchantId);
|
||||
|
||||
#[async_trait]
|
||||
impl<A> AuthenticateAndFetch<AuthenticationData, A> for AdminApiAuthWithMerchantId
|
||||
impl<A> AuthenticateAndFetch<AuthenticationData, A> for AdminApiAuthWithMerchantIdFromRoute
|
||||
where
|
||||
A: SessionStateInfo + Sync,
|
||||
{
|
||||
@ -705,25 +705,12 @@ where
|
||||
request_headers: &HeaderMap,
|
||||
state: &A,
|
||||
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
|
||||
self.0
|
||||
AdminApiAuth
|
||||
.authenticate_and_fetch(request_headers, state)
|
||||
.await?;
|
||||
let merchant_id =
|
||||
get_header_value_by_key(headers::X_MERCHANT_ID.to_string(), request_headers)?
|
||||
.get_required_value(headers::X_MERCHANT_ID)
|
||||
.change_context(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: format!("`{}` header is missing", headers::X_MERCHANT_ID),
|
||||
})
|
||||
.and_then(|merchant_id_str| {
|
||||
id_type::MerchantId::try_from(std::borrow::Cow::from(
|
||||
merchant_id_str.to_string(),
|
||||
))
|
||||
.change_context(
|
||||
errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: format!("`{}` header is invalid", headers::X_MERCHANT_ID),
|
||||
},
|
||||
)
|
||||
})?;
|
||||
|
||||
let merchant_id = self.0.clone();
|
||||
|
||||
let key_manager_state = &(&state.session_state()).into();
|
||||
let key_store = state
|
||||
.store()
|
||||
@ -755,6 +742,113 @@ where
|
||||
}
|
||||
})?;
|
||||
|
||||
let auth = AuthenticationData {
|
||||
merchant_account: merchant,
|
||||
key_store,
|
||||
profile_id: None,
|
||||
};
|
||||
|
||||
Ok((
|
||||
auth,
|
||||
AuthenticationType::AdminApiAuthWithMerchantId { merchant_id },
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper struct to extract headers from the request
|
||||
struct HeaderMapStruct<'a> {
|
||||
headers: &'a HeaderMap,
|
||||
}
|
||||
|
||||
impl<'a> HeaderMapStruct<'a> {
|
||||
pub fn new(headers: &'a HeaderMap) -> Self {
|
||||
HeaderMapStruct { headers }
|
||||
}
|
||||
|
||||
fn get_mandatory_header_value_by_key(
|
||||
&self,
|
||||
key: String,
|
||||
) -> Result<&str, error_stack::Report<errors::ApiErrorResponse>> {
|
||||
self.headers
|
||||
.get(&key)
|
||||
.ok_or(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: format!("Missing header key: `{}`", key),
|
||||
})
|
||||
.attach_printable(format!("Failed to find header key: {}", key))?
|
||||
.to_str()
|
||||
.change_context(errors::ApiErrorResponse::InvalidDataValue {
|
||||
field_name: "`X-Merchant-Id` in headers",
|
||||
})
|
||||
.attach_printable(format!(
|
||||
"Failed to convert header value to string for header key: {}",
|
||||
key
|
||||
))
|
||||
}
|
||||
|
||||
pub fn get_merchant_id_from_header(&self) -> RouterResult<id_type::MerchantId> {
|
||||
self.get_mandatory_header_value_by_key(headers::X_MERCHANT_ID.into())
|
||||
.map(|val| val.to_owned())
|
||||
.and_then(|merchant_id| {
|
||||
id_type::MerchantId::wrap(merchant_id).change_context(
|
||||
errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: format!("`{}` header is invalid", headers::X_MERCHANT_ID),
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the merchant-id from `x-merchant-id` header
|
||||
#[derive(Debug)]
|
||||
pub struct AdminApiAuthWithMerchantIdFromHeader;
|
||||
|
||||
#[async_trait]
|
||||
impl<A> AuthenticateAndFetch<AuthenticationData, A> for AdminApiAuthWithMerchantIdFromHeader
|
||||
where
|
||||
A: SessionStateInfo + Sync,
|
||||
{
|
||||
async fn authenticate_and_fetch(
|
||||
&self,
|
||||
request_headers: &HeaderMap,
|
||||
state: &A,
|
||||
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
|
||||
AdminApiAuth
|
||||
.authenticate_and_fetch(request_headers, state)
|
||||
.await?;
|
||||
|
||||
let merchant_id = HeaderMapStruct::new(request_headers).get_merchant_id_from_header()?;
|
||||
|
||||
let key_manager_state = &(&state.session_state()).into();
|
||||
let key_store = state
|
||||
.store()
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&merchant_id,
|
||||
&state.store().get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if e.current_context().is_db_not_found() {
|
||||
e.change_context(errors::ApiErrorResponse::MerchantAccountNotFound)
|
||||
} else {
|
||||
e.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to fetch merchant key store for the merchant id")
|
||||
}
|
||||
})?;
|
||||
|
||||
let merchant = state
|
||||
.store()
|
||||
.find_merchant_account_by_merchant_id(key_manager_state, &merchant_id, &key_store)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if e.current_context().is_db_not_found() {
|
||||
e.change_context(errors::ApiErrorResponse::Unauthorized)
|
||||
} else {
|
||||
e.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to fetch merchant account for the merchant id")
|
||||
}
|
||||
})?;
|
||||
|
||||
let auth = AuthenticationData {
|
||||
merchant_account: merchant,
|
||||
key_store,
|
||||
@ -1026,6 +1120,111 @@ pub struct JWTAuthMerchantFromRoute {
|
||||
pub required_permission: Permission,
|
||||
}
|
||||
|
||||
pub struct JWTAuthMerchantFromHeader {
|
||||
pub required_permission: Permission,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<A> AuthenticateAndFetch<(), A> for JWTAuthMerchantFromHeader
|
||||
where
|
||||
A: SessionStateInfo + Sync,
|
||||
{
|
||||
async fn authenticate_and_fetch(
|
||||
&self,
|
||||
request_headers: &HeaderMap,
|
||||
state: &A,
|
||||
) -> RouterResult<((), AuthenticationType)> {
|
||||
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||
if payload.check_in_blacklist(state).await? {
|
||||
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||
}
|
||||
|
||||
let permissions = authorization::get_permissions(state, &payload).await?;
|
||||
authorization::check_authorization(&self.required_permission, &permissions)?;
|
||||
|
||||
let merchant_id_from_header =
|
||||
HeaderMapStruct::new(request_headers).get_merchant_id_from_header()?;
|
||||
|
||||
// Check if token has access to MerchantId that has been requested through headers
|
||||
if payload.merchant_id != merchant_id_from_header {
|
||||
return Err(report!(errors::ApiErrorResponse::InvalidJwtToken));
|
||||
}
|
||||
Ok((
|
||||
(),
|
||||
AuthenticationType::MerchantJwt {
|
||||
merchant_id: payload.merchant_id,
|
||||
user_id: Some(payload.user_id),
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<A> AuthenticateAndFetch<AuthenticationData, A> for JWTAuthMerchantFromHeader
|
||||
where
|
||||
A: SessionStateInfo + Sync,
|
||||
{
|
||||
async fn authenticate_and_fetch(
|
||||
&self,
|
||||
request_headers: &HeaderMap,
|
||||
state: &A,
|
||||
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
|
||||
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||
if payload.check_in_blacklist(state).await? {
|
||||
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||
}
|
||||
|
||||
let permissions = authorization::get_permissions(state, &payload).await?;
|
||||
authorization::check_authorization(&self.required_permission, &permissions)?;
|
||||
|
||||
let merchant_id_from_header =
|
||||
HeaderMapStruct::new(request_headers).get_merchant_id_from_header()?;
|
||||
|
||||
// Check if token has access to MerchantId that has been requested through headers
|
||||
if payload.merchant_id != merchant_id_from_header {
|
||||
return Err(report!(errors::ApiErrorResponse::InvalidJwtToken));
|
||||
}
|
||||
|
||||
let key_manager_state = &(&state.session_state()).into();
|
||||
|
||||
let key_store = state
|
||||
.store()
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&payload.merchant_id,
|
||||
&state.store().get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::InvalidJwtToken)
|
||||
.attach_printable("Failed to fetch merchant key store for the merchant id")?;
|
||||
|
||||
let merchant = state
|
||||
.store()
|
||||
.find_merchant_account_by_merchant_id(
|
||||
key_manager_state,
|
||||
&payload.merchant_id,
|
||||
&key_store,
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::InvalidJwtToken)
|
||||
.attach_printable("Failed to fetch merchant account for the merchant id")?;
|
||||
|
||||
let auth = AuthenticationData {
|
||||
merchant_account: merchant,
|
||||
key_store,
|
||||
profile_id: payload.profile_id,
|
||||
};
|
||||
|
||||
Ok((
|
||||
auth,
|
||||
AuthenticationType::MerchantJwt {
|
||||
merchant_id: payload.merchant_id,
|
||||
user_id: Some(payload.user_id),
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<A> AuthenticateAndFetch<(), A> for JWTAuthMerchantFromRoute
|
||||
where
|
||||
|
||||
Reference in New Issue
Block a user