2021-12-01 19:11:29 +07:00
|
|
|
package models
|
|
|
|
|
|
|
|
import (
|
2022-03-02 14:50:36 +07:00
|
|
|
"image"
|
2021-12-01 19:11:29 +07:00
|
|
|
"net/url"
|
|
|
|
"strconv"
|
2022-03-03 18:20:43 +07:00
|
|
|
"time"
|
2022-03-02 14:50:36 +07:00
|
|
|
|
|
|
|
"github.com/pquerna/otp"
|
2021-12-01 19:11:29 +07:00
|
|
|
)
|
|
|
|
|
|
|
|
// TOTPConfiguration represents a users TOTP configuration row in the database.
|
|
|
|
type TOTPConfiguration struct {
|
2022-03-03 18:20:43 +07:00
|
|
|
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:"-"`
|
2021-12-01 19:11:29 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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()
|
|
|
|
}
|
2022-03-02 14:50:36 +07:00
|
|
|
|
2022-03-03 18:20:43 +07:00
|
|
|
// UpdateSignInInfo adjusts the values of the TOTPConfiguration after a sign in.
|
|
|
|
func (c *TOTPConfiguration) UpdateSignInInfo(now time.Time) {
|
|
|
|
c.LastUsedAt = &now
|
|
|
|
}
|
|
|
|
|
2022-03-02 14:50:36 +07:00
|
|
|
// 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)
|
|
|
|
}
|