github.com/greenpau/go-identity@v1.1.6/pkg/qr/qr_test.go (about) 1 // Copyright 2020 Paul Greenberg greenpau@outlook.com 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package qr 16 17 import ( 18 "github.com/greenpau/go-identity/internal/tests" 19 // "github.com/greenpau/go-identity/pkg/errors" 20 "fmt" 21 "testing" 22 ) 23 24 func TestNewCode(t *testing.T) { 25 testcases := []struct { 26 name string 27 code *Code 28 want map[string]interface{} 29 shouldErr bool 30 err error 31 }{ 32 { 33 name: "valid totp app token code with sha1", 34 code: &Code{ 35 Secret: "foobar", 36 Type: "totp", 37 Label: "app token", 38 Period: 30, 39 Algorithm: "sha1", 40 Issuer: "Self", 41 Digits: 6, 42 }, 43 want: map[string]interface{}{ 44 "code": "otpauth://totp/app+token?secret=MZXW6YTBOI&issuer=Self&algorithm=sha1&digits=6&period=30", 45 "encoded": "b3RwYXV0aDovL3RvdHAvYXBwK3Rva2VuP3NlY3JldD1NWlhXNllUQk9JJmlzc3Vlcj1TZWxmJmFsZ29yaXRobT1zaGExJmRpZ2l0cz02JnBlcmlvZD0zMA==", 46 }, 47 }, 48 { 49 name: "valid hotp app token code with sha1", 50 code: &Code{ 51 Secret: "foobar", 52 Type: "hotp", 53 Label: "app token", 54 Algorithm: "sha1", 55 Issuer: "Self", 56 Counter: 100, 57 }, 58 want: map[string]interface{}{ 59 "code": "otpauth://hotp/app+token?secret=MZXW6YTBOI&issuer=Self&algorithm=sha1&digits=6&counter=100&period=30", 60 "encoded": "b3RwYXV0aDovL2hvdHAvYXBwK3Rva2VuP3NlY3JldD1NWlhXNllUQk9JJmlzc3Vlcj1TZWxmJmFsZ29yaXRobT1zaGExJmRpZ2l0cz02JmNvdW50ZXI9MTAwJnBlcmlvZD0zMA==", 61 }, 62 }, 63 { 64 name: "valid totp app token code with defaults", 65 code: &Code{ 66 Secret: "foobar", 67 Type: "totp", 68 Label: "app token", 69 Issuer: "Self", 70 }, 71 want: map[string]interface{}{ 72 "code": "otpauth://totp/app+token?secret=MZXW6YTBOI&issuer=Self&digits=6&period=30", 73 "encoded": "b3RwYXV0aDovL3RvdHAvYXBwK3Rva2VuP3NlY3JldD1NWlhXNllUQk9JJmlzc3Vlcj1TZWxmJmRpZ2l0cz02JnBlcmlvZD0zMA==", 74 }, 75 }, 76 { 77 name: "invalid token code without type", 78 code: &Code{ 79 Label: "app token", 80 Secret: "foobar", 81 }, 82 shouldErr: true, 83 err: fmt.Errorf("token type must be either totp or hotp"), 84 }, 85 { 86 name: "invalid token code without label", 87 code: &Code{ 88 Type: "totp", 89 }, 90 shouldErr: true, 91 err: fmt.Errorf("token label must be set"), 92 }, 93 { 94 name: "invalid token code without secret", 95 code: &Code{ 96 Type: "totp", 97 Label: "app token", 98 }, 99 shouldErr: true, 100 err: fmt.Errorf("token secret must be set"), 101 }, 102 { 103 name: "invalid token code with secret too short", 104 code: &Code{ 105 Type: "totp", 106 Label: "app token", 107 Secret: "12345", 108 }, 109 shouldErr: true, 110 err: fmt.Errorf("token secret must be at least 6 characters long"), 111 }, 112 { 113 name: "invalid token code with invalid digits value", 114 code: &Code{ 115 Type: "totp", 116 Label: "app token", 117 Secret: "foobar", 118 Digits: 100, 119 }, 120 shouldErr: true, 121 err: fmt.Errorf("digits must be between 4 and 8 numbers long"), 122 }, 123 { 124 name: "invalid token code with invalid period value", 125 code: &Code{ 126 Type: "totp", 127 Label: "app token", 128 Secret: "foobar", 129 Period: 360, 130 }, 131 shouldErr: true, 132 err: fmt.Errorf("token period must be between 30 and 180 seconds"), 133 }, 134 { 135 name: "invalid hotp token code without counter", 136 code: &Code{ 137 Type: "hotp", 138 Label: "app token", 139 Secret: "foobar", 140 }, 141 shouldErr: true, 142 err: fmt.Errorf("hotp token counter must be set"), 143 }, 144 { 145 name: "invalid token code with invalid algorithm value", 146 code: &Code{ 147 Type: "totp", 148 Label: "app token", 149 Secret: "foobar", 150 Algorithm: "foobar", 151 }, 152 shouldErr: true, 153 err: fmt.Errorf("token algo must be SHA1, SHA256, or SHA512"), 154 }, 155 { 156 name: "empty code", 157 shouldErr: true, 158 err: fmt.Errorf("token label must be set"), 159 }, 160 } 161 162 for _, tc := range testcases { 163 t.Run(tc.name, func(t *testing.T) { 164 msgs := []string{fmt.Sprintf("test name: %s", tc.name)} 165 if tc.code == nil { 166 tc.code = NewCode() 167 } 168 err := tc.code.Build() 169 if tests.EvalErrWithLog(t, err, "", tc.shouldErr, tc.err, msgs) { 170 return 171 } 172 got := map[string]interface{}{ 173 "code": tc.code.Get(), 174 "encoded": tc.code.GetEncoded(), 175 } 176 tests.EvalObjectsWithLog(t, "qr code", tc.want, got, msgs) 177 }) 178 } 179 }