Pad non-padded secrets. This lets us continue building on <= go1.8.
- Add tests for secrets using various padding methods. - Add a new method/test to append padding to non-padded secrets.
This commit is contained in:
4
hotp.go
4
hotp.go
@@ -88,9 +88,9 @@ func hotpFromURL(u *url.URL) (*HOTP, string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
key, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(secret)
|
||||
key, err := base32.StdEncoding.DecodeString(Pad(secret))
|
||||
if err != nil {
|
||||
// secret isn't base32 encoded
|
||||
// assume secret isn't base32 encoded
|
||||
key = []byte(secret)
|
||||
}
|
||||
otp := NewHOTP(key, counter, digits)
|
||||
|
||||
40
otp_test.go
40
otp_test.go
@@ -69,6 +69,46 @@ func TestURL(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// This test makes sure we can generate codes for padded and non-padded
|
||||
// entries
|
||||
func TestPaddedURL(t *testing.T) {
|
||||
var urlList = []string{
|
||||
"otpauth://hotp/?secret=ME",
|
||||
"otpauth://hotp/?secret=MEFR",
|
||||
"otpauth://hotp/?secret=MFRGG",
|
||||
"otpauth://hotp/?secret=MFRGGZA",
|
||||
"otpauth://hotp/?secret=a6mryljlbufszudtjdt42nh5by=======",
|
||||
"otpauth://hotp/?secret=a6mryljlbufszudtjdt42nh5by",
|
||||
"otpauth://hotp/?secret=a6mryljlbufszudtjdt42nh5by%3D%3D%3D%3D%3D%3D%3D",
|
||||
}
|
||||
var codeList = []string{
|
||||
"413198",
|
||||
"770938",
|
||||
"670717",
|
||||
"402378",
|
||||
"069864",
|
||||
"069864",
|
||||
"069864",
|
||||
}
|
||||
|
||||
for i := range urlList {
|
||||
if o, id, err := FromURL(urlList[i]); err != nil {
|
||||
fmt.Println("hotp: URL should have parsed successfully")
|
||||
fmt.Printf("\turl was: %s\n", urlList[i])
|
||||
t.FailNow()
|
||||
fmt.Printf("\t%s, %s\n", o.OTP(), id)
|
||||
} else {
|
||||
code2 := o.OTP()
|
||||
if code2 != codeList[i] {
|
||||
fmt.Printf("hotp: mismatched OTPs\n")
|
||||
fmt.Printf("\texpected: %s\n", codeList[i])
|
||||
fmt.Printf("\t actual: %s\n", code2)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This test attempts a variety of invalid urls against the parser
|
||||
// to ensure they fail.
|
||||
func TestBadURL(t *testing.T) {
|
||||
|
||||
4
totp.go
4
totp.go
@@ -150,9 +150,9 @@ func totpFromURL(u *url.URL) (*TOTP, string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
key, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(secret)
|
||||
key, err := base32.StdEncoding.DecodeString(Pad(secret))
|
||||
if err != nil {
|
||||
// secret isn't base32 encoded
|
||||
// assume secret isn't base32 encoded
|
||||
key = []byte(secret)
|
||||
}
|
||||
otp := NewTOTP(key, 0, period, digits, algo)
|
||||
|
||||
16
util.go
Normal file
16
util.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package twofactor
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Pad calculates the number of '='s to add to our encoded string
|
||||
// to make base32.StdEncoding.DecodeString happy
|
||||
func Pad(s string) string {
|
||||
if !strings.HasSuffix(s, "=") && len(s)%8 != 0 {
|
||||
for len(s)%8 != 0 {
|
||||
s += "="
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
53
util_test.go
Normal file
53
util_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package twofactor
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const letters = "1234567890!@#$%^&*()abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
func randString() string {
|
||||
b := make([]byte, rand.Intn(len(letters)))
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
return base32.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
func TestPadding(t *testing.T) {
|
||||
for i := 0; i < 300; i++ {
|
||||
b := randString()
|
||||
origEncoding := string(b)
|
||||
modEncoding := strings.Replace(string(b), "=", "", -1)
|
||||
str, err := base32.StdEncoding.DecodeString(origEncoding)
|
||||
if err != nil {
|
||||
fmt.Println("Can't decode: ", string(b))
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
paddedEncoding := Pad(modEncoding)
|
||||
if origEncoding != paddedEncoding {
|
||||
fmt.Println("Padding failed:")
|
||||
fmt.Printf("Expected: '%s'", origEncoding)
|
||||
fmt.Printf("Got: '%s'", paddedEncoding)
|
||||
t.FailNow()
|
||||
} else {
|
||||
mstr, err := base32.StdEncoding.DecodeString(paddedEncoding)
|
||||
if err != nil {
|
||||
fmt.Println("Can't decode: ", paddedEncoding)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if string(mstr) != string(str) {
|
||||
fmt.Println("Re-padding failed:")
|
||||
fmt.Printf("Expected: '%s'", str)
|
||||
fmt.Printf("Got: '%s'", mstr)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user