127 lines
3.4 KiB
Go
127 lines
3.4 KiB
Go
package twofactor
|
|
|
|
import (
|
|
"io"
|
|
"testing"
|
|
)
|
|
|
|
func TestHOTPString(t *testing.T) {
|
|
hotp := NewHOTP(nil, 0, 6)
|
|
hotpString := otpString(hotp)
|
|
if hotpString != "OATH-HOTP, 6" {
|
|
t.Fatal("twofactor: invalid OTP string")
|
|
}
|
|
}
|
|
|
|
// This test generates a new OTP, outputs the URL for that OTP,
|
|
// and attempts to parse that URL. It verifies that the two OTPs
|
|
// are the same, and that they produce the same output.
|
|
func TestURL(t *testing.T) {
|
|
var ident = "testuser@foo"
|
|
otp := NewHOTP(testKey, 0, 6)
|
|
url := otp.URL("testuser@foo")
|
|
otp2, id, err := FromURL(url)
|
|
switch {
|
|
case err != nil:
|
|
t.Fatal("hotp: failed to parse HOTP URL\n")
|
|
case id != ident:
|
|
t.Logf("hotp: bad label\n")
|
|
t.Logf("\texpected: %s\n", ident)
|
|
t.Fatalf("\t actual: %s\n", id)
|
|
case otp2.Counter() != otp.Counter():
|
|
t.Logf("hotp: OTP counters aren't synced\n")
|
|
t.Logf("\toriginal: %d\n", otp.Counter())
|
|
t.Fatalf("\t second: %d\n", otp2.Counter())
|
|
}
|
|
|
|
code1 := otp.OTP()
|
|
code2 := otp2.OTP()
|
|
if code1 != code2 {
|
|
t.Logf("hotp: mismatched OTPs\n")
|
|
t.Logf("\texpected: %s\n", code1)
|
|
t.Fatalf("\t actual: %s\n", code2)
|
|
}
|
|
|
|
// There's not much we can do test the QR code, except to
|
|
// ensure it doesn't fail.
|
|
_, err = otp.QR(ident)
|
|
if err != nil {
|
|
t.Fatalf("hotp: failed to generate QR code PNG (%v)\n", err)
|
|
}
|
|
|
|
// This should fail because the maximum size of an alphanumeric
|
|
// QR code with the lowest-level of error correction should
|
|
// max out at 4296 bytes. 8k may be a bit overkill... but it
|
|
// gets the job done. The value is read from the PRNG to
|
|
// increase the likelihood that the returned data is
|
|
// uncompressible.
|
|
var tooBigIdent = make([]byte, 8192)
|
|
_, err = io.ReadFull(PRNG, tooBigIdent)
|
|
if err != nil {
|
|
t.Fatalf("hotp: failed to read identity (%v)\n", err)
|
|
} else if _, err = otp.QR(string(tooBigIdent)); err == nil {
|
|
t.Fatal("hotp: QR code should fail to encode oversized URL")
|
|
}
|
|
}
|
|
|
|
// 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 {
|
|
t.Log("hotp: URL should have parsed successfully (id=", id, ")")
|
|
t.Logf("\turl was: %s\n", urlList[i])
|
|
t.Fatalf("\t%s, %s\n", o.OTP(), id)
|
|
} else {
|
|
code2 := o.OTP()
|
|
if code2 != codeList[i] {
|
|
t.Logf("hotp: mismatched OTPs\n")
|
|
t.Logf("\texpected: %s\n", codeList[i])
|
|
t.Fatalf("\t actual: %s\n", code2)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// This test attempts a variety of invalid urls against the parser
|
|
// to ensure they fail.
|
|
func TestBadURL(t *testing.T) {
|
|
var urlList = []string{
|
|
"http://google.com",
|
|
"",
|
|
"-",
|
|
"foo",
|
|
"otpauth:/foo/bar/baz",
|
|
"://",
|
|
"otpauth://hotp/?digits=",
|
|
"otpauth://hotp/?secret=MFRGGZDF&digits=ABCD",
|
|
"otpauth://hotp/?secret=MFRGGZDF&counter=ABCD",
|
|
}
|
|
|
|
for i := range urlList {
|
|
if _, _, err := FromURL(urlList[i]); err == nil {
|
|
t.Log("hotp: URL should not have parsed successfully")
|
|
t.Fatalf("\turl was: %s\n", urlList[i])
|
|
}
|
|
}
|
|
}
|