Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(router): add duplication_check field in stored card response #59

Merged
merged 12 commits into from
Jan 29, 2024
21 changes: 15 additions & 6 deletions src/routes/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use axum::middleware;

use masking::ExposeInterface;

use types::StoreCardResponse;

use crate::{
app::AppState,
crypto::{aes::GcmAes256, sha::Sha512},
Expand Down Expand Up @@ -94,7 +96,7 @@ pub async fn add_card(

let optional_hash_table = state.db.find_by_data_hash(&hash_data).await?;

let output = match optional_hash_table {
let (duplication_check, output) = match optional_hash_table {
Some(hash_table) => {
let stored_data = state
.db
Expand All @@ -107,7 +109,10 @@ pub async fn add_card(
)
.await?;

match stored_data {
let duplication_check =
transformers::validate_card_metadata(stored_data.as_ref(), &request.data)?;

let output = match stored_data {
Some(data) => data,
None => {
state
Expand All @@ -123,12 +128,14 @@ pub async fn add_card(
)
.await?
}
}
};

(duplication_check, output)
}
None => {
let hash_table = state.db.insert_hash(hash_data).await?;

state
let output = state
.db
.insert_or_get_from_locker(
(
Expand All @@ -139,11 +146,13 @@ pub async fn add_card(
.try_into()?,
&merchant_dek,
)
.await?
.await?;

(None, output)
}
};

Ok(Json(output.into()))
Ok(Json(StoreCardResponse::from((duplication_check, output))))
}

/// `/data/delete` handling the requirement of deleting cards
Expand Down
43 changes: 40 additions & 3 deletions src/routes/data/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
storage,
};

use super::types;
use super::types::{self, DataDuplicationCheck};

impl<'a> TryFrom<(super::types::StoreCardRequest, &'a str, &'a str)>
for storage::types::LockerNew<'a>
Expand Down Expand Up @@ -38,12 +38,17 @@ impl<'a> TryFrom<(super::types::StoreCardRequest, &'a str, &'a str)>
}
}

impl From<storage::types::Locker> for super::types::StoreCardResponse {
fn from(value: storage::types::Locker) -> Self {
impl From<(Option<DataDuplicationCheck>, storage::types::Locker)>
for super::types::StoreCardResponse
{
fn from(
(duplication_check, value): (Option<DataDuplicationCheck>, storage::types::Locker),
) -> Self {
Self {
status: types::Status::Ok,
payload: Some(super::types::StoreCardRespPayload {
card_reference: value.locker_id.expose(),
duplication_check,
dedup: None,
}),
}
Expand Down Expand Up @@ -71,6 +76,18 @@ impl TryFrom<storage::types::Locker> for super::types::RetrieveCardResponse {
}
}

impl std::cmp::PartialEq<types::Data> for super::types::StoredData {
fn eq(&self, other: &types::Data) -> bool {
match (self, other) {
(Self::EncData(request_enc_card_data), types::Data::EncData { enc_card_data }) => {
request_enc_card_data == enc_card_data
}
(Self::CardData(request_card), types::Data::Card { card }) => request_card == card,
_ => false,
}
}
}

/// Generate UUID v4 as strings to be used in storage layer
pub fn generate_uuid() -> String {
uuid::Uuid::new_v4().to_string()
Expand Down Expand Up @@ -98,3 +115,23 @@ where

Ok(hash_data)
}

pub fn validate_card_metadata(
stored_payload: Option<&storage::types::Locker>,
request_data: &types::Data,
) -> Result<Option<DataDuplicationCheck>, ContainerError<error::ApiError>> {
stored_payload
.map(|stored_data| {
let stored_data =
serde_json::from_slice::<types::StoredData>(stored_data.enc_data.peek())
.change_error(error::ApiError::DecodingError)?;

let is_metadata_duplicated = stored_data.eq(request_data);

Ok(match is_metadata_duplicated {
true => DataDuplicationCheck::Duplicated,
false => DataDuplicationCheck::MetaDataChanged,
})
})
.transpose()
}
14 changes: 11 additions & 3 deletions src/routes/data/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use masking::PeekInterface;

use crate::error;

#[derive(serde::Serialize, serde::Deserialize, Debug)]
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
pub struct Card {
pub card_number: masking::StrongSecret<String>,
name_on_card: Option<String>,
Expand All @@ -25,9 +25,17 @@ pub struct Card {
#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct StoreCardRespPayload {
pub card_reference: String,
pub duplication_check: Option<DataDuplicationCheck>,
pub dedup: Option<DedupResponsePayload>,
}

#[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum DataDuplicationCheck {
Duplicated,
MetaDataChanged,
}

#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct DedupResponsePayload {
hash1_reference: Option<String>,
Expand All @@ -48,7 +56,7 @@ pub struct StoreCardRequest {
pub data: Data,
}

#[derive(serde::Serialize, serde::Deserialize, Debug)]
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
#[serde(untagged)]
pub enum Data {
EncData { enc_card_data: String },
Expand Down Expand Up @@ -94,7 +102,7 @@ pub struct DeleteCardResponse {
pub status: Status,
}

#[derive(serde::Serialize, serde::Deserialize)]
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq)]
pub enum StoredData {
EncData(String),
CardData(Card),
Expand Down
Loading