-
Notifications
You must be signed in to change notification settings - Fork 5
/
ccgen.go
130 lines (100 loc) · 2.81 KB
/
ccgen.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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
126
127
128
129
130
package ccgen
import (
"math/rand"
"strconv"
"time"
)
// CardType represents card number type to be generated
type CardType int
// Generate generates card number of a random card type
func Generate() string {
return getRandomCardType().Generate()
}
// Returns random card type
// @todo: consider other way to limit highest type
func getRandomCardType() CardType {
rand.Seed(time.Now().Unix())
randType := rand.Intn(int(Mir))
if randType == 0 {
randType++
}
return CardType(randType)
}
// Generate generates random card number of CardType
func (t CardType) Generate() string {
length := t.getRandomValidLength()
binNumber := t.getRandomCardPrefix()
return completeDigits(binNumber, length)
}
// GenerateOfLength generates card number of specified length
// If length is not valid, random among valid ones will be used
func (t CardType) GenerateOfLength(l int) string {
if !t.ValidLength(l) {
l = t.getRandomValidLength()
}
binNumber := t.getRandomCardPrefix()
return completeDigits(binNumber, l)
}
// ValidLength validates if specified card length is valid for the card type
func (t CardType) ValidLength(l int) bool {
for _, n := range cardLength[t] {
if n == l {
return true
}
}
return false
}
// Returns random card prefix among valid for the card type
func (t CardType) getRandomCardPrefix() string {
rand.Seed(time.Now().Unix())
return cardPrefix[t][rand.Intn(len(cardPrefix[t]))]
}
// Returns random card length among valid for the card type
func (t CardType) getRandomValidLength() int {
rand.Seed(time.Now().Unix())
return cardLength[t][rand.Intn(len(cardLength[t]))]
}
// ValidNumber validates card number for a prefix and Luhn algo
// @todo: add card prefix check
func (t CardType) ValidNumber(cnumber string) bool {
return checkLuhn(cnumber)
}
// Checks if the card number has valid check digit
func checkLuhn(cnumber string) bool {
if len(cnumber) < 12 || len(cnumber) > 19 {
return false
}
checkDigit := cnumber[len(cnumber)-1:]
return checkDigit == generateCheckDigit(cnumber[:len(cnumber)-1])
}
// generates the rest of the digits after the card prefix
// leaving the last position for the check digit
func completeDigits(bin string, l int) string {
rand.Seed(time.Now().Unix())
randomNumberLength := l - (len(bin) + 1)
for i := 0; i < randomNumberLength; i++ {
rand := rand.Intn(10)
bin += strconv.Itoa(rand)
}
checkDigit := generateCheckDigit(bin)
return bin + checkDigit
}
// Generates last digit according to Luhn algo
func generateCheckDigit(cnumber string) string {
sum := 0
for i := 0; i < len(cnumber); i++ {
digit, _ := strconv.Atoi((string(cnumber[i])))
if i%2 == 0 {
digit = digit * 2
if digit > 9 {
digit = (digit / 10) + (digit % 10)
}
}
sum += digit
}
mod := sum % 10
if mod == 0 {
return strconv.Itoa(0)
}
return strconv.Itoa(10 - mod)
}