credit_card_validations 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +75 -0
- data/Rakefile +13 -0
- data/credit_card_validations.gemspec +22 -0
- data/lib/credit_card_number_validator.rb +11 -0
- data/lib/credit_card_validations.rb +13 -0
- data/lib/credit_card_validations/card_rules.rb +58 -0
- data/lib/credit_card_validations/detector.rb +72 -0
- data/lib/credit_card_validations/luhn.rb +17 -0
- data/lib/credit_card_validations/version.rb +3 -0
- data/test/credit_card_validations_test.rb +92 -0
- metadata +82 -0
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Igor Fedoronchuk
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# CreditCardValidations
|
2
|
+
|
3
|
+
Gem adds validator to check whether or not a given number actually falls within the ranges of possible numbers prior to performing such verification, and, as such, CreditCardValidations simply verifies that the credit card number provided is well-formed.
|
4
|
+
This is a port of Zend Framework `Zend\Validator\CreditCard` .
|
5
|
+
|
6
|
+
The following issuing institutes are accepted:
|
7
|
+
|
8
|
+
|
9
|
+
American Express
|
10
|
+
China UnionPay
|
11
|
+
Diners Club
|
12
|
+
Dinner Club US
|
13
|
+
Discover
|
14
|
+
JCB
|
15
|
+
Maestro
|
16
|
+
MasterCard
|
17
|
+
Solo
|
18
|
+
Visa
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Also You can add your own rules to detect other credit card brands/types
|
23
|
+
passing name,length(integer/array of integers) and prefix(string/array of strings)
|
24
|
+
Example
|
25
|
+
|
26
|
+
CreditCardValidations::Detector.add_rule(:voyager, 15, '86')
|
27
|
+
voyager_test_card_number = '869926275400212'
|
28
|
+
CreditCardValidations::Detector.new(voyager_test_card_number).brand #:voyager
|
29
|
+
CreditCardValidations::Detector.new(voyager_test_card_number).voyager? #true
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
AvtiveModel support
|
34
|
+
|
35
|
+
only for certain brads
|
36
|
+
|
37
|
+
class CreditCardModel
|
38
|
+
attr_accessor :number
|
39
|
+
include ActiveModel::Validations
|
40
|
+
validates :number, presence: true, credit_card_number: {brands: [:amex, :maestro]}
|
41
|
+
end
|
42
|
+
|
43
|
+
for all known brands
|
44
|
+
|
45
|
+
validates :number, presence: true, credit_card_number: true
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
## Installation
|
52
|
+
|
53
|
+
Add this line to your application's Gemfile:
|
54
|
+
|
55
|
+
gem 'credit_card_validations'
|
56
|
+
|
57
|
+
And then execute:
|
58
|
+
|
59
|
+
$ bundle
|
60
|
+
|
61
|
+
Or install it yourself as:
|
62
|
+
|
63
|
+
$ gem install credit_card_validations
|
64
|
+
|
65
|
+
## Usage
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
## Contributing
|
70
|
+
|
71
|
+
1. Fork it
|
72
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
73
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
74
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
75
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'credit_card_validations/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "credit_card_validations"
|
8
|
+
gem.version = CreditCardValidations::VERSION
|
9
|
+
gem.authors = ["Igor"]
|
10
|
+
gem.email = ["fedoronchuk@gmail.com"]
|
11
|
+
gem.description = %q{A ruby gem for validating credit card numbers (a port of ZF2 Zend\Validator\CreditCard) —}
|
12
|
+
gem.summary = "gem for credit card numbers validation, card brands detections"
|
13
|
+
gem.homepage = "https://github.com/Fivell/credit_card_validations"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency('activemodel', '~> 3.0')
|
21
|
+
gem.add_dependency('activesupport', '~> 3.0')
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class CreditCardNumberValidator < ActiveModel::EachValidator
|
2
|
+
|
3
|
+
def validate_each(record, attribute, value)
|
4
|
+
brands = options.fetch(:brands)
|
5
|
+
record.errors[attribute] << (options[:message] || "is not valid") unless credit_card_valid?(value, Array.wrap(brands))
|
6
|
+
end
|
7
|
+
|
8
|
+
def credit_card_valid?(number, brands = [])
|
9
|
+
CreditCardValidations::Detector.new(number).valid?(*brands)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'credit_card_validations/version'
|
2
|
+
require 'active_model'
|
3
|
+
require 'active_support/all'
|
4
|
+
require 'active_model/validations'
|
5
|
+
require 'credit_card_number_validator'
|
6
|
+
|
7
|
+
module CreditCardValidations
|
8
|
+
extend ActiveSupport::Autoload
|
9
|
+
autoload :VERSION, 'credit_card_validations/version'
|
10
|
+
autoload :Luhn, 'credit_card_validations/luhn'
|
11
|
+
autoload :CardRules , 'credit_card_validations/card_rules'
|
12
|
+
autoload :Detector , 'credit_card_validations/detector'
|
13
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module CreditCardValidations
|
2
|
+
module CardRules
|
3
|
+
######## most used brands #########
|
4
|
+
|
5
|
+
|
6
|
+
VISA = [
|
7
|
+
{length: [16], prefixes: ['4']}
|
8
|
+
]
|
9
|
+
MASTERCARD = [
|
10
|
+
{length: [16], prefixes: ['51', '52', '53', '54', '55']}
|
11
|
+
]
|
12
|
+
######## other brands ########
|
13
|
+
AMEX = [
|
14
|
+
{length: [15], prefixes: ['34', '37']}
|
15
|
+
]
|
16
|
+
|
17
|
+
DINERS = [
|
18
|
+
{length: [14], prefixes: ['300', '301', '302', '303', '304', '305', '36']},
|
19
|
+
]
|
20
|
+
|
21
|
+
#There are Diners Club (North America) cards that begin with 5. These are a joint venture between Diners Club and MasterCard, and are processed like a MasterCard
|
22
|
+
DINERS_US = [
|
23
|
+
{length: [16], prefixes: ['54', '55']}
|
24
|
+
]
|
25
|
+
|
26
|
+
DISCOVER = [
|
27
|
+
{length: [16], prefixes: ['6011', '622126', '622127', '622128', '622129', '62213',
|
28
|
+
'62214', '62215', '62216', '62217', '62218', '62219',
|
29
|
+
'6222', '6223', '6224', '6225', '6226', '6227', '6228',
|
30
|
+
'62290', '62291', '622920', '622921', '622922', '622923',
|
31
|
+
'622924', '622925', '644', '645', '646', '647', '648',
|
32
|
+
'649', '65']}
|
33
|
+
]
|
34
|
+
|
35
|
+
JCB = [
|
36
|
+
{length: [16], prefixes: ['3528', '3529', '353', '354', '355', '356', '357', '358']}
|
37
|
+
]
|
38
|
+
|
39
|
+
|
40
|
+
LASER = [
|
41
|
+
{length: [16, 17, 18, 19], prefixes: ['6304', '6706', '6771', '6709']}
|
42
|
+
]
|
43
|
+
|
44
|
+
MAESTRO = [
|
45
|
+
{length: [12, 13, 14, 15, 16, 17, 18, 19], prefixes: ['5018', '5020', '5038', '6304', '6759', '6761', '6763']}
|
46
|
+
]
|
47
|
+
|
48
|
+
SOLO = [
|
49
|
+
{length: [16, 18, 19], prefixes: ['6334', '6767']}
|
50
|
+
]
|
51
|
+
|
52
|
+
UNIONPAY = [
|
53
|
+
{length: [16, 17, 18, 19], prefixes: ['620', '621', '623', '625', '626']}
|
54
|
+
]
|
55
|
+
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module CreditCardValidations
|
2
|
+
class Detector
|
3
|
+
class_attribute :rules
|
4
|
+
self.rules = {}
|
5
|
+
|
6
|
+
attr_reader :number
|
7
|
+
|
8
|
+
def initialize(number)
|
9
|
+
@number = number.to_s.delete(' ')
|
10
|
+
end
|
11
|
+
|
12
|
+
# credit card number
|
13
|
+
def valid?(*brands)
|
14
|
+
!!valid_number?(*brands)
|
15
|
+
end
|
16
|
+
|
17
|
+
#brand name
|
18
|
+
def brand
|
19
|
+
valid_number?
|
20
|
+
end
|
21
|
+
|
22
|
+
def valid_number?(*brands)
|
23
|
+
return nil unless valid_luhn?
|
24
|
+
number_length = number.length
|
25
|
+
brand_rules = brands.blank? ? self.rules : self.rules.slice(*brands.map{|el| el.downcase })
|
26
|
+
unless brand_rules.blank?
|
27
|
+
brand_rules.each do |brand_name, rules|
|
28
|
+
rules.each do |rule|
|
29
|
+
return brand_name if (rule[:length].include?(number_length) and number.match(rule[:regexp]))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
#check if luhn valid
|
37
|
+
def valid_luhn?
|
38
|
+
Luhn.valid?(number)
|
39
|
+
end
|
40
|
+
|
41
|
+
class << self
|
42
|
+
|
43
|
+
#create regexp by array of prefixes
|
44
|
+
def compile_regexp(prefixes)
|
45
|
+
Regexp.new("^((#{prefixes.join(")|(")}))")
|
46
|
+
end
|
47
|
+
|
48
|
+
#create rule for detecting brand
|
49
|
+
def add_rule(brand, length, prefixes)
|
50
|
+
prefixes = Array.wrap(prefixes)
|
51
|
+
length = Array.wrap(length)
|
52
|
+
rules[brand] = [] if rules[brand].blank?
|
53
|
+
rules[brand] << {length: length, regexp: compile_regexp(prefixes), prefixes: prefixes}
|
54
|
+
#create methods like visa? mastercard? etc
|
55
|
+
class_eval <<-BOOLEAN_RULE, __FILE__, __LINE__
|
56
|
+
def #{brand}?
|
57
|
+
valid?(:#{brand})
|
58
|
+
end
|
59
|
+
BOOLEAN_RULE
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
CardRules.constants.each do |const_name|
|
64
|
+
CardRules.const_get(const_name).each do |const_value|
|
65
|
+
self.add_rule(const_name.to_s.downcase.to_sym , const_value[:length], const_value[:prefixes])
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module CreditCardValidations
|
2
|
+
class Luhn
|
3
|
+
def self.valid?(number)
|
4
|
+
s1 = s2 = 0
|
5
|
+
number.to_s.reverse.chars.each_slice(2) do |odd, even|
|
6
|
+
s1 += odd.to_i
|
7
|
+
|
8
|
+
double = even.to_i * 2
|
9
|
+
double -= 9 if double >= 10
|
10
|
+
s2 += double
|
11
|
+
end
|
12
|
+
(s1 + s2) % 10 == 0
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
|
3
|
+
unit_tests = File.expand_path("#{File.dirname(__FILE__)}/../test")
|
4
|
+
$:.unshift(lib)
|
5
|
+
$:.unshift(unit_tests)
|
6
|
+
|
7
|
+
require 'credit_card_validations'
|
8
|
+
|
9
|
+
class CreditCardValidationsTest < Test::Unit::TestCase
|
10
|
+
|
11
|
+
class CreditCardModel
|
12
|
+
attr_accessor :number
|
13
|
+
include ActiveModel::Validations
|
14
|
+
validates :number, presence: true, credit_card_number: {brands: [:amex, :maestro]}
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def initialize name
|
19
|
+
super name
|
20
|
+
@test_numbers = {
|
21
|
+
visa: '4012 8888 8888 1881',
|
22
|
+
mastercard: '5274 5763 9425 9961',
|
23
|
+
diners: '3020 4169 3226 43',
|
24
|
+
amex: '3400 0000 0000 009',
|
25
|
+
discover: '6011 1111 1111 1117',
|
26
|
+
maestro: '6759 6498 2643 8453',
|
27
|
+
jcb: '3575 7591 5225 4876',
|
28
|
+
solo: '6767 6222 2222 2222 222',
|
29
|
+
unionpay: '6264185212922132067',
|
30
|
+
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_card_brand_detection
|
35
|
+
@test_numbers.each do |key, value|
|
36
|
+
assert_equal key, detector(value).brand
|
37
|
+
assert detector(value).send("#{key}?")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_card_brand_is_nil_if_credit_card_invalid
|
42
|
+
assert_nil detector('1111111111111111').brand
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_card_valid_method
|
46
|
+
@test_numbers.each do |key, value|
|
47
|
+
assert detector(value).valid?(key)
|
48
|
+
assert detector(value).valid?
|
49
|
+
end
|
50
|
+
assert !detector('1111111111111111').valid?
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def test_card_particular_brand_valid
|
55
|
+
assert !detector(@test_numbers[:visa]).valid?(:mastercard)
|
56
|
+
assert !detector(@test_numbers[:mastercard]).valid?(:visa)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def test_card_particular_brands_valid
|
61
|
+
assert detector(@test_numbers[:visa]).valid?(:mastercard, :visa)
|
62
|
+
assert !detector(@test_numbers[:visa]).valid?(:mastercard, :amex)
|
63
|
+
end
|
64
|
+
|
65
|
+
#add rules which were not present before
|
66
|
+
def test_card_valid_after_rules_added
|
67
|
+
voyager_test_card_number = '869926275400212'
|
68
|
+
assert !detector(voyager_test_card_number).valid?
|
69
|
+
CreditCardValidations::Detector.add_rule(:voyager, 15, '86')
|
70
|
+
assert detector(voyager_test_card_number).valid?
|
71
|
+
assert_equal :voyager, detector(voyager_test_card_number).brand
|
72
|
+
assert detector(voyager_test_card_number).voyager?
|
73
|
+
assert !detector(voyager_test_card_number).visa?
|
74
|
+
assert !detector(voyager_test_card_number).mastercard?
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_active_model_validator
|
78
|
+
cc = CreditCardModel.new
|
79
|
+
cc.number = @test_numbers[:mastercard]
|
80
|
+
assert !cc.valid?
|
81
|
+
cc.number = @test_numbers[:amex]
|
82
|
+
assert cc.valid?
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
def detector(number)
|
88
|
+
CreditCardValidations::Detector.new(number)
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: credit_card_validations
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Igor
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activemodel
|
16
|
+
requirement: &70262684219780 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70262684219780
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &70262684219080 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3.0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70262684219080
|
36
|
+
description: A ruby gem for validating credit card numbers (a port of ZF2 Zend\Validator\CreditCard)
|
37
|
+
—
|
38
|
+
email:
|
39
|
+
- fedoronchuk@gmail.com
|
40
|
+
executables: []
|
41
|
+
extensions: []
|
42
|
+
extra_rdoc_files: []
|
43
|
+
files:
|
44
|
+
- Gemfile
|
45
|
+
- LICENSE.txt
|
46
|
+
- README.md
|
47
|
+
- Rakefile
|
48
|
+
- credit_card_validations.gemspec
|
49
|
+
- lib/credit_card_number_validator.rb
|
50
|
+
- lib/credit_card_validations.rb
|
51
|
+
- lib/credit_card_validations/card_rules.rb
|
52
|
+
- lib/credit_card_validations/detector.rb
|
53
|
+
- lib/credit_card_validations/luhn.rb
|
54
|
+
- lib/credit_card_validations/version.rb
|
55
|
+
- test/credit_card_validations_test.rb
|
56
|
+
homepage: https://github.com/Fivell/credit_card_validations
|
57
|
+
licenses: []
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.8.17
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: gem for credit card numbers validation, card brands detections
|
80
|
+
test_files:
|
81
|
+
- test/credit_card_validations_test.rb
|
82
|
+
has_rdoc:
|