Class: CreditCardSanitizer
- Inherits:
-
Object
- Object
- CreditCardSanitizer
- Defined in:
- lib/credit_card_sanitizer.rb
Defined Under Namespace
Classes: Candidate
Constant Summary collapse
- CARD_COMPANIES =
{ 'visa' => /^4\d{12}(\d{3})?(\d{3})?$/, '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}$/, 'discover' => /^((6011|65\d{2}|64[4-9]\d)\d{12}|(62\d{14}))$/, 'american_express' => /^3[47]\d{13}$/, 'diners_club' => /^3(0[0-5]|[68]\d)\d{11}$/, 'jcb' => /^35(28|29|[3-8]\d)\d{12}$/, 'switch' => /^6759\d{12}(\d{2,3})?$/, 'solo' => /^6767\d{12}(\d{2,3})?$/, 'dankort' => /^5019\d{12}$/, 'maestro' => /^(5[06-8]|6\d)\d{10,17}$/, 'forbrugsforeningen' => /^600722\d{10}$/, 'laser' => /^(6304|6706|6709|6771(?!89))\d{8}(\d{4}|\d{6,7})?$/ }.freeze
- CARD_NUMBER_GROUPINGS =
{ 'visa' => [[4, 4, 4, 4]], 'master' => [[4, 4, 4, 4]], 'discover' => [[4, 4, 4, 4]], 'american_express' => [[4, 6, 5]], 'diners_club' => [[4, 6, 4]], 'jcb' => [[4, 4, 4, 4]], 'switch' => [[4, 4, 4, 4]], 'solo' => [[4, 4, 4, 4]], 'dankort' => [[4, 4, 4, 4]], 'maestro' => [[4], [5]], 'forbrugsforeningen' => [[4, 4, 4, 4]], 'laser' => [[4, 4, 4, 4]] }.freeze
- ACCEPTED_PREFIX =
/(?:cc|card|visa|amex)\z/i- ACCEPTED_POSTFIX =
/\Aex/i- ALPHANUMERIC =
/[[:alnum:]]/i- VALID_COMPANY_PREFIXES =
Regexp.union(*CARD_COMPANIES.values)
- EXPIRATION_DATE =
/\s(?:0?[1-9]|1[0-2])(?:\/|-)(?:\d{4}|\d{2})(?:\D|$)/- LINE_NOISE_CHAR =
/[^\w\n,()&.\/:;<>]/- LINE_NOISE =
/#{LINE_NOISE_CHAR}{,5}/- NONEMPTY_LINE_NOISE =
/#{LINE_NOISE_CHAR}{1,5}/- SCHEME_OR_PLUS =
/((?:+|\+|\/)|(?:[a-zA-Z][\-+.a-zA-Z\d]{,9}):[^\s>]+)/- NUMBERS_WITH_LINE_NOISE =
/#{SCHEME_OR_PLUS}?\d(?:#{LINE_NOISE}\d){10,30}/- DEFAULT_OPTIONS =
{ replacement_token: '▇', expose_first: 6, expose_last: 4, use_groupings: false, exclude_tracking_numbers: false, parse_flanking: false }.freeze
Instance Attribute Summary collapse
-
#settings ⇒ Object
readonly
Returns the value of attribute settings.
Class Method Summary collapse
-
.parameter_filter(options = {}) ⇒ Object
A proc that can be used.
Instance Method Summary collapse
-
#initialize(options = {}) ⇒ CreditCardSanitizer
constructor
Create a new CreditCardSanitizer.
-
#sanitize!(text, options = {}) ⇒ Object
Finds credit card numbers and redacts digits from them.
Constructor Details
#initialize(options = {}) ⇒ CreditCardSanitizer
Create a new CreditCardSanitizer
Options
:replacement_character - the character that will replace digits for redaction. :expose_first - the number of leading digits that will not be redacted. :expose_last - the number of ending digits that will not be redacted. :use_groupings - require card number groupings to match to redact. :exclude_tracking_numbers - do not redact valid shipping company tracking numbers.
73 74 75 |
# File 'lib/credit_card_sanitizer.rb', line 73 def initialize( = {}) @settings = DEFAULT_OPTIONS.merge() end |
Instance Attribute Details
#settings ⇒ Object (readonly)
Returns the value of attribute settings.
59 60 61 |
# File 'lib/credit_card_sanitizer.rb', line 59 def settings @settings end |
Class Method Details
.parameter_filter(options = {}) ⇒ Object
A proc that can be used
text - the text containing potential credit card numbers
Examples
Rails.app.config.filter_parameters = [:password, CreditCardSanitizer.parameter_filter]
env = {
"action_dispatch.request.parameters" => {"credit_card_number" => "4111 1111 1111 1111", "password" => "123"},
"action_dispatch.parameter_filter" => Rails.app.config.filter_parameters
}
>> ActionDispatch::Request.new(env).filtered_parameters
=> {"credit_card_number" => "4111 11▇▇ ▇▇▇▇ 1111", "password" => "[FILTERED]"}
Returns a Proc that takes the key/value of the request parameter.
144 145 146 |
# File 'lib/credit_card_sanitizer.rb', line 144 def self.parameter_filter( = {}) proc { |_, value| new().sanitize!(value) if value.is_a?(String) } end |
Instance Method Details
#sanitize!(text, options = {}) ⇒ Object
Finds credit card numbers and redacts digits from them
text - the text containing potential credit card numbers
Examples
# If the text contains a credit card number:
sanitize!("4111 1111 1111 1111")
#=> "4111 11▇▇ ▇▇▇▇ 1111"
# If the text does not contain a credit card number:
sanitize!("I want all your credit card numbers!")
#=> nil
If options is false, returns nil if no redaction happened, else the full text after redaction.
If options is true, returns nil if no redaction happened, else an array of [old_text, new_text] indicating what substrings were redacted.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/credit_card_sanitizer.rb', line 96 def sanitize!(text, = {}) = @settings.merge() text.force_encoding(Encoding::UTF_8) text.scrub!('�') changes = nil without_expiration(text) do text.gsub!(NUMBERS_WITH_LINE_NOISE) do |match| next match if $1 candidate = Candidate.new(match, match.tr('^0-9', ''), $`, $') if valid_context?(candidate, ) && valid_numbers?(candidate, ) redact_numbers(candidate, ).tap do |redacted_text| changes ||= [] changes << [candidate.text, redacted_text] end else match end end end if [:return_changes] changes else changes && text end end |