diff --git a/otp.go b/otp.go index 02b08f3..d66823d 100644 --- a/otp.go +++ b/otp.go @@ -46,6 +46,9 @@ var ErrGenerateMissingIssuer = errors.New("Issuer must be set") // When generating a Key, the Account Name must be set. var ErrGenerateMissingAccountName = errors.New("AccountName must be set") +// When regenerating a Key, the Secret must be set. +var ErrRegenerateMissingSecret = errors.New("Secret must be set") + // Key represents an TOTP or HTOP key. type Key struct { orig string @@ -55,8 +58,8 @@ type Key struct { // NewKeyFromURL creates a new Key from an TOTP or HOTP url. // // The URL format is documented here: -// https://github.com/google/google-authenticator/wiki/Key-Uri-Format // +// https://github.com/google/google-authenticator/wiki/Key-Uri-Format func NewKeyFromURL(orig string) (*Key, error) { s := strings.TrimSpace(orig) diff --git a/totp/totp.go b/totp/totp.go index a2fb7d5..76f32c8 100644 --- a/totp/totp.go +++ b/totp/totp.go @@ -18,10 +18,11 @@ package totp import ( + "io" + "github.com/pquerna/otp" "github.com/pquerna/otp/hotp" "github.com/pquerna/otp/internal" - "io" "crypto/rand" "encoding/base32" @@ -205,3 +206,17 @@ func Generate(opts GenerateOpts) (*otp.Key, error) { return otp.NewKeyFromURL(u.String()) } + +// Restores a key from a secret opts.Secret must be set +func Regenerate(opts GenerateOpts) (*otp.Key, error) { + if opts.SecretSize == 0 { + return nil, otp.ErrRegenerateMissingSecret + } + secret := make([]byte, base32.StdEncoding.DecodedLen(len(opts.Secret))) + _, err := base32.StdEncoding.Decode(secret, opts.Secret) + if err != nil { + return nil, err + } + opts.Secret = secret + return Generate(opts) +}