credit_card_sanitizer 0.6.9 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/credit_card_sanitizer.rb +63 -45
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed9cddb911074ee952f3f65184cd75c50b81376f5c57b6aa9d198f0bc5859aff
|
4
|
+
data.tar.gz: 735236460e25ffcb4f458046a664a174bfdffc460c6eebbbec2c9a950ef06697
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2536400933a1b3c5ee9a6df3070eb31f4b2447a780c335a3429055fb046df072a416c34813d9e4bd00238beaac3db626a285080b7f7063d1af45b87ef29656b4
|
7
|
+
data.tar.gz: d9f623e2b39d0ca88430bc15407d664c40569b8802dc85c10ca2c3795a339f3b129f95fe0d120e6623eeca1c28f02a9203159bd42c2446fab4000bf8cdd5b6a5
|
@@ -1,39 +1,48 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require 'securerandom'
|
5
|
-
require 'tracking_number'
|
1
|
+
require "luhn_checksum"
|
2
|
+
require "securerandom"
|
3
|
+
require "tracking_number"
|
6
4
|
|
7
5
|
class CreditCardSanitizer
|
8
|
-
# https://github.com/Shopify/active_merchant/blob/master/lib/active_merchant/billing/credit_card_methods.rb#L5-L18
|
9
6
|
CARD_COMPANIES = {
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
7
|
+
"visa" => /^4\d{12}(\d{3})?(\d{3})?$/,
|
8
|
+
"master" => /^(5[1-5]\d{4}|677189|222[1-9]\d{2}|22[3-9]\d{3}|2[3-6]\d{4}|27[01]\d{3}|2720\d{2})\d{10}$/,
|
9
|
+
"discover" => /^((6011\d{12})|(65[4-9]\d{13})|(64[4-9]\d{13})|(622(?:12[6-9]|1[3-9]\d|[2-8]\d{2}|9[01]\d|92[0-5])\d{10}))$/,
|
10
|
+
"american_express" => /^3[47]\d{13}$/,
|
11
|
+
"diners_club" => /^3(0[0-5]|[68]\d)\d{11}$/,
|
12
|
+
"jcb" => /^35(28|29|[3-8]\d)\d{12}$/,
|
13
|
+
"switch" => /^(6759\d{12}(\d{2,3})?|(4903|4905|4911|4936|6333|6759)\d{12}|(4903|4905|4911|4936|6333|6759)\d{14}|(4903|4905|4911|4936|6333|6759)\d{15}|564182\d{10}|564182\d{12}|564182\d{13}|633110\d{10}|633110\d{12}|633110\d{13})$/,
|
14
|
+
"solo" => /^(6767\d{12}(\d{2,3})?|6334\d{12}|6334\d{14}|6334\d{15}|6767\d{14}|6767\d{15})$/,
|
15
|
+
"dankort" => /^5019\d{12}$/,
|
16
|
+
"maestro" => /^(5[06-8]\d{10,17}|6\d\d{10,17}|5018|5020|5038|5893|6304|6759|6761|6762|6763\d{8,15})$/,
|
17
|
+
"forbrugsforeningen" => /^600722\d{10}$/,
|
18
|
+
"laser" => /^(6304|6706|6709|6771(?!89))(\d{12,15}|\d{8}(\d{4}|\d{6,7})?)$/,
|
19
|
+
"bc_global" => /^(6541|6556)\d{12}$/,
|
20
|
+
"carte_blanche" => /^389\d{11}$/,
|
21
|
+
"insta_payment" => /^63[7-9]\d{13}$/,
|
22
|
+
"korean_local" => /^9\d{15}$/,
|
23
|
+
"union_pay" => /^62\d{14,17}$/,
|
24
|
+
"visa_master" => /^(4\d{12}(\d{3})?|5[1-5]\d{14})$/
|
22
25
|
}.freeze
|
23
26
|
|
24
27
|
CARD_NUMBER_GROUPINGS = {
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
"visa" => [[4, 4, 4, 4]],
|
29
|
+
"master" => [[4, 4, 4, 4]],
|
30
|
+
"discover" => [[4, 4, 4, 4]],
|
31
|
+
"american_express" => [[4, 6, 5]],
|
32
|
+
"diners_club" => [[4, 6, 4]],
|
33
|
+
"jcb" => [[4, 4, 4, 4]],
|
34
|
+
"switch" => [[4, 4, 4, 4]],
|
35
|
+
"solo" => [[4, 4, 4, 4], [4, 4, 4, 4, 2], [4, 4, 4, 4, 3]],
|
36
|
+
"dankort" => [[4, 4, 4, 4]],
|
37
|
+
"maestro" => [[4], [5], [4, 4, 4, 4], [4, 4, 4, 4, 1], [4, 4, 4, 4, 2], [4, 4, 4, 4, 3]],
|
38
|
+
"forbrugsforeningen" => [[4, 4, 4, 4]],
|
39
|
+
"laser" => [[4, 4, 4, 4], [4, 4, 4, 4, 1], [4, 4, 4, 4, 2], [4, 4, 4, 4, 3]],
|
40
|
+
"bc_global" => [[4, 4, 4, 4]],
|
41
|
+
"carte_blanche" => [[4, 6, 4]],
|
42
|
+
"insta_payment" => [[4, 4, 4, 4]],
|
43
|
+
"korean_local" => [[4, 4, 4, 4]],
|
44
|
+
"union_pay" => [[4, 4, 4, 4], [4, 4, 4, 4, 1], [4, 4, 4, 4, 2], [4, 4, 4, 4, 3]],
|
45
|
+
"visa_master" => [[4, 4, 4, 4], [4, 4, 4, 4, 3]]
|
37
46
|
}.freeze
|
38
47
|
|
39
48
|
ACCEPTED_PREFIX = /(?:cc|card|visa|amex)\z/i
|
@@ -44,11 +53,11 @@ class CreditCardSanitizer
|
|
44
53
|
LINE_NOISE_CHAR = /[^\w\n,()&.\/:;<>]/
|
45
54
|
LINE_NOISE = /#{LINE_NOISE_CHAR}{,5}/
|
46
55
|
NONEMPTY_LINE_NOISE = /#{LINE_NOISE_CHAR}{1,5}/
|
47
|
-
SCHEME_OR_PLUS = /((?:+|\+|\/)|(?:[a-zA-Z][
|
56
|
+
SCHEME_OR_PLUS = /((?:+|\+|\/)|(?:[a-zA-Z][-+.a-zA-Z\d]{,9}):[^\s>]+)/
|
48
57
|
NUMBERS_WITH_LINE_NOISE = /#{SCHEME_OR_PLUS}?\d(?:#{LINE_NOISE}\d){10,30}/
|
49
58
|
|
50
59
|
DEFAULT_OPTIONS = {
|
51
|
-
replacement_token:
|
60
|
+
replacement_token: "▇",
|
52
61
|
expose_first: 6,
|
53
62
|
expose_last: 4,
|
54
63
|
use_groupings: false,
|
@@ -88,31 +97,40 @@ class CreditCardSanitizer
|
|
88
97
|
# sanitize!("I want all your credit card numbers!")
|
89
98
|
# #=> nil
|
90
99
|
#
|
91
|
-
#
|
92
|
-
#
|
100
|
+
# If options[:return_changes] is false, returns nil if no redaction happened,
|
101
|
+
# else the full text after redaction.
|
102
|
+
#
|
103
|
+
# If options[:return_changes] is true, returns nil if no redaction happened,
|
104
|
+
# else an array of [old_text, new_text] indicating what substrings were redacted.
|
93
105
|
def sanitize!(text, options = {})
|
94
106
|
options = @settings.merge(options)
|
95
107
|
|
96
108
|
text.force_encoding(Encoding::UTF_8)
|
97
|
-
text.scrub!(
|
98
|
-
|
109
|
+
text.scrub!("�")
|
110
|
+
changes = nil
|
99
111
|
|
100
112
|
without_expiration(text) do
|
101
113
|
text.gsub!(NUMBERS_WITH_LINE_NOISE) do |match|
|
102
114
|
next match if $1
|
103
115
|
|
104
|
-
candidate = Candidate.new(match, match.tr(
|
116
|
+
candidate = Candidate.new(match, match.tr("^0-9", ""), $`, $')
|
105
117
|
|
106
118
|
if valid_context?(candidate, options) && valid_numbers?(candidate, options)
|
107
|
-
|
108
|
-
|
119
|
+
redact_numbers(candidate, options).tap do |redacted_text|
|
120
|
+
changes ||= []
|
121
|
+
changes << [candidate.text, redacted_text]
|
122
|
+
end
|
109
123
|
else
|
110
124
|
match
|
111
125
|
end
|
112
126
|
end
|
113
127
|
end
|
114
128
|
|
115
|
-
|
129
|
+
if options[:return_changes]
|
130
|
+
changes
|
131
|
+
else
|
132
|
+
changes && text
|
133
|
+
end
|
116
134
|
end
|
117
135
|
|
118
136
|
# A proc that can be used
|
@@ -144,16 +162,16 @@ class CreditCardSanitizer
|
|
144
162
|
|
145
163
|
def find_company(numbers)
|
146
164
|
CARD_COMPANIES.each do |company, pattern|
|
147
|
-
return company if numbers
|
165
|
+
return company if pattern.match?(numbers)
|
148
166
|
end
|
149
167
|
end
|
150
168
|
|
151
169
|
def valid_grouping?(candidate, options)
|
152
170
|
if options[:use_groupings]
|
153
|
-
if company = find_company(candidate.numbers)
|
171
|
+
if (company = find_company(candidate.numbers))
|
154
172
|
groupings = candidate.text.split(NONEMPTY_LINE_NOISE).map(&:length)
|
155
173
|
return true if groupings.length == 1
|
156
|
-
if company_groupings = CARD_NUMBER_GROUPINGS[company]
|
174
|
+
if (company_groupings = CARD_NUMBER_GROUPINGS[company])
|
157
175
|
company_groupings.each do |company_grouping|
|
158
176
|
return true if groupings.take(company_grouping.length) == company_grouping
|
159
177
|
end
|
@@ -202,12 +220,12 @@ class CreditCardSanitizer
|
|
202
220
|
end
|
203
221
|
|
204
222
|
def without_expiration(text)
|
205
|
-
expiration_date_boundary = SecureRandom.hex.tr(
|
223
|
+
expiration_date_boundary = SecureRandom.hex.tr("0123456789", "ABCDEFGHIJ")
|
206
224
|
text.gsub!(EXPIRATION_DATE) do |expiration_date|
|
207
225
|
match = expiration_date.match(/(?<whitespace>\s*)(?<rest>.*)/m)
|
208
226
|
"#{match[:whitespace]}#{expiration_date_boundary}#{match[:rest]}#{expiration_date_boundary}"
|
209
227
|
end
|
210
228
|
yield
|
211
|
-
text.gsub!(expiration_date_boundary,
|
229
|
+
text.gsub!(expiration_date_boundary, "")
|
212
230
|
end
|
213
231
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: credit_card_sanitizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Chapweske
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2024-06-21 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: luhn_checksum
|
@@ -67,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
requirements: []
|
70
|
-
rubygems_version: 3.
|
70
|
+
rubygems_version: 3.5.11
|
71
71
|
signing_key:
|
72
72
|
specification_version: 4
|
73
73
|
summary: Credit card sanitizer
|