// Copyright (C) 2019 Marius Schellenberger package otp import ( "bytes" "encoding/base64" "errors" "github.com/pquerna/otp" "github.com/pquerna/otp/totp" "html/template" "image/png" ) const size = 200 func base64Image(key *otp.Key) (data template.URL, err error) { var buf bytes.Buffer img, err := key.Image(size, size) if err != nil { err = errors.New("otp: " + err.Error()) return } err = png.Encode(&buf, img) if err != nil { err = errors.New("otp: " + err.Error()) return } data = template.URL("data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes())) return } type Request struct { Username string Image template.URL Secret string URL string } func New(username string) (req Request, err error) { key, err := totp.Generate(totp.GenerateOpts{ Issuer: "gowiki", AccountName: username, }) if err != nil { return } data, err := base64Image(key) if err != nil { return } return Request{ Username: username, Image: data, Secret: key.Secret(), URL: key.URL(), }, nil } func Validate(pin, secret string) bool { if secret == "" { return true } return totp.Validate(pin, secret) } func ImageSecretFromURL(url string) (data template.URL, secret string, err error) { key, err := otp.NewKeyFromURL(url) if err != nil { err = errors.New("otp: " + err.Error()) return } secret = key.Secret() data, err = base64Image(key) return }