From d51be3e6585c307900567c305150ebe9d57b95b8 Mon Sep 17 00:00:00 2001 From: Oleg Kovalov Date: Sat, 2 Dec 2023 13:06:43 +0100 Subject: [PATCH] Drop Digits type --- example_test.go | 4 ++-- hotp.go | 12 +++++++----- hotp_test.go | 18 +++++++++--------- otp.go | 17 ++++------------- totp.go | 9 ++++----- totp_test.go | 22 +++++++++++----------- 6 files changed, 37 insertions(+), 45 deletions(-) diff --git a/example_test.go b/example_test.go index 4653055..71b73f3 100644 --- a/example_test.go +++ b/example_test.go @@ -10,7 +10,7 @@ import ( func ExampleHOTP() { hotp, err := otp.NewHOTP(otp.HOTPConfig{ Algo: otp.AlgorithmSHA1, - Digits: otp.Digits(10), + Digits: 10, Issuer: "cristalhq", }) checkErr(err) @@ -31,7 +31,7 @@ func ExampleHOTP() { func ExampleTOTP() { totp, err := otp.NewTOTP(otp.TOTPConfig{ Algo: otp.AlgorithmSHA1, - Digits: otp.Digits(10), + Digits: 10, Issuer: "cristalhq", Period: 30, Skew: 2, diff --git a/hotp.go b/hotp.go index e48de9d..d4d6e63 100644 --- a/hotp.go +++ b/hotp.go @@ -4,6 +4,7 @@ import ( "crypto/hmac" "crypto/subtle" "encoding/binary" + "fmt" "math" "net/url" ) @@ -15,7 +16,7 @@ type HOTP struct { type HOTPConfig struct { Algo Algorithm - Digits Digits + Digits uint Issuer string } @@ -44,7 +45,7 @@ func NewHOTP(cfg HOTPConfig) (*HOTP, error) { func (h *HOTP) GenerateURL(account string, secret []byte) string { v := url.Values{} v.Set("algorithm", h.cfg.Algo.String()) - v.Set("digits", h.cfg.Digits.String()) + v.Set("digits", atoi(h.cfg.Digits)) v.Set("issuer", h.cfg.Issuer) v.Set("secret", b32Enc(secret)) @@ -79,13 +80,14 @@ func (h *HOTP) GenerateCode(counter uint64, secret string) (string, error) { value |= int64(sum[offset+2]&0xff) << 8 value |= int64(sum[offset+3] & 0xff) - length := int64(math.Pow10(h.cfg.Digits.Length())) - return h.cfg.Digits.Format(int(value % length)), nil + length := int64(math.Pow10(int(h.cfg.Digits))) + code := fmt.Sprintf(fmt.Sprintf("%%0%dd", h.cfg.Digits), value%length) + return code, nil } // Validate the given passcode, counter and secret. func (h *HOTP) Validate(passcode string, counter uint64, secret string) error { - if len(passcode) != h.cfg.Digits.Length() { + if len(passcode) != int(h.cfg.Digits) { return ErrCodeLengthMismatch } diff --git a/hotp_test.go b/hotp_test.go index b86bb5d..f9691f2 100644 --- a/hotp_test.go +++ b/hotp_test.go @@ -27,7 +27,7 @@ func TestHOTP(t *testing.T) { for _, tc := range hotpRFCTestCases { hotp, err := NewHOTP(HOTPConfig{ Algo: tc.algo, - Digits: Digits(6), + Digits: 6, Issuer: "cristalhq", }) mustOk(t, err) @@ -44,28 +44,28 @@ func TestHOTP(t *testing.T) { func TestNewHOTP(t *testing.T) { _, err := NewHOTP(HOTPConfig{ Algo: 0, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", }) mustEqual(t, err, ErrUnsupportedAlgorithm) _, err = NewHOTP(HOTPConfig{ Algo: 100, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", }) mustEqual(t, err, ErrUnsupportedAlgorithm) _, err = NewHOTP(HOTPConfig{ Algo: 1, - Digits: Digits(0), + Digits: 0, Issuer: "cristalhq", }) mustEqual(t, err, ErrNoDigits) _, err = NewHOTP(HOTPConfig{ Algo: 1, - Digits: Digits(8), + Digits: 8, Issuer: "", }) mustEqual(t, err, ErrEmptyIssuer) @@ -74,7 +74,7 @@ func TestNewHOTP(t *testing.T) { func TestHOTPGenerateURL(t *testing.T) { hotp, err := NewHOTP(HOTPConfig{ Algo: AlgorithmSHA1, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", }) mustOk(t, err) @@ -89,7 +89,7 @@ func TestHOTPGenerateURL(t *testing.T) { func BenchmarkHOTP_GenerateURL(b *testing.B) { hotp, err := NewHOTP(HOTPConfig{ Algo: AlgorithmSHA1, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", }) mustOk(b, err) @@ -111,7 +111,7 @@ func BenchmarkHOTP_GenerateURL(b *testing.B) { func BenchmarkHOTP_GenerateCode(b *testing.B) { hotp, err := NewHOTP(HOTPConfig{ Algo: AlgorithmSHA1, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", }) mustOk(b, err) @@ -130,7 +130,7 @@ func BenchmarkHOTP_GenerateCode(b *testing.B) { func BenchmarkHOTP_Validate(b *testing.B) { hotp, err := NewHOTP(HOTPConfig{ Algo: AlgorithmSHA1, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", }) mustOk(b, err) diff --git a/otp.go b/otp.go index eff1fac..329c269 100644 --- a/otp.go +++ b/otp.go @@ -65,19 +65,6 @@ func (a Algorithm) Hash() hash.Hash { } } -// Digits is the number of digits in the OTP passcode. -type Digits uint - -func (d Digits) String() string { return fmt.Sprintf("%d", d) } - -// Length of the passcode. -func (d Digits) Length() int { return int(d) } - -// Format the number to a digit format (zero-filled upto digits size). -func (d Digits) Format(n int) string { - return fmt.Sprintf(fmt.Sprintf("%%0%dd", d), n) -} - // Key represents an HTOP or TOTP key. type Key struct { url *url.URL @@ -147,3 +134,7 @@ func b32Dec(s string) ([]byte, error) { func b32Enc(src []byte) string { return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(src) } + +func atoi(v uint) string { + return strconv.FormatUint(uint64(v), 10) +} diff --git a/totp.go b/totp.go index 285cc46..f48da48 100644 --- a/totp.go +++ b/totp.go @@ -3,7 +3,6 @@ package otp import ( "math" "net/url" - "strconv" "time" ) @@ -15,7 +14,7 @@ type TOTP struct { type TOTPConfig struct { Algo Algorithm - Digits Digits + Digits uint Issuer string Period uint Skew uint @@ -62,10 +61,10 @@ func NewTOTP(cfg TOTPConfig) (*TOTP, error) { func (t *TOTP) GenerateURL(account string, secret []byte) string { v := url.Values{} v.Set("algorithm", t.cfg.Algo.String()) - v.Set("digits", t.cfg.Digits.String()) + v.Set("digits", atoi(t.cfg.Digits)) v.Set("issuer", t.cfg.Issuer) v.Set("secret", b32Enc(secret)) - v.Set("period", strconv.FormatUint(uint64(t.cfg.Period), 10)) + v.Set("period", atoi(t.cfg.Period)) u := url.URL{ Scheme: "otpauth", @@ -88,7 +87,7 @@ func (t *TOTP) GenerateCode(secret string, at time.Time) (string, error) { // Validate the given passcode, time and secret. func (t *TOTP) Validate(passcode string, at time.Time, secret string) error { - if len(passcode) != t.cfg.Digits.Length() { + if len(passcode) != int(t.cfg.Digits) { return ErrCodeLengthMismatch } diff --git a/totp_test.go b/totp_test.go index b9795e2..c31aa3d 100644 --- a/totp_test.go +++ b/totp_test.go @@ -36,7 +36,7 @@ func TestTOTP(t *testing.T) { for _, tc := range totpRFCTestCases { totp, err := NewTOTP(TOTPConfig{ Algo: tc.algo, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", Period: 30, Skew: 1, @@ -56,7 +56,7 @@ func TestTOTP(t *testing.T) { func TestNewTOTP(t *testing.T) { _, err := NewTOTP(TOTPConfig{ Algo: 0, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", Period: 30, Skew: 1, @@ -65,7 +65,7 @@ func TestNewTOTP(t *testing.T) { _, err = NewTOTP(TOTPConfig{ Algo: 100, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", Period: 30, Skew: 1, @@ -74,7 +74,7 @@ func TestNewTOTP(t *testing.T) { _, err = NewTOTP(TOTPConfig{ Algo: 1, - Digits: Digits(0), + Digits: 0, Issuer: "cristalhq", Period: 30, Skew: 1, @@ -83,7 +83,7 @@ func TestNewTOTP(t *testing.T) { _, err = NewTOTP(TOTPConfig{ Algo: 1, - Digits: Digits(8), + Digits: 8, Issuer: "", Period: 30, Skew: 1, @@ -92,7 +92,7 @@ func TestNewTOTP(t *testing.T) { _, err = NewTOTP(TOTPConfig{ Algo: 1, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", Period: 0, Skew: 1, @@ -101,7 +101,7 @@ func TestNewTOTP(t *testing.T) { _, err = NewTOTP(TOTPConfig{ Algo: 1, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", Period: 30, Skew: 0, @@ -112,7 +112,7 @@ func TestNewTOTP(t *testing.T) { func TestTOTPGenerateURL(t *testing.T) { totp, err := NewTOTP(TOTPConfig{ Algo: AlgorithmSHA1, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", Period: 30, Skew: 1, @@ -129,7 +129,7 @@ func TestTOTPGenerateURL(t *testing.T) { func BenchmarkTOTP_GenerateURL(b *testing.B) { totp, err := NewTOTP(TOTPConfig{ Algo: AlgorithmSHA1, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", Period: 30, Skew: 1, @@ -153,7 +153,7 @@ func BenchmarkTOTP_GenerateURL(b *testing.B) { func BenchmarkTOTP_GenerateCode(b *testing.B) { totp, err := NewTOTP(TOTPConfig{ Algo: AlgorithmSHA1, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", Period: 30, Skew: 1, @@ -176,7 +176,7 @@ func BenchmarkTOTP_GenerateCode(b *testing.B) { func BenchmarkTOTP_Validate(b *testing.B) { totp, err := NewTOTP(TOTPConfig{ Algo: AlgorithmSHA1, - Digits: Digits(8), + Digits: 8, Issuer: "cristalhq", Period: 30, Skew: 1,