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
| package google_auth
import ( "bytes" "crypto/hmac" "crypto/sha1" "encoding/base32" "encoding/binary" "fmt" "net/url" "strings" "time" )
var GlobalGoogleAuth *GoogleAuth
type GoogleAuth struct { }
func NewGoogleAuth() *GoogleAuth { return &GoogleAuth{} }
func InitGoogleAuth() { GlobalGoogleAuth = NewGoogleAuth() }
func (this *GoogleAuth) un() int64 { return time.Now().UnixNano() / 1000 / 30 }
func (this *GoogleAuth) hmacSha1(key, data []byte) []byte { h := hmac.New(sha1.New, key) if total := len(data); total > 0 { h.Write(data) } return h.Sum(nil) }
func (this *GoogleAuth) base32encode(src []byte) string { return base32.StdEncoding.EncodeToString(src) }
func (this *GoogleAuth) base32decode(s string) ([]byte, error) { return base32.StdEncoding.DecodeString(s) }
func (this *GoogleAuth) toBytes(value int64) []byte { var result []byte mask := int64(0xFF) shifts := [8]uint16{56, 48, 40, 32, 24, 16, 8, 0} for _, shift := range shifts { result = append(result, byte((value>>shift)&mask)) } return result }
func (this *GoogleAuth) toUint32(bts []byte) uint32 { return (uint32(bts[0]) << 24) + (uint32(bts[1]) << 16) + (uint32(bts[2]) << 8) + uint32(bts[3]) }
func (this *GoogleAuth) oneTimePassword(key []byte, data []byte) uint32 { hash := this.hmacSha1(key, data) offset := hash[len(hash)-1] & 0x0F hashParts := hash[offset : offset+4] hashParts[0] = hashParts[0] & 0x7F number := this.toUint32(hashParts) return number % 1000000 }
func (this *GoogleAuth) GetSecret() string { var buf bytes.Buffer binary.Write(&buf, binary.BigEndian, this.un()) return strings.ToUpper(this.base32encode(this.hmacSha1(buf.Bytes(), nil))) }
func (this *GoogleAuth) GetCode(secret string) (string, error) { secretUpper := strings.ToUpper(secret) secretKey, err := this.base32decode(secretUpper) if err != nil { return "", err } number := this.oneTimePassword(secretKey, this.toBytes(time.Now().Unix()/30)) return fmt.Sprintf("%06d", number), nil }
func (this *GoogleAuth) GetQrcode(user, secret string) string { return fmt.Sprintf("otpauth://totp/%s?secret=%s", user, secret) }
func (this *GoogleAuth) GetQrcodeUrl(user, secret string) string { qrcode := this.GetQrcode(user, secret) width := "200" height := "200" data := url.Values{} data.Set("data", qrcode) return "https://api.qrserver.com/v1/create-qr-code/?" + data.Encode() + "&size=" + width + "x" + height + "&ecc=M" }
func (this *GoogleAuth) VerifyCode(secret, code string) (bool, error) { _code, err := this.GetCode(secret) fmt.Println(_code, code, err) if err != nil { return false, err } return _code == code, nil }
|