juspay / hyperswitch

An open source payments switch written in Rust to make payments fast, reliable and affordable
https://hyperswitch.io/
Apache License 2.0
12.34k stars 1.34k forks source link

[FEATURE] Validate card numbers when accepting payment method information #606

Closed SanchithHegde closed 1 year ago

SanchithHegde commented 1 year ago

Feature Description

As of now, we just pass the card information to the payment processor without performing any form of validation on the provided card number. It'd be great if the card number could have been validated on our end whenever a payment is being created or payment method is being created, instead of invalid card numbers being caught by the payment processor.

It'd be preferable if the card number validation logic is included in a new crate called cards which would contain this validation of card numbers and card brand identification logic (taken up on #379). This must check that the card number provided is of correct length, and also handle whitespaces being included in the card number input. Please also include unit tests in your PR.

For external contributors, clarify any questions you may have, and let us know that you're interested in picking this up. We'll assign this issue to you to reduce duplication of effort on the same task.

Possible Implementation

For validating card numbers, you can use the Luhn Algorithm. I'm thinking of an API like so (refer to the newtype pattern):

use masking::StrongSecret;

struct CardNumber(StrongSecret<String>);

let card_number = CardNumber::from_str("..."); // You can use the `FromStr` trait for this purpose

This would ensure that a CardNumber once constructed is always valid and no further validation is necessary. You can also implement Serialize and Deserialize traits on CardNumber.

Have you spent some time to check if this feature request has been raised before?

Have you read the Contributing Guidelines?

Are you willing to submit a PR?

None

phillyphil91 commented 1 year ago

Hi.

I would like to take a look at this.

hemantku commented 1 year ago

Is someone working on this already?

phillyphil91 commented 1 year ago

Hi @SanchithHegde, I'm currently working on this and wondering about error handling. For example when the CC number validation would fail. Should I create a new error type for this? Is there a central place for errors? I saw: crates/router/src/core/errors.rs not sure if it would make sense to include this there.

I saw that StrongSecret::from_str(s) is Infallible. So I probably don't have to worry about this, if my assumption is correct. I am mainly concerned with the associated type Err in the FromStr trait. Currently I have as a first try:

impl FromStr for CardNumber {                                                                                                                  
    type Err = Box<dyn std::error::Error>;
SanchithHegde commented 1 year ago

@phillyphil91

Should I create a new error type for this?

Yes, you can have it as an enum if there are multiple possible card number validation errors. Otherwise, a unit struct should suffice.

Is there a central place for errors?

If you're adding this card validation logic in a new crate, you can include the card validation error in the same crate.

I saw that StrongSecret::from_str(s) is Infallible. So I probably don't have to worry about this, if my assumption is correct.

Correct. It should suffice to check if the string input received is valid or not.