Credit card validation (#924)

pull/936/head
alessmar 3 years ago committed by GitHub
parent bb30072b48
commit dd2857a4cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      .github/workflows/workflow.yml
  2. 1
      README.md
  3. 39
      baked_in.go
  4. 6
      doc.go
  5. 38
      validator_test.go

@ -41,8 +41,11 @@ jobs:
name: lint name: lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/setup-go@v3
with:
go-version: 1.16
- uses: actions/checkout@v3
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v2 uses: golangci/golangci-lint-action@v3
with: with:
version: v1.45.2 version: v1.45.2

@ -153,6 +153,7 @@ Baked-in Validations
| bcp47_language_tag | Language tag (BCP 47) | | bcp47_language_tag | Language tag (BCP 47) |
| btc_addr | Bitcoin Address | | btc_addr | Bitcoin Address |
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) | | btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
| credit_card | Credit Card Number |
| datetime | Datetime | | datetime | Datetime |
| e164 | e164 formatted phone number | | e164 | e164 formatted phone number |
| email | E-mail String | email | E-mail String

@ -203,6 +203,7 @@ var (
"bic": isIsoBicFormat, "bic": isIsoBicFormat,
"semver": isSemverFormat, "semver": isSemverFormat,
"dns_rfc1035_label": isDnsRFC1035LabelFormat, "dns_rfc1035_label": isDnsRFC1035LabelFormat,
"credit_card": isCreditCard,
} }
) )
@ -2469,3 +2470,41 @@ func isDnsRFC1035LabelFormat(fl FieldLevel) bool {
val := fl.Field().String() val := fl.Field().String()
return dnsRegexRFC1035Label.MatchString(val) return dnsRegexRFC1035Label.MatchString(val)
} }
// isCreditCard is the validation function for validating if the current field's value is a valid credit card number
func isCreditCard(fl FieldLevel) bool {
val := fl.Field().String()
var creditCard bytes.Buffer
segments := strings.Split(val, " ")
for _, segment := range segments {
if len(segment) < 3 {
return false
}
creditCard.WriteString(segment)
}
ccDigits := strings.Split(creditCard.String(), "")
size := len(ccDigits)
if size < 12 || size > 19 {
return false
}
sum := 0
for i, digit := range ccDigits {
value, err := strconv.Atoi(digit)
if err != nil {
return false
}
if size%2 == 0 && i%2 == 0 || size%2 == 1 && i%2 == 1 {
v := value * 2
if v >= 10 {
sum += 1 + (v % 10)
} else {
sum += v
}
} else {
sum += value
}
}
return (sum % 10) == 0
}

@ -1317,6 +1317,12 @@ More information on https://semver.org/
Usage: semver Usage: semver
Credit Card
This validates that a string value contains a valid credit card number using Luhn algoritm.
Usage: credit_card
Alias Validators and Tags Alias Validators and Tags
NOTE: When returning an error, the tag returned in "FieldError" will be NOTE: When returning an error, the tag returned in "FieldError" will be

@ -11750,3 +11750,41 @@ func TestPostCodeByIso3166Alpha2Field_InvalidKind(t *testing.T) {
_ = New().Struct(test{"ABC", 123, false}) _ = New().Struct(test{"ABC", 123, false})
t.Errorf("Didn't panic as expected") t.Errorf("Didn't panic as expected")
} }
func TestCreditCardFormatValidation(t *testing.T) {
tests := []struct {
value string `validate:"credit_card"`
tag string
expected bool
}{
{"586824160825533338", "credit_card", true},
{"586824160825533328", "credit_card", false},
{"4624748233249780", "credit_card", true},
{"4624748233349780", "credit_card", false},
{"378282246310005", "credit_card", true},
{"378282146310005", "credit_card", false},
{"4624 7482 3324 9780", "credit_card", true},
{"4624 7482 3324 9780", "credit_card", false},
}
validate := New()
for i, test := range tests {
errs := validate.Var(test.value, test.tag)
if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d credit_card failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d credit_card failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "credit_card" {
t.Fatalf("Index: %d credit_card failed Error: %s", i, errs)
}
}
}
}
}

Loading…
Cancel
Save