codecal 0.4.0 → 0.4.1
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/.gitignore +1 -1
- data/README.md +1 -25
- data/lib/codecal.rb +18 -123
- data/lib/codecal/version.rb +1 -1
- data/lib/lib/mask.rb +55 -0
- data/lib/lib/modulo.rb +46 -0
- data/lib/lib/validation.rb +22 -0
- metadata +6 -4
- data/lib/code.rb +0 -19
- data/lib/currencies.yml +0 -1270
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 906b6f9a01fba1bbe351b720d0c627b908cbd1fa
|
4
|
+
data.tar.gz: 936507f7d62bb95cd9a4a8b8de08e34fb25e8fa7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 610df9b32e98baaa6209e84aa83c0be8df835a20016b949421846639e8a4fb22dff19916d624e775ad4be5dd5ceb0c87516bfc75f40a8e524cdd67d8c5b26cb1
|
7
|
+
data.tar.gz: 0d55b7353a451a50464c27db02d743d1e72afce2475856b1185f4e6e4103207461e1c9bf4cebbc9f218ea62e17cf4deaa708d2e36d2e49f25e163cd240f9be24
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -25,19 +25,9 @@ codecal = Codecal::Calc.new()
|
|
25
25
|
|
26
26
|
codecal = Codecal::Calc.new('fdsa32jkh89704lncmxzvrueopwytq')
|
27
27
|
|
28
|
-
# Generate customer code for user account
|
29
|
-
# Parameters:
|
30
|
-
# number : Integer(<=9) -- code to be calculated and masked
|
31
|
-
# currency : String --currency name
|
32
|
-
# Return: Hash
|
33
|
-
# success : boolean -- generate customer code success
|
34
|
-
# customer code : String -- 16 numbers string when success == true
|
35
|
-
# error : String -- error message of parameters when success == false
|
36
|
-
codecal.bank_customer_code_generate(number, currency)
|
37
|
-
|
38
28
|
# Generate simple code for account
|
39
29
|
# Parameters:
|
40
|
-
# number : Integer
|
30
|
+
# number : Integer -- code to be calculated and masked
|
41
31
|
# Return: Hash
|
42
32
|
# success : boolean -- generate customer code success
|
43
33
|
# customer code : String -- numbers(number.length + 1) string when success == true
|
@@ -54,13 +44,6 @@ codecal.simple_code_generate(number)
|
|
54
44
|
# error : String -- error message of parameters when success == false
|
55
45
|
codecal.code_generate_with_mask(mask, number)
|
56
46
|
|
57
|
-
# Validate customer code
|
58
|
-
# Parameters:
|
59
|
-
# customer_code : String
|
60
|
-
# Return:
|
61
|
-
# valid : boolean
|
62
|
-
codecal.validate_bank_customer_code(String)
|
63
|
-
|
64
47
|
# Validate simple code
|
65
48
|
# Parameters:
|
66
49
|
# simple_code : String
|
@@ -83,10 +66,3 @@ codecal.validate_masked_code(String)
|
|
83
66
|
# Return:
|
84
67
|
# code : String(>=6) || false : boolean
|
85
68
|
codecal.get_unmasked_code(String)
|
86
|
-
|
87
|
-
# Get currency name
|
88
|
-
# Parameters:
|
89
|
-
# currency_code : String(4)
|
90
|
-
# Return:
|
91
|
-
# currency name : String -- nil if not found
|
92
|
-
codecal.get_currency_name(String)
|
data/lib/codecal.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
require "codecal/version"
|
2
|
-
require_relative "./
|
2
|
+
require_relative "./lib/modulo"
|
3
|
+
require_relative "./lib/mask"
|
4
|
+
require_relative "./lib/validation"
|
3
5
|
|
4
6
|
module Codecal
|
5
7
|
|
6
8
|
class Calc
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
include Validation
|
10
|
+
include Modulo
|
11
|
+
include Mask
|
12
|
+
|
13
|
+
@@MASK_ALPHABET = ['a','4','p','9','h','r','7','q','c','3','b','2','j','s','6','d','t','8','k','u','e','v','f','w','x','5','m','y','g','z','n']
|
10
14
|
|
11
15
|
def initialize(mask_alphabet = nil)
|
12
16
|
if mask_alphabet.is_a?(String) &&
|
@@ -15,61 +19,38 @@ module Codecal
|
|
15
19
|
mask_alphabet.size == mask_alphabet.split('').uniq.size
|
16
20
|
@mask_alphabet = mask_alphabet.split('')
|
17
21
|
else
|
18
|
-
@mask_alphabet = @@MASK_ALPHABET
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def bank_customer_code_generate(account_id, currency)
|
23
|
-
errormsg = ""
|
24
|
-
if account_id == nil || currency == nil
|
25
|
-
errormsg += "parameter is nil. "
|
26
|
-
return {success:false, error: errormsg}
|
27
|
-
end
|
28
|
-
errormsg += "parameter 1 type should be Integer and length not longer than 9. " unless account_id.is_a?(Integer) && account_id.to_s.size <= 9
|
29
|
-
currency.is_a?(String) ? currency.upcase! : errormsg += "parameter 2 type should be String. "
|
30
|
-
currency_code = Code.new[currency]
|
31
|
-
errormsg += "currency not found. " unless currency_code
|
32
|
-
if errormsg.size == 0
|
33
|
-
cal_array = ("%09d" % account_id + "%04d" % currency_code.to_i).split("").map! {|i| i.to_i}
|
34
|
-
{success:true,customer_code: code_calculate(cal_array, @@generate_seed) }
|
35
|
-
else
|
36
|
-
{success:false, error: errormsg}
|
22
|
+
@mask_alphabet = @@MASK_ALPHABET
|
37
23
|
end
|
38
24
|
end
|
39
25
|
|
40
|
-
def simple_code_generate(
|
26
|
+
def simple_code_generate(number)
|
41
27
|
errormsg = ""
|
42
|
-
if
|
28
|
+
if number == nil
|
43
29
|
errormsg += "parameter is nil. "
|
44
30
|
return {success:false, error: errormsg}
|
45
31
|
end
|
46
|
-
errormsg += "the type of the code to be encrypted should be Integer. " unless all_digits?(
|
32
|
+
errormsg += "the type of the code to be encrypted should be Integer. " unless all_digits?(number.to_s)
|
47
33
|
if errormsg.size == 0
|
48
|
-
cal_array = (
|
49
|
-
{success:true,customer_code: simple_code_calculate(cal_array
|
34
|
+
cal_array = (number.to_i.to_s).split("").map! {|i| i.to_i}
|
35
|
+
{success:true, customer_code: simple_code_calculate(cal_array) }
|
50
36
|
else
|
51
37
|
{success:false, error: errormsg}
|
52
38
|
end
|
53
39
|
end
|
54
40
|
|
55
|
-
def code_generate_with_mask(mask,
|
41
|
+
def code_generate_with_mask(mask, number)
|
56
42
|
errormsg = "mark should be string of letter or number and length should >= 5" unless is_legal_mask?(mask)
|
57
43
|
return {success:false, error: errormsg} if errormsg
|
58
|
-
result = simple_code_generate(
|
44
|
+
result = simple_code_generate(number)
|
59
45
|
return result unless result[:success]
|
60
46
|
offset = get_mask_offset(mask)
|
47
|
+
# puts "masked code: #{result[:customer_code]}"
|
61
48
|
{success:true, customer_code: mask_code(offset, result[:customer_code])}
|
62
49
|
end
|
63
50
|
|
64
|
-
def validate_bank_customer_code(customer_code)
|
65
|
-
return false unless customer_code && customer_code.is_a?(String) && customer_code.size == 16
|
66
|
-
calcode = code_calculate(customer_code[0..12].split("").map! {|i| i.to_i}, @@generate_seed)
|
67
|
-
return customer_code == calcode
|
68
|
-
end
|
69
|
-
|
70
51
|
def validate_simple_code(simple_code)
|
71
52
|
return false unless simple_code && simple_code.to_i > 0 && simple_code.size > 1
|
72
|
-
calcode = simple_code_calculate(simple_code[0..-2].split("").map! {|i| i.to_i}
|
53
|
+
calcode = simple_code_calculate(simple_code[0..-2].split("").map! {|i| i.to_i})
|
73
54
|
return simple_code == calcode
|
74
55
|
end
|
75
56
|
|
@@ -85,10 +66,6 @@ module Codecal
|
|
85
66
|
return masked_code == mask_code(offset, result[:customer_code])
|
86
67
|
end
|
87
68
|
|
88
|
-
def convert_masked_code_typo(masked_code)
|
89
|
-
masked_code.gsub('1', 'l')
|
90
|
-
end
|
91
|
-
|
92
69
|
def get_unmasked_code(mask, masked_code)
|
93
70
|
return false unless is_legal_masked_code?(masked_code)
|
94
71
|
return false unless is_legal_mask?(mask)
|
@@ -99,87 +76,5 @@ module Codecal
|
|
99
76
|
masked_code.size == code.size ? code : false
|
100
77
|
end
|
101
78
|
|
102
|
-
def get_currency_name(currency_code)
|
103
|
-
return nil if !currency_code || currency_code.size !=4 || !currency_code.is_a?(String)
|
104
|
-
return Code.new.get_name(currency_code)
|
105
|
-
end
|
106
|
-
|
107
|
-
private
|
108
|
-
def code_calculate(array, seed)
|
109
|
-
code = array.each_with_index.inject(0){|count, (i, index)| count += i*seed[index]}
|
110
|
-
return array.join + ("%03d" % code).to_s
|
111
|
-
end
|
112
|
-
|
113
|
-
def simple_code_calculate(array, seed)
|
114
|
-
code = array.reverse.each_with_index.inject(0){|count, (i, index)| count += i*( index < 11 ? seed.reverse[index + 1] : (index+1).times.inject(1) {|c| c *= 3} % 7 ) }
|
115
|
-
return (array.join + ( code % 7 ).to_s).to_i.to_s
|
116
|
-
end
|
117
|
-
|
118
|
-
def mask_code(offset, code)
|
119
|
-
code_arr = code.size > 5 ? code.split("") : ("%06d" % code).split("")
|
120
|
-
masked_code = code_arr.each_with_index.inject([]) do |code, (c, i)|
|
121
|
-
code.push(mask_char(c, offset[ i % offset.size ]))
|
122
|
-
end
|
123
|
-
start_code = masked_code.pop
|
124
|
-
masked_code.unshift(start_code).join
|
125
|
-
end
|
126
|
-
|
127
|
-
def unmask_code(offset, masked_code)
|
128
|
-
masked_code = masked_code[1..-1] + masked_code[0]
|
129
|
-
code = masked_code.downcase.split("").each_with_index.inject([]) do |code, (c, i)|
|
130
|
-
code.push(un_mask_char(c, offset[ i % offset.size ]))
|
131
|
-
end
|
132
|
-
code.join
|
133
|
-
end
|
134
|
-
|
135
|
-
def get_mask_offset(mask)
|
136
|
-
mask.split("").inject([]) do |offset,c|
|
137
|
-
[[*'a'..'z'], [*'A'..'Z'], [*'0'..'9']].each do |m|
|
138
|
-
if m.include?(c)
|
139
|
-
offset.push(m.find_index(c))
|
140
|
-
break
|
141
|
-
end
|
142
|
-
end
|
143
|
-
offset
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def all_letters_or_digits?(str)
|
148
|
-
str[/[a-zA-Z0-9]+/] == str
|
149
|
-
end
|
150
|
-
|
151
|
-
def all_digits?(str)
|
152
|
-
str[/[0-9]+/] == str
|
153
|
-
end
|
154
|
-
|
155
|
-
def is_legal_mask?(mask)
|
156
|
-
return false if !mask.is_a?(String) || mask.size < 6 || !all_letters_or_digits?(mask)
|
157
|
-
return true
|
158
|
-
end
|
159
|
-
|
160
|
-
def is_legal_masked_code?(masked_code)
|
161
|
-
return false unless masked_code.is_a?(String) && masked_code.size > 5
|
162
|
-
return false unless mask_alphabet_include?(masked_code)
|
163
|
-
return true
|
164
|
-
end
|
165
|
-
|
166
|
-
def mask_alphabet_include?(code)
|
167
|
-
code.split('').each do |c|
|
168
|
-
return false unless @mask_alphabet.include?(c)
|
169
|
-
end
|
170
|
-
true
|
171
|
-
end
|
172
|
-
|
173
|
-
def mask_char(char, offset)
|
174
|
-
if all_digits?(char) && char.size == 1
|
175
|
-
@mask_alphabet[(@mask_alphabet.find_index(@mask_alphabet[char.to_i]) + offset) % @mask_alphabet.size]
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
def un_mask_char(char, offset)
|
180
|
-
if mask_alphabet_include?(char)
|
181
|
-
(@mask_alphabet.find_index(char) - offset) % @mask_alphabet.size
|
182
|
-
end
|
183
|
-
end
|
184
79
|
end
|
185
80
|
end
|
data/lib/codecal/version.rb
CHANGED
data/lib/lib/mask.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Codecal
|
2
|
+
module Mask
|
3
|
+
def mask_code(offset, code)
|
4
|
+
code_arr = code.size > 5 ? code.split("") : ("%06d" % code).split("")
|
5
|
+
masked_code = code_arr.each_with_index.inject([]) do |codes, (c, i)|
|
6
|
+
codes.push(mask_char(c, offset[ i % offset.size ]))
|
7
|
+
end
|
8
|
+
start_code = masked_code.pop
|
9
|
+
masked_code.unshift(start_code).join
|
10
|
+
end
|
11
|
+
|
12
|
+
def unmask_code(offset, masked_code)
|
13
|
+
masked_code = masked_code[1..-1] + masked_code[0]
|
14
|
+
masked_code.downcase.split("").each_with_index.inject([]) do |code, (c, i)|
|
15
|
+
code.push(un_mask_char(c, offset[ i % offset.size ]))
|
16
|
+
end.join
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_mask_offset(mask)
|
20
|
+
mask.split("").inject([]) do |offset,c|
|
21
|
+
[[*'a'..'z'], [*'A'..'Z'], [*'0'..'9']].each do |m|
|
22
|
+
if m.include?(c)
|
23
|
+
offset.push(m.find_index(c))
|
24
|
+
break
|
25
|
+
end
|
26
|
+
end
|
27
|
+
offset
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def mask_alphabet_include?(code)
|
32
|
+
code.split('').each do |c|
|
33
|
+
return false unless @mask_alphabet.include?(c)
|
34
|
+
end
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
def mask_char(char, offset)
|
39
|
+
if all_digits?(char) && char.size == 1
|
40
|
+
@mask_alphabet[(@mask_alphabet.find_index(@mask_alphabet[char.to_i]) + offset) % @mask_alphabet.size]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def un_mask_char(char, offset)
|
45
|
+
if mask_alphabet_include?(char)
|
46
|
+
(@mask_alphabet.find_index(char) - offset) % @mask_alphabet.size
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# not used
|
51
|
+
def convert_masked_code_typo(masked_code)
|
52
|
+
masked_code.gsub('1', 'l')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/lib/modulo.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# this is a modulo 17 Galois field
|
2
|
+
|
3
|
+
module Codecal
|
4
|
+
module Modulo
|
5
|
+
## module 7
|
6
|
+
@@MODULO_NUMBER = 7
|
7
|
+
@@MODULO_WEIGHT = [5,4,6,2,3,1,5,4,6,2,3,1]
|
8
|
+
## module 17
|
9
|
+
# @@MODULO_NUMBER = 17
|
10
|
+
# @@MODULO_WEIGHT = %w[01 06 02 12 04 07 08 14 16 11 15 05 13 10 09 03 01]
|
11
|
+
## module 11
|
12
|
+
# @@MODULO_NUMBER = 11
|
13
|
+
# @@MODULO_WEIGHT = %w[07 09 10 05 08 04 02 01 06 03 07 09 10 05 08 04 02 01]
|
14
|
+
## module 13
|
15
|
+
# @@MODULO_NUMBER = 13
|
16
|
+
# @@MODULO_WEIGHT = %w[3 8 4 2 1 7 10 5 9 11 12 6 3 8 4 2 1]
|
17
|
+
@@SEVENTEEN_SYMBOL = '0123456789abcdefg'
|
18
|
+
|
19
|
+
def simple_code_calculate(int_array)
|
20
|
+
code = int_array.reverse.each_with_index.inject(0) do |count, (i, index)|
|
21
|
+
count += i * ( index < @@MODULO_WEIGHT.size ?
|
22
|
+
@@MODULO_WEIGHT.reverse[index + 1].to_i :
|
23
|
+
( index + 1 ).times.inject(1) { |c| c *= 3 } % @@MODULO_NUMBER
|
24
|
+
)
|
25
|
+
end
|
26
|
+
symbol = convert_to_symbol(code % @@MODULO_NUMBER)
|
27
|
+
(int_array.join + symbol).to_i.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
# def simple_code_calculate(array)
|
31
|
+
# code = array.reverse.each_with_index.inject(0){|count, (i, index)| count += i*( index < 11 ? @@MODULO_WEIGHT.reverse[index + 1] : (index+1).times.inject(1) {|c| c *= 3} % 7 ) }
|
32
|
+
# return (array.join + ( code % 7 ).to_s).to_i.to_s
|
33
|
+
# end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def convert_to_symbol(number)
|
38
|
+
@@SEVENTEEN_SYMBOL[number]
|
39
|
+
end
|
40
|
+
|
41
|
+
def convert_to_number(symbol)
|
42
|
+
@@SEVENTEEN_SYMBOL.find_index(symbol)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Codecal
|
2
|
+
module Validation
|
3
|
+
def all_letters_or_digits?(str)
|
4
|
+
str[/[a-zA-Z0-9]+/] == str
|
5
|
+
end
|
6
|
+
|
7
|
+
def all_digits?(str)
|
8
|
+
str[/[0-9]+/] == str
|
9
|
+
end
|
10
|
+
|
11
|
+
def is_legal_mask?(mask)
|
12
|
+
return false if !mask.is_a?(String) || mask.size < 6 || !all_letters_or_digits?(mask)
|
13
|
+
return true
|
14
|
+
end
|
15
|
+
|
16
|
+
def is_legal_masked_code?(masked_code)
|
17
|
+
return false unless masked_code.is_a?(String) && masked_code.size > 5
|
18
|
+
return false unless mask_alphabet_include?(masked_code)
|
19
|
+
return true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: codecal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roger Fang
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -73,6 +73,7 @@ executables: []
|
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
|
+
- ".DS_Store"
|
76
77
|
- ".gitignore"
|
77
78
|
- ".rspec"
|
78
79
|
- ".ruby-version"
|
@@ -86,10 +87,11 @@ files:
|
|
86
87
|
- bin/console
|
87
88
|
- bin/setup
|
88
89
|
- codecal.gemspec
|
89
|
-
- lib/code.rb
|
90
90
|
- lib/codecal.rb
|
91
91
|
- lib/codecal/version.rb
|
92
|
-
- lib/
|
92
|
+
- lib/lib/mask.rb
|
93
|
+
- lib/lib/modulo.rb
|
94
|
+
- lib/lib/validation.rb
|
93
95
|
homepage: https://github.com/roger-fang-bct/codecal.git
|
94
96
|
licenses:
|
95
97
|
- MIT
|
data/lib/code.rb
DELETED