-
Notifications
You must be signed in to change notification settings - Fork 0
/
authenticator.go
105 lines (91 loc) · 2.75 KB
/
authenticator.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
package googleauthenticator
import (
"crypto/rand"
"encoding/base32"
"regexp"
"strings"
"time"
"github.com/pquerna/otp"
"github.com/pquerna/otp/totp"
)
type Authenticator struct {
key *otp.Key
}
func NewAuthenticator(issuer string, accountName string, formattedKey string) *Authenticator {
rx := regexp.MustCompile(`\W+`)
secret := []byte(rx.ReplaceAllString(formattedKey, ""))
ret, _ := totp.Generate(totp.GenerateOpts{
Issuer: issuer,
AccountName: accountName,
SecretSize: uint(len(secret)),
Secret: secret,
})
return &Authenticator{key: ret}
}
func (a *Authenticator) VerifyToken(passcode string) bool {
rv, _ := totp.ValidateCustom(
passcode,
a.key.Secret(),
time.Now().UTC(),
totp.ValidateOpts{
Period: 30,
Skew: 1,
Digits: otp.DigitsSix,
Algorithm: otp.AlgorithmSHA1,
},
)
return rv
}
func (a *Authenticator) GenerateToken() (passcode string) {
passcode, _ = totp.GenerateCode(a.key.Secret(), time.Now().UTC())
return
}
func (a *Authenticator) GenerateTotpUri() string {
return a.key.URL()
}
func GenerateKey() (formattedKey string) {
formattedKey = encodeGoogleAuthKey(generateOtpKey())
return
}
// Generate a key
func generateOtpKey() []byte {
// 20 cryptographically random binary bytes (160-bit key)
key := make([]byte, 20)
_, _ = rand.Read(key)
return key
}
// Text-encode the key as base32 (in the style of Google Authenticator - same as Facebook, Microsoft, etc)
func encodeGoogleAuthKey(bin []byte) string {
// 32 ascii characters without trailing '='s
rx := regexp.MustCompile(`=`)
base32 := rx.ReplaceAllString(base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(bin), "")
base32 = strings.ToLower(base32)
// lowercase with a space every 4 characters
rx = regexp.MustCompile(`(\w{4})`)
key := strings.TrimSpace(rx.ReplaceAllString(base32, "$1 "))
return key
}
// Binary-decode the key from base32 (Google Authenticator, FB, M$, etc)
// func decodeGoogleAuthKey(key string) []byte {
// // decode base32 google auth key to binary
// rx := regexp.MustCompile(`\W+`)
// unformatted := strings.ToUpper(rx.ReplaceAllString(key, ""))
// bin, _ := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(unformatted)
// return bin
// }
// func GenerateTotpUri(secret, accountName, issuer string) string {
// // Full OTPAUTH URI spec as explained at
// // https://github.com/google/google-authenticator/wiki/Key-Uri-Format
// u := url.URL{}
// v := url.Values{}
// u.Scheme = "otpauth"
// u.Host = "totp"
// u.Path = fmt.Sprintf("%s:%s", issuer, accountName)
// v.Add("secret", secret)
// v.Add("issuer", issuer)
// v.Add("algorithm", "SHA1")
// v.Add("digits", strconv.Itoa(6))
// v.Add("period", strconv.Itoa(30))
// u.RawQuery = v.Encode()
// return u.String()
// }