package models import ( "image" "net/url" "strconv" "time" "github.com/pquerna/otp" ) // TOTPConfiguration represents a users TOTP configuration row in the database. type TOTPConfiguration struct { ID int `db:"id" json:"-"` CreatedAt time.Time `db:"created_at" json:"-"` LastUsedAt *time.Time `db:"last_used_at" json:"-"` Username string `db:"username" json:"-"` Issuer string `db:"issuer" json:"-"` Algorithm string `db:"algorithm" json:"-"` Digits uint `db:"digits" json:"digits"` Period uint `db:"period" json:"period"` Secret []byte `db:"secret" json:"-"` } // URI shows the configuration in the URI representation. func (c TOTPConfiguration) URI() (uri string) { v := url.Values{} v.Set("secret", string(c.Secret)) v.Set("issuer", c.Issuer) v.Set("period", strconv.FormatUint(uint64(c.Period), 10)) v.Set("algorithm", c.Algorithm) v.Set("digits", strconv.Itoa(int(c.Digits))) u := url.URL{ Scheme: "otpauth", Host: "totp", Path: "/" + c.Issuer + ":" + c.Username, RawQuery: v.Encode(), } return u.String() } // UpdateSignInInfo adjusts the values of the TOTPConfiguration after a sign in. func (c *TOTPConfiguration) UpdateSignInInfo(now time.Time) { c.LastUsedAt = &now } // Key returns the *otp.Key using TOTPConfiguration.URI with otp.NewKeyFromURL. func (c TOTPConfiguration) Key() (key *otp.Key, err error) { return otp.NewKeyFromURL(c.URI()) } // Image returns the image.Image of the TOTPConfiguration using the Image func from the return of TOTPConfiguration.Key. func (c TOTPConfiguration) Image(width, height int) (img image.Image, err error) { var key *otp.Key if key, err = c.Key(); err != nil { return nil, err } return key.Image(width, height) }