mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 04:04:55 +08:00
307 lines
10 KiB
Rust
307 lines
10 KiB
Rust
use common_utils::custom_serde;
|
|
use masking::StrongSecret;
|
|
use serde::{Deserialize, Serialize};
|
|
use time::PrimitiveDateTime;
|
|
use utoipa::ToSchema;
|
|
|
|
/// The request body for creating an API Key.
|
|
#[derive(Debug, Deserialize, ToSchema, Serialize)]
|
|
#[serde(deny_unknown_fields)]
|
|
pub struct CreateApiKeyRequest {
|
|
/// A unique name for the API Key to help you identify it.
|
|
#[schema(max_length = 64, example = "Sandbox integration key")]
|
|
pub name: String,
|
|
|
|
/// A description to provide more context about the API Key.
|
|
#[schema(
|
|
max_length = 256,
|
|
example = "Key used by our developers to integrate with the sandbox environment"
|
|
)]
|
|
pub description: Option<String>,
|
|
|
|
/// An expiration date for the API Key. Although we allow keys to never expire, we recommend
|
|
/// rotating your keys once every 6 months.
|
|
#[schema(example = "2022-09-10T10:11:12Z")]
|
|
pub expiration: ApiKeyExpiration,
|
|
}
|
|
|
|
/// The response body for creating an API Key.
|
|
#[derive(Debug, Serialize, ToSchema)]
|
|
pub struct CreateApiKeyResponse {
|
|
/// The identifier for the API Key.
|
|
#[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)]
|
|
pub merchant_id: common_utils::id_type::MerchantId,
|
|
|
|
/// The unique name for the API Key to help you identify it.
|
|
#[schema(max_length = 64, example = "Sandbox integration key")]
|
|
pub name: String,
|
|
|
|
/// The description to provide more context about the API Key.
|
|
#[schema(
|
|
max_length = 256,
|
|
example = "Key used by our developers to integrate with the sandbox environment"
|
|
)]
|
|
pub description: Option<String>,
|
|
|
|
/// The plaintext API Key used for server-side API access. Ensure you store the API Key
|
|
/// securely as you will not be able to see it again.
|
|
#[schema(value_type = String, max_length = 128)]
|
|
pub api_key: StrongSecret<String>,
|
|
|
|
/// The time at which the API Key was created.
|
|
#[schema(example = "2022-09-10T10:11:12Z")]
|
|
#[serde(with = "common_utils::custom_serde::iso8601")]
|
|
pub created: PrimitiveDateTime,
|
|
|
|
/// The expiration date for the API Key.
|
|
#[schema(example = "2022-09-10T10:11:12Z")]
|
|
pub expiration: ApiKeyExpiration,
|
|
/*
|
|
/// The date and time indicating when the API Key was last used.
|
|
#[schema(example = "2022-09-10T10:11:12Z")]
|
|
#[serde(with = "common_utils::custom_serde::iso8601::option")]
|
|
pub last_used: Option<PrimitiveDateTime>,
|
|
*/
|
|
}
|
|
|
|
/// The response body for retrieving an API Key.
|
|
#[derive(Debug, Serialize, ToSchema)]
|
|
pub struct RetrieveApiKeyResponse {
|
|
/// The identifier for the API Key.
|
|
#[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)]
|
|
pub merchant_id: common_utils::id_type::MerchantId,
|
|
|
|
/// The unique name for the API Key to help you identify it.
|
|
#[schema(max_length = 64, example = "Sandbox integration key")]
|
|
pub name: String,
|
|
|
|
/// The description to provide more context about the API Key.
|
|
#[schema(
|
|
max_length = 256,
|
|
example = "Key used by our developers to integrate with the sandbox environment"
|
|
)]
|
|
pub description: Option<String>,
|
|
|
|
/// The first few characters of the plaintext API Key to help you identify it.
|
|
#[schema(value_type = String, max_length = 64)]
|
|
pub prefix: StrongSecret<String>,
|
|
|
|
/// The time at which the API Key was created.
|
|
#[schema(example = "2022-09-10T10:11:12Z")]
|
|
#[serde(with = "common_utils::custom_serde::iso8601")]
|
|
pub created: PrimitiveDateTime,
|
|
|
|
/// The expiration date for the API Key.
|
|
#[schema(example = "2022-09-10T10:11:12Z")]
|
|
pub expiration: ApiKeyExpiration,
|
|
/*
|
|
/// The date and time indicating when the API Key was last used.
|
|
#[schema(example = "2022-09-10T10:11:12Z")]
|
|
#[serde(with = "common_utils::custom_serde::iso8601::option")]
|
|
pub last_used: Option<PrimitiveDateTime>,
|
|
*/
|
|
}
|
|
|
|
/// The request body for updating an API Key.
|
|
#[derive(Debug, Deserialize, ToSchema, Serialize)]
|
|
#[serde(deny_unknown_fields)]
|
|
pub struct UpdateApiKeyRequest {
|
|
/// A unique name for the API Key to help you identify it.
|
|
#[schema(max_length = 64, example = "Sandbox integration key")]
|
|
pub name: Option<String>,
|
|
|
|
/// A description to provide more context about the API Key.
|
|
#[schema(
|
|
max_length = 256,
|
|
example = "Key used by our developers to integrate with the sandbox environment"
|
|
)]
|
|
pub description: Option<String>,
|
|
|
|
/// An expiration date for the API Key. Although we allow keys to never expire, we recommend
|
|
/// rotating your keys once every 6 months.
|
|
#[schema(example = "2022-09-10T10:11:12Z")]
|
|
pub expiration: Option<ApiKeyExpiration>,
|
|
|
|
#[serde(skip_deserializing)]
|
|
#[schema(value_type = String)]
|
|
pub key_id: common_utils::id_type::ApiKeyId,
|
|
|
|
#[serde(skip_deserializing)]
|
|
#[schema(value_type = String)]
|
|
pub merchant_id: common_utils::id_type::MerchantId,
|
|
}
|
|
|
|
/// The response body for revoking an API Key.
|
|
#[derive(Debug, Serialize, ToSchema)]
|
|
pub struct RevokeApiKeyResponse {
|
|
/// The identifier for the Merchant Account.
|
|
#[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)]
|
|
pub merchant_id: common_utils::id_type::MerchantId,
|
|
|
|
/// The identifier for the API Key.
|
|
#[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,
|
|
}
|
|
|
|
/// The constraints that are applicable when listing API Keys associated with a merchant account.
|
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
|
#[serde(deny_unknown_fields)]
|
|
pub struct ListApiKeyConstraints {
|
|
/// The maximum number of API Keys to include in the response.
|
|
pub limit: Option<i64>,
|
|
|
|
/// The number of API Keys to skip when retrieving the list of API keys.
|
|
pub skip: Option<i64>,
|
|
}
|
|
|
|
/// The expiration date and time for an API Key.
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
|
#[serde(untagged)]
|
|
pub enum ApiKeyExpiration {
|
|
/// The API Key does not expire.
|
|
#[serde(with = "never")]
|
|
Never,
|
|
|
|
/// The API Key expires at the specified date and time.
|
|
#[serde(with = "custom_serde::iso8601")]
|
|
DateTime(PrimitiveDateTime),
|
|
}
|
|
|
|
impl From<ApiKeyExpiration> for Option<PrimitiveDateTime> {
|
|
fn from(expiration: ApiKeyExpiration) -> Self {
|
|
match expiration {
|
|
ApiKeyExpiration::Never => None,
|
|
ApiKeyExpiration::DateTime(date_time) => Some(date_time),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Option<PrimitiveDateTime>> for ApiKeyExpiration {
|
|
fn from(date_time: Option<PrimitiveDateTime>) -> Self {
|
|
date_time.map_or(Self::Never, Self::DateTime)
|
|
}
|
|
}
|
|
|
|
// This implementation is required as otherwise, `serde` would serialize and deserialize
|
|
// `ApiKeyExpiration::Never` as `null`, which is not preferable.
|
|
// Reference: https://github.com/serde-rs/serde/issues/1560#issuecomment-506915291
|
|
mod never {
|
|
const NEVER: &str = "never";
|
|
|
|
pub fn serialize<S>(serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: serde::Serializer,
|
|
{
|
|
serializer.serialize_str(NEVER)
|
|
}
|
|
|
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
struct NeverVisitor;
|
|
|
|
impl serde::de::Visitor<'_> for NeverVisitor {
|
|
type Value = ();
|
|
|
|
fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, r#""{NEVER}""#)
|
|
}
|
|
|
|
fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
|
|
if value == NEVER {
|
|
Ok(())
|
|
} else {
|
|
Err(E::invalid_value(serde::de::Unexpected::Str(value), &self))
|
|
}
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_str(NeverVisitor)
|
|
}
|
|
}
|
|
|
|
impl<'a> ToSchema<'a> for ApiKeyExpiration {
|
|
fn schema() -> (
|
|
&'a str,
|
|
utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>,
|
|
) {
|
|
use utoipa::openapi::{KnownFormat, ObjectBuilder, OneOfBuilder, SchemaFormat, SchemaType};
|
|
|
|
(
|
|
"ApiKeyExpiration",
|
|
OneOfBuilder::new()
|
|
.item(
|
|
ObjectBuilder::new()
|
|
.schema_type(SchemaType::String)
|
|
.enum_values(Some(["never"])),
|
|
)
|
|
.item(
|
|
ObjectBuilder::new()
|
|
.schema_type(SchemaType::String)
|
|
.format(Some(SchemaFormat::KnownFormat(KnownFormat::DateTime))),
|
|
)
|
|
.into(),
|
|
)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod api_key_expiration_tests {
|
|
#![allow(clippy::unwrap_used)]
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_serialization() {
|
|
assert_eq!(
|
|
serde_json::to_string(&ApiKeyExpiration::Never).unwrap(),
|
|
r#""never""#
|
|
);
|
|
|
|
let date = time::Date::from_calendar_date(2022, time::Month::September, 10).unwrap();
|
|
let time = time::Time::from_hms(11, 12, 13).unwrap();
|
|
assert_eq!(
|
|
serde_json::to_string(&ApiKeyExpiration::DateTime(PrimitiveDateTime::new(
|
|
date, time
|
|
)))
|
|
.unwrap(),
|
|
r#""2022-09-10T11:12:13.000Z""#
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_deserialization() {
|
|
assert_eq!(
|
|
serde_json::from_str::<ApiKeyExpiration>(r#""never""#).unwrap(),
|
|
ApiKeyExpiration::Never
|
|
);
|
|
|
|
let date = time::Date::from_calendar_date(2022, time::Month::September, 10).unwrap();
|
|
let time = time::Time::from_hms(11, 12, 13).unwrap();
|
|
assert_eq!(
|
|
serde_json::from_str::<ApiKeyExpiration>(r#""2022-09-10T11:12:13.000Z""#).unwrap(),
|
|
ApiKeyExpiration::DateTime(PrimitiveDateTime::new(date, time))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_null() {
|
|
let result = serde_json::from_str::<ApiKeyExpiration>("null");
|
|
assert!(result.is_err());
|
|
|
|
let result = serde_json::from_str::<Option<ApiKeyExpiration>>("null").unwrap();
|
|
assert_eq!(result, None);
|
|
}
|
|
}
|