File: otp_test.go

package info (click to toggle)
golang-github-gokyle-twofactor 1.0.1-1.1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 120 kB
  • sloc: makefile: 2
file content (134 lines) | stat: -rw-r--r-- 3,691 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package twofactor

import "fmt"
import "io"
import "testing"

func TestHOTPString(t *testing.T) {
	hotp := NewHOTP(nil, 0, 6)
	hotpString := otpString(hotp)
	if hotpString != "OATH-HOTP, 6" {
		fmt.Println("twofactor: invalid OTP string")
		t.FailNow()
	}
}

// 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)
	if err != nil {
		fmt.Printf("hotp: failed to parse HOTP URL\n")
		t.FailNow()
	} else if id != ident {
		fmt.Printf("hotp: bad label\n")
		fmt.Printf("\texpected: %s\n", ident)
		fmt.Printf("\t  actual: %s\n", id)
		t.FailNow()
	} else if otp2.Counter() != otp.Counter() {
		fmt.Printf("hotp: OTP counters aren't synced\n")
		fmt.Printf("\toriginal: %d\n", otp.Counter())
		fmt.Printf("\t  second: %d\n", otp2.Counter())
		t.FailNow()
	}

	code1 := otp.OTP()
	code2 := otp2.OTP()
	if code1 != code2 {
		fmt.Printf("hotp: mismatched OTPs\n")
		fmt.Printf("\texpected: %s\n", code1)
		fmt.Printf("\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 {
		fmt.Printf("hotp: failed to generate QR code PNG (%v)\n", err)
		t.FailNow()
	}

	// 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 {
		fmt.Printf("hotp: failed to read identity (%v)\n", err)
		t.FailNow()
	} else if _, err = otp.QR(string(tooBigIdent)); err == nil {
		fmt.Println("hotp: QR code should fail to encode oversized URL")
		t.FailNow()
	}
}

// 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) {
	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 {
			fmt.Println("hotp: URL should not have parsed successfully")
			fmt.Printf("\turl was: %s\n", urlList[i])
			t.FailNow()
		}
	}
}