refactor(router): Introduce ApiKeyId id type (#6324)

This commit is contained in:
Anurag Thakur
2024-10-21 19:19:31 +05:30
committed by GitHub
parent 58296ffae6
commit b3ce373f8e
14 changed files with 166 additions and 75 deletions

View File

@ -1,5 +1,8 @@
[default]
check-filename = true
extend-ignore-identifiers-re = [
"UE_[0-9]{3,4}", # Unified error codes
]
[default.extend-identifiers]
ABD = "ABD" # Aberdeenshire, UK ISO 3166-2 code
@ -38,7 +41,6 @@ ws2ipdef = "ws2ipdef" # WinSock Extension
ws2tcpip = "ws2tcpip" # WinSock Extension
ZAR = "ZAR" # South African Rand currency code
JOD = "JOD" # Jordan currency code
UE_000 = "UE_000" #default unified error code
[default.extend-words]

View File

@ -29,8 +29,8 @@ pub struct CreateApiKeyRequest {
#[derive(Debug, Serialize, ToSchema)]
pub struct CreateApiKeyResponse {
/// The identifier for the API Key.
#[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX")]
pub key_id: String,
#[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX", value_type = String)]
pub key_id: common_utils::id_type::ApiKeyId,
/// The identifier for the Merchant Account.
#[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)]
@ -72,8 +72,8 @@ pub struct CreateApiKeyResponse {
#[derive(Debug, Serialize, ToSchema)]
pub struct RetrieveApiKeyResponse {
/// The identifier for the API Key.
#[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX")]
pub key_id: String,
#[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX", value_type = String)]
pub key_id: common_utils::id_type::ApiKeyId,
/// The identifier for the Merchant Account.
#[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)]
@ -131,7 +131,8 @@ pub struct UpdateApiKeyRequest {
pub expiration: Option<ApiKeyExpiration>,
#[serde(skip_deserializing)]
pub key_id: String,
#[schema(value_type = String)]
pub key_id: common_utils::id_type::ApiKeyId,
#[serde(skip_deserializing)]
#[schema(value_type = String)]
@ -146,8 +147,8 @@ pub struct RevokeApiKeyResponse {
pub merchant_id: common_utils::id_type::MerchantId,
/// The identifier for the API Key.
#[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX")]
pub key_id: String,
#[schema(max_length = 64, example = "5hEEqkgJUyuxgSKGArHA4mWSnX", value_type = String)]
pub key_id: common_utils::id_type::ApiKeyId,
/// Indicates whether the API key was revoked or not.
#[schema(example = "true")]
pub revoked: bool,

View File

@ -45,6 +45,9 @@ pub enum ApiEventsType {
BusinessProfile {
profile_id: id_type::ProfileId,
},
ApiKey {
key_id: id_type::ApiKeyId,
},
User {
user_id: String,
},
@ -130,10 +133,6 @@ impl_api_event_type!(
(
String,
id_type::MerchantId,
(id_type::MerchantId, String),
(id_type::MerchantId, &String),
(&id_type::MerchantId, &String),
(&String, &String),
(Option<i64>, Option<i64>, String),
(Option<i64>, Option<i64>, id_type::MerchantId),
bool

View File

@ -3,6 +3,7 @@
use std::{borrow::Cow, fmt::Debug};
mod api_key;
mod customer;
mod merchant;
mod merchant_connector_account;
@ -14,6 +15,7 @@ mod routing;
#[cfg(feature = "v2")]
mod global_id;
pub use api_key::ApiKeyId;
pub use customer::CustomerId;
use diesel::{
backend::Backend,

View File

@ -0,0 +1,46 @@
crate::id_type!(
ApiKeyId,
"A type for key_id that can be used for API key IDs"
);
crate::impl_id_type_methods!(ApiKeyId, "key_id");
// This is to display the `ApiKeyId` as ApiKeyId(abcd)
crate::impl_debug_id_type!(ApiKeyId);
crate::impl_try_from_cow_str_id_type!(ApiKeyId, "key_id");
crate::impl_serializable_secret_id_type!(ApiKeyId);
crate::impl_queryable_id_type!(ApiKeyId);
crate::impl_to_sql_from_sql_id_type!(ApiKeyId);
impl ApiKeyId {
/// Generate Api Key Id from prefix
pub fn generate_key_id(prefix: &'static str) -> Self {
Self(crate::generate_ref_id_with_default_length(prefix))
}
}
impl crate::events::ApiEventMetric for ApiKeyId {
fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
Some(crate::events::ApiEventsType::ApiKey {
key_id: self.clone(),
})
}
}
impl crate::events::ApiEventMetric for (super::MerchantId, ApiKeyId) {
fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
Some(crate::events::ApiEventsType::ApiKey {
key_id: self.1.clone(),
})
}
}
impl crate::events::ApiEventMetric for (&super::MerchantId, &ApiKeyId) {
fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
Some(crate::events::ApiEventsType::ApiKey {
key_id: self.1.clone(),
})
}
}
crate::impl_default_id_type!(ApiKeyId, "key");

View File

@ -9,7 +9,7 @@ use crate::schema::api_keys;
)]
#[diesel(table_name = api_keys, primary_key(key_id), check_for_backend(diesel::pg::Pg))]
pub struct ApiKey {
pub key_id: String,
pub key_id: common_utils::id_type::ApiKeyId,
pub merchant_id: common_utils::id_type::MerchantId,
pub name: String,
pub description: Option<String>,
@ -23,7 +23,7 @@ pub struct ApiKey {
#[derive(Debug, Insertable)]
#[diesel(table_name = api_keys)]
pub struct ApiKeyNew {
pub key_id: String,
pub key_id: common_utils::id_type::ApiKeyId,
pub merchant_id: common_utils::id_type::MerchantId,
pub name: String,
pub description: Option<String>,
@ -141,7 +141,7 @@ mod diesel_impl {
// Tracking data by process_tracker
#[derive(Default, Debug, Deserialize, Serialize, Clone)]
pub struct ApiKeyExpiryTrackingData {
pub key_id: String,
pub key_id: common_utils::id_type::ApiKeyId,
pub merchant_id: common_utils::id_type::MerchantId,
pub api_key_name: String,
pub prefix: String,

View File

@ -18,7 +18,7 @@ impl ApiKey {
pub async fn update_by_merchant_id_key_id(
conn: &PgPooledConn,
merchant_id: common_utils::id_type::MerchantId,
key_id: String,
key_id: common_utils::id_type::ApiKeyId,
api_key_update: ApiKeyUpdate,
) -> StorageResult<Self> {
match generics::generic_update_with_unique_predicate_get_result::<
@ -57,7 +57,7 @@ impl ApiKey {
pub async fn revoke_by_merchant_id_key_id(
conn: &PgPooledConn,
merchant_id: &common_utils::id_type::MerchantId,
key_id: &str,
key_id: &common_utils::id_type::ApiKeyId,
) -> StorageResult<bool> {
generics::generic_delete::<<Self as HasTable>::Table, _>(
conn,
@ -71,7 +71,7 @@ impl ApiKey {
pub async fn find_optional_by_merchant_id_key_id(
conn: &PgPooledConn,
merchant_id: &common_utils::id_type::MerchantId,
key_id: &str,
key_id: &common_utils::id_type::ApiKeyId,
) -> StorageResult<Option<Self>> {
generics::generic_find_one_optional::<<Self as HasTable>::Table, _, _>(
conn,

View File

@ -13,7 +13,6 @@ use crate::{
routes::{metrics, SessionState},
services::{authentication, ApplicationResponse},
types::{api, storage, transformers::ForeignInto},
utils,
};
#[cfg(feature = "email")]
@ -63,9 +62,9 @@ impl PlaintextApiKey {
Self(format!("{env}_{key}").into())
}
pub fn new_key_id() -> String {
pub fn new_key_id() -> common_utils::id_type::ApiKeyId {
let env = router_env::env::prefix_for_env();
utils::generate_id(consts::ID_LENGTH, env)
common_utils::id_type::ApiKeyId::generate_key_id(env)
}
pub fn prefix(&self) -> String {
@ -223,7 +222,7 @@ pub async fn add_api_key_expiry_task(
expiry_reminder_days: expiry_reminder_days.clone(),
};
let process_tracker_id = generate_task_id_for_api_key_expiry_workflow(api_key.key_id.as_str());
let process_tracker_id = generate_task_id_for_api_key_expiry_workflow(&api_key.key_id);
let process_tracker_entry = storage::ProcessTrackerNew::new(
process_tracker_id,
API_KEY_EXPIRY_NAME,
@ -241,7 +240,7 @@ pub async fn add_api_key_expiry_task(
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable_lazy(|| {
format!(
"Failed while inserting API key expiry reminder to process_tracker: api_key_id: {}",
"Failed while inserting API key expiry reminder to process_tracker: {:?}",
api_key.key_id
)
})?;
@ -258,11 +257,11 @@ pub async fn add_api_key_expiry_task(
pub async fn retrieve_api_key(
state: SessionState,
merchant_id: common_utils::id_type::MerchantId,
key_id: &str,
key_id: common_utils::id_type::ApiKeyId,
) -> 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")?
@ -388,7 +387,7 @@ pub async fn update_api_key_expiry_task(
}
}
let task_id = generate_task_id_for_api_key_expiry_workflow(api_key.key_id.as_str());
let task_id = generate_task_id_for_api_key_expiry_workflow(&api_key.key_id);
let task_ids = vec![task_id.clone()];
@ -430,7 +429,7 @@ pub async fn update_api_key_expiry_task(
pub async fn revoke_api_key(
state: SessionState,
merchant_id: &common_utils::id_type::MerchantId,
key_id: &str,
key_id: &common_utils::id_type::ApiKeyId,
) -> RouterResponse<api::RevokeApiKeyResponse> {
let store = state.store.as_ref();
@ -496,7 +495,7 @@ pub async fn revoke_api_key(
#[instrument(skip_all)]
pub async fn revoke_api_key_expiry_task(
store: &dyn crate::db::StorageInterface,
key_id: &str,
key_id: &common_utils::id_type::ApiKeyId,
) -> Result<(), errors::ProcessTrackerError> {
let task_id = generate_task_id_for_api_key_expiry_workflow(key_id);
let task_ids = vec![task_id];
@ -535,8 +534,13 @@ pub async fn list_api_keys(
}
#[cfg(feature = "email")]
fn generate_task_id_for_api_key_expiry_workflow(key_id: &str) -> String {
format!("{API_KEY_EXPIRY_RUNNER}_{API_KEY_EXPIRY_NAME}_{key_id}")
fn generate_task_id_for_api_key_expiry_workflow(
key_id: &common_utils::id_type::ApiKeyId,
) -> String {
format!(
"{API_KEY_EXPIRY_RUNNER}_{API_KEY_EXPIRY_NAME}_{}",
key_id.get_string_repr()
)
}
impl From<&str> for PlaintextApiKey {

View File

@ -20,20 +20,20 @@ pub trait ApiKeyInterface {
async fn update_api_key(
&self,
merchant_id: common_utils::id_type::MerchantId,
key_id: String,
key_id: common_utils::id_type::ApiKeyId,
api_key: storage::ApiKeyUpdate,
) -> CustomResult<storage::ApiKey, errors::StorageError>;
async fn revoke_api_key(
&self,
merchant_id: &common_utils::id_type::MerchantId,
key_id: &str,
key_id: &common_utils::id_type::ApiKeyId,
) -> CustomResult<bool, errors::StorageError>;
async fn find_api_key_by_merchant_id_key_id_optional(
&self,
merchant_id: &common_utils::id_type::MerchantId,
key_id: &str,
key_id: &common_utils::id_type::ApiKeyId,
) -> CustomResult<Option<storage::ApiKey>, errors::StorageError>;
async fn find_api_key_by_hash_optional(
@ -67,7 +67,7 @@ impl ApiKeyInterface for Store {
async fn update_api_key(
&self,
merchant_id: common_utils::id_type::MerchantId,
key_id: String,
key_id: common_utils::id_type::ApiKeyId,
api_key: storage::ApiKeyUpdate,
) -> CustomResult<storage::ApiKey, errors::StorageError> {
let conn = connection::pg_connection_write(self).await?;
@ -99,7 +99,8 @@ impl ApiKeyInterface for Store {
.await
.map_err(|error| report!(errors::StorageError::from(error)))?
.ok_or(report!(errors::StorageError::ValueNotFound(format!(
"ApiKey of {_key_id} not found"
"ApiKey of {} not found",
_key_id.get_string_repr()
))))?;
cache::publish_and_redact(
@ -115,7 +116,7 @@ impl ApiKeyInterface for Store {
async fn revoke_api_key(
&self,
merchant_id: &common_utils::id_type::MerchantId,
key_id: &str,
key_id: &common_utils::id_type::ApiKeyId,
) -> CustomResult<bool, errors::StorageError> {
let conn = connection::pg_connection_write(self).await?;
let delete_call = || async {
@ -141,7 +142,8 @@ impl ApiKeyInterface for Store {
.await
.map_err(|error| report!(errors::StorageError::from(error)))?
.ok_or(report!(errors::StorageError::ValueNotFound(format!(
"ApiKey of {key_id} not found"
"ApiKey of {} not found",
key_id.get_string_repr()
))))?;
cache::publish_and_redact(
@ -157,7 +159,7 @@ impl ApiKeyInterface for Store {
async fn find_api_key_by_merchant_id_key_id_optional(
&self,
merchant_id: &common_utils::id_type::MerchantId,
key_id: &str,
key_id: &common_utils::id_type::ApiKeyId,
) -> CustomResult<Option<storage::ApiKey>, errors::StorageError> {
let conn = connection::pg_connection_read(self).await?;
storage::ApiKey::find_optional_by_merchant_id_key_id(&conn, merchant_id, key_id)
@ -240,7 +242,7 @@ impl ApiKeyInterface for MockDb {
async fn update_api_key(
&self,
merchant_id: common_utils::id_type::MerchantId,
key_id: String,
key_id: common_utils::id_type::ApiKeyId,
api_key: storage::ApiKeyUpdate,
) -> CustomResult<storage::ApiKey, errors::StorageError> {
let mut locked_api_keys = self.api_keys.lock().await;
@ -282,13 +284,13 @@ impl ApiKeyInterface for MockDb {
async fn revoke_api_key(
&self,
merchant_id: &common_utils::id_type::MerchantId,
key_id: &str,
key_id: &common_utils::id_type::ApiKeyId,
) -> CustomResult<bool, errors::StorageError> {
let mut locked_api_keys = self.api_keys.lock().await;
// find the key to remove, if it exists
if let Some(pos) = locked_api_keys
.iter()
.position(|k| k.merchant_id == *merchant_id && k.key_id == key_id)
.position(|k| k.merchant_id == *merchant_id && k.key_id == *key_id)
{
// use `remove` instead of `swap_remove` so we have a consistent order, which might
// matter to someone using limit/offset in `list_api_keys_by_merchant_id`
@ -302,14 +304,14 @@ impl ApiKeyInterface for MockDb {
async fn find_api_key_by_merchant_id_key_id_optional(
&self,
merchant_id: &common_utils::id_type::MerchantId,
key_id: &str,
key_id: &common_utils::id_type::ApiKeyId,
) -> CustomResult<Option<storage::ApiKey>, errors::StorageError> {
Ok(self
.api_keys
.lock()
.await
.iter()
.find(|k| k.merchant_id == *merchant_id && k.key_id == key_id)
.find(|k| k.merchant_id == *merchant_id && k.key_id == *key_id)
.cloned())
}
@ -397,9 +399,16 @@ mod tests {
let merchant_id =
common_utils::id_type::MerchantId::try_from(Cow::from("merchant1")).unwrap();
let key_id1 = common_utils::id_type::ApiKeyId::try_from(Cow::from("key_id1")).unwrap();
let key_id2 = common_utils::id_type::ApiKeyId::try_from(Cow::from("key_id2")).unwrap();
let non_existent_key_id =
common_utils::id_type::ApiKeyId::try_from(Cow::from("does_not_exist")).unwrap();
let key1 = mockdb
.insert_api_key(storage::ApiKeyNew {
key_id: "key_id1".into(),
key_id: key_id1.clone(),
merchant_id: merchant_id.clone(),
name: "Key 1".into(),
description: None,
@ -414,7 +423,7 @@ mod tests {
mockdb
.insert_api_key(storage::ApiKeyNew {
key_id: "key_id2".into(),
key_id: key_id2.clone(),
merchant_id: merchant_id.clone(),
name: "Key 2".into(),
description: None,
@ -428,13 +437,13 @@ mod tests {
.unwrap();
let found_key1 = mockdb
.find_api_key_by_merchant_id_key_id_optional(&merchant_id, "key_id1")
.find_api_key_by_merchant_id_key_id_optional(&merchant_id, &key_id1)
.await
.unwrap()
.unwrap();
assert_eq!(found_key1.key_id, key1.key_id);
assert!(mockdb
.find_api_key_by_merchant_id_key_id_optional(&merchant_id, "does_not_exist")
.find_api_key_by_merchant_id_key_id_optional(&merchant_id, &non_existent_key_id)
.await
.unwrap()
.is_none());
@ -442,7 +451,7 @@ mod tests {
mockdb
.update_api_key(
merchant_id.clone(),
"key_id1".into(),
key_id1.clone(),
storage::ApiKeyUpdate::LastUsedUpdate {
last_used: datetime!(2023-02-04 1:11),
},
@ -450,7 +459,7 @@ mod tests {
.await
.unwrap();
let updated_key1 = mockdb
.find_api_key_by_merchant_id_key_id_optional(&merchant_id, "key_id1")
.find_api_key_by_merchant_id_key_id_optional(&merchant_id, &key_id1)
.await
.unwrap()
.unwrap();
@ -464,10 +473,7 @@ mod tests {
.len(),
2
);
mockdb
.revoke_api_key(&merchant_id, "key_id1")
.await
.unwrap();
mockdb.revoke_api_key(&merchant_id, &key_id1).await.unwrap();
assert_eq!(
mockdb
.list_api_keys_by_merchant_id(&merchant_id, None, None)
@ -495,8 +501,10 @@ mod tests {
.await
.unwrap();
let test_key = common_utils::id_type::ApiKeyId::try_from(Cow::from("test_ey")).unwrap();
let api = storage::ApiKeyNew {
key_id: "test_key".into(),
key_id: test_key.clone(),
merchant_id: merchant_id.clone(),
name: "My test key".into(),
description: None,

View File

@ -226,7 +226,7 @@ impl ApiKeyInterface for KafkaStore {
async fn update_api_key(
&self,
merchant_id: id_type::MerchantId,
key_id: String,
key_id: id_type::ApiKeyId,
api_key: storage::ApiKeyUpdate,
) -> CustomResult<storage::ApiKey, errors::StorageError> {
self.diesel_store
@ -237,7 +237,7 @@ impl ApiKeyInterface for KafkaStore {
async fn revoke_api_key(
&self,
merchant_id: &id_type::MerchantId,
key_id: &str,
key_id: &id_type::ApiKeyId,
) -> CustomResult<bool, errors::StorageError> {
self.diesel_store.revoke_api_key(merchant_id, key_id).await
}
@ -245,7 +245,7 @@ impl ApiKeyInterface for KafkaStore {
async fn find_api_key_by_merchant_id_key_id_optional(
&self,
merchant_id: &id_type::MerchantId,
key_id: &str,
key_id: &id_type::ApiKeyId,
) -> CustomResult<Option<storage::ApiKey>, errors::StorageError> {
self.diesel_store
.find_api_key_by_merchant_id_key_id_optional(merchant_id, key_id)

View File

@ -79,7 +79,7 @@ pub async fn api_key_create(
pub async fn api_key_retrieve(
state: web::Data<AppState>,
req: HttpRequest,
path: web::Path<String>,
path: web::Path<common_utils::id_type::ApiKeyId>,
) -> impl Responder {
let flow = Flow::ApiKeyRetrieve;
let key_id = path.into_inner();
@ -93,7 +93,7 @@ pub async fn api_key_retrieve(
api_keys::retrieve_api_key(
state,
auth_data.merchant_account.get_id().to_owned(),
key_id,
key_id.to_owned(),
)
},
auth::auth_type(
@ -114,7 +114,10 @@ pub async fn api_key_retrieve(
pub async fn api_key_retrieve(
state: web::Data<AppState>,
req: HttpRequest,
path: web::Path<(common_utils::id_type::MerchantId, String)>,
path: web::Path<(
common_utils::id_type::MerchantId,
common_utils::id_type::ApiKeyId,
)>,
) -> impl Responder {
let flow = Flow::ApiKeyRetrieve;
let (merchant_id, key_id) = path.into_inner();
@ -123,7 +126,7 @@ pub async fn api_key_retrieve(
flow,
state,
&req,
(merchant_id.clone(), &key_id),
(merchant_id.clone(), key_id.clone()),
|state, _, (merchant_id, key_id), _| api_keys::retrieve_api_key(state, merchant_id, key_id),
auth::auth_type(
&auth::AdminApiAuth,
@ -144,7 +147,10 @@ pub async fn api_key_retrieve(
pub async fn api_key_update(
state: web::Data<AppState>,
req: HttpRequest,
path: web::Path<(common_utils::id_type::MerchantId, String)>,
path: web::Path<(
common_utils::id_type::MerchantId,
common_utils::id_type::ApiKeyId,
)>,
json_payload: web::Json<api_types::UpdateApiKeyRequest>,
) -> impl Responder {
let flow = Flow::ApiKeyUpdate;
@ -177,7 +183,7 @@ pub async fn api_key_update(
pub async fn api_key_update(
state: web::Data<AppState>,
req: HttpRequest,
key_id: web::Path<String>,
key_id: web::Path<common_utils::id_type::ApiKeyId>,
json_payload: web::Json<api_types::UpdateApiKeyRequest>,
) -> impl Responder {
let flow = Flow::ApiKeyUpdate;
@ -212,7 +218,10 @@ pub async fn api_key_update(
pub async fn api_key_revoke(
state: web::Data<AppState>,
req: HttpRequest,
path: web::Path<(common_utils::id_type::MerchantId, String)>,
path: web::Path<(
common_utils::id_type::MerchantId,
common_utils::id_type::ApiKeyId,
)>,
) -> impl Responder {
let flow = Flow::ApiKeyRevoke;
let (merchant_id, key_id) = path.into_inner();
@ -242,7 +251,10 @@ pub async fn api_key_revoke(
pub async fn api_key_revoke(
state: web::Data<AppState>,
req: HttpRequest,
path: web::Path<(common_utils::id_type::MerchantId, String)>,
path: web::Path<(
common_utils::id_type::MerchantId,
common_utils::id_type::ApiKeyId,
)>,
) -> impl Responder {
let flow = Flow::ApiKeyRevoke;
let (merchant_id, key_id) = path.into_inner();

View File

@ -89,7 +89,7 @@ pub struct AuthenticationDataWithUser {
pub enum AuthenticationType {
ApiKey {
merchant_id: id_type::MerchantId,
key_id: String,
key_id: id_type::ApiKeyId,
},
AdminApiKey,
AdminApiAuthWithMerchantId {

View File

@ -67,7 +67,7 @@ pub enum Identifiers {
/// [`ApiKey`] is an authentication method that uses an API key. This is used with [`ApiKey`]
ApiKey {
merchant_id: common_utils::id_type::MerchantId,
key_id: String,
key_id: common_utils::id_type::ApiKeyId,
},
/// [`PublishableKey`] is an authentication method that uses a publishable key. This is used with [`PublishableKey`]
PublishableKey { merchant_id: String },
@ -80,7 +80,7 @@ pub async fn add_api_key(
state: &SessionState,
api_key: Secret<String>,
merchant_id: common_utils::id_type::MerchantId,
key_id: String,
key_id: common_utils::id_type::ApiKeyId,
expiry: Option<u64>,
) -> CustomResult<(), ApiClientError> {
let decision_config = if let Some(config) = &state.conf.decision {

View File

@ -1,7 +1,10 @@
use std::{borrow::Cow, string::ToString};
use actix_web::http::header::HeaderMap;
use common_utils::{crypto::VerifySignature, id_type::MerchantId};
use common_utils::{
crypto::VerifySignature,
id_type::{ApiKeyId, MerchantId},
};
use error_stack::ResultExt;
use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse;
@ -16,7 +19,7 @@ const HEADER_CHECKSUM: &str = "x-checksum";
pub struct ExtractedPayload {
pub payload_type: PayloadType,
pub merchant_id: Option<MerchantId>,
pub key_id: Option<String>,
pub key_id: Option<ApiKeyId>,
}
#[derive(strum::EnumString, strum::Display, PartialEq, Debug)]
@ -61,13 +64,19 @@ impl ExtractedPayload {
message: format!("`{}` header not present", HEADER_AUTH_TYPE),
})?;
let key_id = headers
.get(HEADER_KEY_ID)
.and_then(|value| value.to_str().ok())
.map(|key_id| ApiKeyId::try_from(Cow::from(key_id.to_string())))
.transpose()
.change_context(ApiErrorResponse::InvalidRequestData {
message: format!("`{}` header is invalid or not present", HEADER_KEY_ID),
})?;
Ok(Self {
payload_type: auth_type,
merchant_id: Some(merchant_id),
key_id: headers
.get(HEADER_KEY_ID)
.and_then(|v| v.to_str().ok())
.map(|v| v.to_string()),
key_id,
})
}
@ -95,7 +104,7 @@ impl ExtractedPayload {
&self
.merchant_id
.as_ref()
.map(|inner| append_option(inner.get_string_repr(), &self.key_id)),
.map(|inner| append_api_key(inner.get_string_repr(), &self.key_id)),
)
}
}
@ -107,3 +116,11 @@ fn append_option(prefix: &str, data: &Option<String>) -> String {
None => prefix.to_string(),
}
}
#[inline]
fn append_api_key(prefix: &str, data: &Option<ApiKeyId>) -> String {
match data {
Some(inner) => format!("{}:{}", prefix, inner.get_string_repr()),
None => prefix.to_string(),
}
}