hyperswitch
feat(core): implement `NameType` for name validation
#6734
Merged

feat(core): implement `NameType` for name validation #6734

likhinbopanna merged 40 commits into main from card_holder_name_validator
Sakilmostak
Sakilmostak141 days ago (edited 93 days ago)

Type of Change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring
  • Dependency updates
  • Documentation
  • CI/CD

Description

for card holder name in cards, validation is added before creation of request to flag invalid data in case it is present.
Reference is taken from Visa Documetation
image

Additional Changes

  • This PR modifies the API contract
  • This PR modifies the database schema
  • This PR modifies application configuration/environment variables

Motivation and Context

How did you test it?

Tested through Postman:

  • Create a MCA (Cybersource):

Case 1: Create a Payment with valid name:

{
    "amount": 499,
    "currency": "EUR",
    "confirm": true,
    "capture_method": "automatic",
    "customer_id": "test_rec7",
    "email": "guest@example.com",
    "customer_acceptance": {
        "acceptance_type": "online"
    },
    "payment_method": "card",
    "payment_method_type": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4242424242424242",
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "Sakil Mostak",
            "card_cvc": "737",
            "card_network": "Visa"
        }
    },
    "billing": {
        "address": {
            "city": "test",
            "country": "US",
            "line1": "here is some \n there is some \n none is some? \n ",
            "line2": "there",
            "line3": "anywhere",
            "zip": "560095",
            "state": "Washington",
            "first_name": "Sakil",
            "last_name": "Mostak"
        },
        "phone": {
            "number": "1234567890",
            "country_code": "+1"
        },
        "email": "guest@example.com"
    },
    "authentication_type": "no_three_ds"
}
  • The payment should succeed, below is an example:
{
    "payment_id": "pay_7YANCrkBMUVJngRBg36l",
    "merchant_id": "merchant_1737373987",
    "status": "succeeded",
    "amount": 499,
    "net_amount": 499,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 499,
    "connector": "cybersource",
    "client_secret": "pay_7YANCrkBMUVJngRBg36l_secret_jp4t6pcoJTnMFrQsGd1R",
    "created": "2025-01-20T17:52:24.651Z",
    "currency": "EUR",
    "customer_id": "test_rec7",
    "customer": {
        "id": "test_rec7",
        "name": null,
        "email": "guest@example.com",
        "phone": null,
        "phone_country_code": null
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "4242",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "424242",
            "card_extended_bin": null,
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "Sakil Mostak",
            "payment_checks": {
                "avs_response": {
                    "code": "X",
                    "codeRaw": "I1"
                },
                "card_verification": null
            },
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": "token_7usZJrOsD3Qoy6kLGDnQ",
    "shipping": null,
    "billing": {
        "address": {
            "city": "test",
            "country": "US",
            "line1": "here is some \n there is some \n none is some? \n ",
            "line2": "there",
            "line3": "anywhere",
            "zip": "560095",
            "state": "Washington",
            "first_name": "Sakil",
            "last_name": "Mostak"
        },
        "phone": {
            "number": "1234567890",
            "country_code": "+1"
        },
        "email": "guest@example.com"
    },
    "order_details": null,
    "email": "guest@example.com",
    "name": null,
    "phone": null,
    "return_url": null,
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "credit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "test_rec7",
        "created_at": 1737395544,
        "expires": 1737399144,
        "secret": "epk_b4c0b9ee60c844dd88e6cbc9daa9e7cb"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "7373955459786405604807",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "pay_7YANCrkBMUVJngRBg36l_1",
    "payment_link": null,
    "profile_id": "pro_VcDn0jWTcCmofCpz2CAH",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_KXO79qkYuOXsSZCYByGz",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-01-20T18:07:24.651Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-01-20T17:52:26.511Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null
}

Case 2: Create a Payment with invalid name:

{
    "amount": 499,
    "currency": "EUR",
    "confirm": true,
    "capture_method": "automatic",
    "customer_id": "test_rec7",
    "email": "guest@example.com",
    "customer_acceptance": {
        "acceptance_type": "online"
    },
    "payment_method": "card",
    "payment_method_type": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4242424242424242",
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "S@k*l M0st@k",
            "card_cvc": "737",
            "card_network": "Visa"
        }
    },
    "billing": {
        "address": {
            "city": "test",
            "country": "US",
            "line1": "here is some \n there is some \n none is some? \n ",
            "line2": "there",
            "line3": "anywhere",
            "zip": "560095",
            "state": "Washington",
            "first_name": "Sakil",
            "last_name": "Mostak"
        },
        "phone": {
            "number": "1234567890",
            "country_code": "+1"
        },
        "email": "guest@example.com"
    },
    "authentication_type": "no_three_ds"
}

Response should contain 400 error with below response:

{
    "error": {
        "error_type": "invalid_request",
        "message": "Json deserialize error: invalid character found in card holder name: @ at line 23 column 5",
        "code": "IR_06"
    }
}

Checklist

  • I formatted the code cargo +nightly fmt --all
  • I addressed lints thrown by cargo clippy
  • I reviewed the submitted code
  • I added unit tests for my changes where possible
Sakilmostak feat: add card_holder_name validation
1d18cce9
Sakilmostak Sakilmostak added A-core
Sakilmostak Sakilmostak added C-feature
Sakilmostak Sakilmostak added this to the December 2024 Release milestone 141 days ago
Sakilmostak Sakilmostak assigned Sakilmostak Sakilmostak 141 days ago
Sakilmostak Sakilmostak requested a review 141 days ago
Sakilmostak Sakilmostak requested a review 141 days ago
semanticdiff-com
semanticdiff-com141 days ago (edited 27 days ago)

Review changes with  SemanticDiff

Changed Files
File Status
  crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs  96% smaller
  crates/router/tests/connectors/bitpay.rs  83% smaller
  crates/router/tests/connectors/coinbase.rs  83% smaller
  crates/router/tests/connectors/cryptopay.rs  83% smaller
  crates/router/tests/connectors/cybersource.rs  83% smaller
  crates/router/tests/connectors/forte.rs  83% smaller
  crates/router/tests/connectors/iatapay.rs  83% smaller
  crates/router/tests/connectors/opennode.rs  83% smaller
  crates/router/tests/connectors/trustpay.rs  83% smaller
  crates/router/tests/connectors/bluesnap.rs  83% smaller
  crates/router/tests/connectors/payme.rs  83% smaller
  crates/router/src/core/payment_methods/tokenize/card_executor.rs  82% smaller
  crates/router/tests/connectors/multisafepay.rs  82% smaller
  crates/router/tests/connectors/adyen.rs  81% smaller
  crates/router/src/core/payments/helpers.rs  80% smaller
  crates/router/tests/connectors/worldline.rs  80% smaller
  crates/router/src/core/payment_methods/tokenize/payment_method_executor.rs  79% smaller
  crates/router/tests/connectors/aci.rs  79% smaller
  crates/router/tests/connectors/rapyd.rs  78% smaller
  crates/router/tests/connectors/utils.rs  77% smaller
  crates/router/tests/payments.rs  77% smaller
  crates/router/tests/payments2.rs  77% smaller
  crates/router/tests/connectors/airwallex.rs  77% smaller
  crates/router/src/types/api/payments.rs  76% smaller
  crates/router/tests/connectors/fiserv.rs  75% smaller
  crates/router/src/core/payment_methods/cards.rs  71% smaller
  crates/router/src/connector/netcetera/netcetera_types.rs  70% smaller
  crates/router/src/core/payment_methods.rs  61% smaller
  crates/router/src/compatibility/stripe/setup_intents/types.rs  55% smaller
  crates/router/src/compatibility/stripe/payment_intents/types.rs  54% smaller
  crates/hyperswitch_connectors/src/utils.rs  45% smaller
  crates/api_models/src/payments.rs  42% smaller
  crates/router/src/connector/utils.rs  38% smaller
  crates/api_models/src/payment_methods.rs  34% smaller
  crates/hyperswitch_connectors/src/connectors/dlocal/transformers.rs  20% smaller
  crates/hyperswitch_domain_models/src/address.rs  13% smaller
  crates/router/src/core/payment_methods/tokenize.rs  12% smaller
  crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs  6% smaller
  crates/router/src/connector/stripe/transformers.rs  5% smaller
  crates/router/src/core/payment_methods/vault.rs  4% smaller
  crates/common_utils/src/types.rs  1% smaller
  crates/api_models/src/payments/additional_info.rs  1% smaller
  crates/api_models/src/customers.rs  0% smaller
  crates/api_models/src/mandates.rs  0% smaller
  crates/api_models/src/payouts.rs  0% smaller
  crates/cards/tests/basic.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/authorizedotnet/transformers.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/trustpay/transformers.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/wellsfargo/transformers.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/worldline/transformers.rs  0% smaller
  crates/hyperswitch_domain_models/src/bulk_tokenization.rs  0% smaller
  crates/hyperswitch_domain_models/src/payment_method_data.rs  0% smaller
  crates/hyperswitch_domain_models/src/router_data.rs  0% smaller
  crates/hyperswitch_domain_models/src/router_request_types/fraud_check.rs  0% smaller
  crates/router/src/compatibility/stripe/customers/types.rs  0% smaller
  crates/router/src/connector/payone/transformers.rs  0% smaller
  crates/router/src/connector/riskified/transformers/api.rs  0% smaller
  crates/router/src/connector/signifyd/transformers/api.rs  0% smaller
  crates/router/src/connector/stripe/transformers/connect.rs  0% smaller
  crates/router/src/core/customers.rs  0% smaller
  crates/router/src/core/locker_migration.rs  0% smaller
  crates/router/src/core/payment_methods/network_tokenization.rs  0% smaller
  crates/router/src/core/payment_methods/transformers.rs  0% smaller
  crates/router/src/core/payouts/helpers.rs  0% smaller
  crates/router/src/core/unified_authentication_service.rs  0% smaller
  crates/router/src/core/utils.rs  0% smaller
  crates/router/src/types/transformers.rs  0% smaller
  crates/router/src/utils.rs  0% smaller
Sakilmostak refactor: spell check
6bfa78e1
Sakilmostak feat: add unit test cases
8d5c164b
Sakilmostak refactor: use unified billing address for payment confirm test
0793d2b0
Sakilmostak refactor: resolve ci checks
8cadc2f1
Narayanbhat166
Narayanbhat166 commented on 2024-12-04
crates/router/src/core/payments/operations/payment_confirm.rs
711713 });
712714
715 // validate billing name for card holder name
716
helpers::validate_billing_name(
Narayanbhat166140 days ago

create a domain type which will have these validations, use the domain type wherever validations are required

Sakilmostak feat: add nametype and implement in domain crate
62b63b6c
Sakilmostak feat: add nametype to router crate
4397e273
Sakilmostak refactor: unit tests
f8980db2
Sakilmostak refactor: nametype implementation for v2
998f9900
Sakilmostak Sakilmostak requested a review 124 days ago
Sakilmostak Sakilmostak requested a review 124 days ago
Sakilmostak Sakilmostak requested a review 124 days ago
Sakilmostak refactor: resolve merge main
d06e84be
Sakilmostak Sakilmostak changed the title feat(router): add card_holder_name pre-validator feat(router): implement `NameType` for name validation 121 days ago
Sakilmostak refactor: conversion
5199422d
Sakilmostak Sakilmostak changed the title feat(router): implement `NameType` for name validation feat(core): implement `NameType` for name validation 114 days ago
Narayanbhat166
Narayanbhat166 commented on 2025-01-03
crates/cards/src/validate.rs
238// pub struct NameTypeValidationErr(&'static str);
239
240#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize)]
241
pub struct NameType(Secret<LengthString<256, 1>>);
Narayanbhat166110 days ago

can we move this to common_utils or common_types, since this is not specific to cards as you have used this in all the other payment methods as well

Sakilmostak refactor: resolve comment
53e92b4b
Sakilmostak refactor: resolve comments
7aef96ea
Sakilmostak refactor: minimum allowed size is zero
e377b2b0
Sakilmostak Merge branch 'main' into card_holder_name_validator
56a0254e
Sakilmostak refactor: resolve conflict with main
8ebd788e
Narayanbhat166
Narayanbhat166 commented on 2025-01-17
crates/api_models/src/payments.rs
17861786 .next()
17871787 .map(ToOwned::to_owned)
1788 .map(Secret::new);
1788
.and_then(|name| NameType::try_from(name).ok());
Narayanbhat16696 days ago

do not use .ok(), log the error

Narayanbhat166
Narayanbhat166 commented on 2025-01-17
Narayanbhat16696 days ago

replace all instances of .ok() with logging the error, and if possible qualify the imports

SanchithHegde SanchithHegde removed this from to the December 2024 Release milestone 94 days ago
SanchithHegde SanchithHegde added this to the January 2025 Release milestone 94 days ago
Sakilmostak refactor: resolve comments
6ae7480b
Narayanbhat166
Narayanbhat166 commented on 2025-01-21
Narayanbhat16692 days ago

wherever possible try to use the nametype, and if the domain is expanding too much convert the type, and raise errors when the conversion might fail

Sakilmostak refactor: resolve comments
4ead56c1
Sakilmostak Merge branch 'main' into card_holder_name_validator
f5406eab
SanchithHegde SanchithHegde removed this from to the January 2025 Release milestone 79 days ago
SanchithHegde SanchithHegde added this to the February 2025 Release milestone 79 days ago
Sakilmostak refactor: resolve comments
dc70eca5
Sakilmostak Merge branch 'main' into card_holder_name_validator
b9cb94cd
Sakilmostak refactor: resolve conflict with main
f04391ac
Sakilmostak Merge branch 'main' into card_holder_name_validator
a3ef9d60
Sakilmostak Merge branch 'main' into card_holder_name_validator
3e58bddd
Narayanbhat166
Narayanbhat166 dismissed these changes on 2025-02-12
Narayanbhat16670 days ago

Please ensure that the values that we read from the database are backwards compatible.

Sakilmostak Merge branch 'main' into card_holder_name_validator
170ed95d
Sakilmostak refactor(utils): use to_state_code of hyperswitch_connectors in route…
8b7319e4
Sakilmostak refactor: resolve conflct with main
e5653114
Sakilmostak Sakilmostak dismissed their stale review via e5653114 61 days ago
Sakilmostak Merge branch 'main' into card_holder_name_validator
1cea81b6
Sakilmostak Merge branch 'main' into card_holder_name_validator
f97af3cd
Sakilmostak Merge branch 'main' into card_holder_name_validator
3c0e1292
Sakilmostak refactor: resolve conflict with main
c4d4859a
Sakilmostak Merge branch 'main' into card_holder_name_validator
04ecc2b1
Sakilmostak refactor: update with latest changes in main
85592d89
Sakilmostak Merge branch 'main' into card_holder_name_validator
9d0ff6b8
srujanchikke
srujanchikke dismissed these changes on 2025-03-17
srujanchikke37 days ago

connector related files LGTM!

prajjwalkumar17
prajjwalkumar17 dismissed these changes on 2025-03-17
prajjwalkumar1737 days ago

Routing related changes LGTM!!

Narayanbhat166
Narayanbhat166 dismissed these changes on 2025-03-18
jarnura
jarnura requested changes on 2025-03-18
Conversation is marked as resolved
Show resolved
crates/api_models/Cargo.toml
4848euclid = { version = "0.1.0", path = "../euclid" }
4949masking = { version = "0.1.0", path = "../masking", default-features = false, features = ["alloc", "serde"] }
5050router_derive = { version = "0.1.0", path = "../router_derive" }
51
router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"] }
jarnura36 days ago

remove the usage of router_env

Conversation is marked as resolved
Show resolved
crates/common_utils/src/types.rs
10871089#[derive(Debug, Clone, Serialize, Hash, PartialEq, Eq, AsExpression)]
10881090#[diesel(sql_type = sql_types::Text)]
1089pub(crate) struct LengthString<const MAX_LENGTH: u16, const MIN_LENGTH: u16>(String);
1091
pub struct LengthString<const MAX_LENGTH: u16, const MIN_LENGTH: u16>(String);
jarnura36 days ago👍 1

Add the visibility to crate back

Conversation is marked as resolved
Show resolved
crates/common_utils/src/types.rs
10911093/// Error generated from violation of constraints for MerchantReferenceId
10921094#[derive(Debug, Error, PartialEq, Eq)]
1093pub(crate) enum LengthStringError {
1095
pub enum LengthStringError {
jarnura36 days ago👍 1

Add the visibility to crate back

Conversation is marked as resolved
Show resolved
crates/router/src/core/payment_methods.rs
782782 card_exp_year: card.card_exp_year.clone(),
783 card_holder_name: billing_name,
783 card_holder_name: billing_name
784 .map(|name| {
785
common_utils::types::NameType::try_from(name).map_err(|_| {
jarnura36 days ago

Don't discard the error, log the error.

SanchithHegde SanchithHegde removed this from to the February 2025 Release milestone 33 days ago
SanchithHegde SanchithHegde added this to the March 2025 Release milestone 33 days ago
Sakilmostak refactor: resolve comments
0a3d671f
Sakilmostak Sakilmostak dismissed their stale review via 0a3d671f 33 days ago
Sakilmostak Sakilmostak dismissed their stale review via 0a3d671f 33 days ago
Sakilmostak Sakilmostak dismissed their stale review via 0a3d671f 33 days ago
Sakilmostak refactor: resolve comments
38086e8a
Sakilmostak refactor: remove try_from of NameType from Optional value
5d6f6eb0
Sakilmostak chore: merge main
e1fb40aa
Sakilmostak refactor: merge main
b830c169
jarnura
jarnura dismissed these changes on 2025-03-27
Sakilmostak Sakilmostak dismissed their stale review via b830c169 27 days ago
Sakilmostak Sakilmostak requested a review 27 days ago
Sakilmostak Sakilmostak requested a review 27 days ago
Sakilmostak Sakilmostak requested a review 27 days ago
Sakilmostak Sakilmostak requested a review 27 days ago
hyperswitch-bot hyperswitch-bot added M-database-changes
hyperswitch-bot hyperswitch-bot added M-api-contract-changes
Sakilmostak Merge branch 'main' into card_holder_name_validator
64851231
Sakilmostak Sakilmostak removed M-database-changes
Sakilmostak Sakilmostak removed M-api-contract-changes
Sakilmostak Sakilmostak removed review request 27 days ago
Sakilmostak Sakilmostak removed review request 27 days ago
Sakilmostak Sakilmostak removed review request 27 days ago
Sakilmostak Sakilmostak removed review request 27 days ago
prajjwalkumar17
prajjwalkumar17 approved these changes on 2025-03-27
srujanchikke
srujanchikke approved these changes on 2025-03-27
jarnura
jarnura approved these changes on 2025-03-27
Narayanbhat166
Narayanbhat166 approved these changes on 2025-03-27
likhinbopanna likhinbopanna merged 1100dcc6 into main 22 days ago
likhinbopanna likhinbopanna deleted the card_holder_name_validator branch 22 days ago

Login to write a write a comment.

Login via GitHub

Assignees
Labels
Milestone