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 {
|
if err != nil {
|
||||||
// secret isn't base32 encoded
|
// assume secret isn't base32 encoded
|
||||||
key = []byte(secret)
|
key = []byte(secret)
|
||||||
}
|
}
|
||||||
otp := NewHOTP(key, counter, digits)
|
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
|
// This test attempts a variety of invalid urls against the parser
|
||||||
// to ensure they fail.
|
// to ensure they fail.
|
||||||
func TestBadURL(t *testing.T) {
|
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 {
|
if err != nil {
|
||||||
// secret isn't base32 encoded
|
// assume secret isn't base32 encoded
|
||||||
key = []byte(secret)
|
key = []byte(secret)
|
||||||
}
|
}
|
||||||
otp := NewTOTP(key, 0, period, digits, algo)
|
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