github.com/greenpau/go-authcrunch@v1.1.4/pkg/identity/qr/qr_test.go (about) 1 // Copyright 2022 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 "fmt" 19 "github.com/greenpau/go-authcrunch/internal/tests" 20 "testing" 21 ) 22 23 func TestNewCode(t *testing.T) { 24 testcases := []struct { 25 name string 26 code *Code 27 want map[string]interface{} 28 shouldErr bool 29 err error 30 }{ 31 { 32 name: "valid totp app token code with sha1", 33 code: &Code{ 34 Secret: "foobar", 35 Type: "totp", 36 Label: "app token", 37 Period: 30, 38 Algorithm: "sha1", 39 Issuer: "Self", 40 Digits: 6, 41 }, 42 want: map[string]interface{}{ 43 "code": "otpauth://totp/app+token?secret=MZXW6YTBOI&issuer=Self&algorithm=sha1&digits=6&period=30", 44 "encoded": "b3RwYXV0aDovL3RvdHAvYXBwK3Rva2VuP3NlY3JldD1NWlhXNllUQk9JJmlzc3Vlcj1TZWxmJmFsZ29yaXRobT1zaGExJmRpZ2l0cz02JnBlcmlvZD0zMA==", 45 }, 46 }, 47 { 48 name: "valid hotp app token code with sha1", 49 code: &Code{ 50 Secret: "foobar", 51 Type: "hotp", 52 Label: "app token", 53 Algorithm: "sha1", 54 Issuer: "Self", 55 Counter: 100, 56 }, 57 want: map[string]interface{}{ 58 "code": "otpauth://hotp/app+token?secret=MZXW6YTBOI&issuer=Self&algorithm=sha1&digits=6&counter=100&period=30", 59 "encoded": "b3RwYXV0aDovL2hvdHAvYXBwK3Rva2VuP3NlY3JldD1NWlhXNllUQk9JJmlzc3Vlcj1TZWxmJmFsZ29yaXRobT1zaGExJmRpZ2l0cz02JmNvdW50ZXI9MTAwJnBlcmlvZD0zMA==", 60 }, 61 }, 62 { 63 name: "valid totp app token code with defaults", 64 code: &Code{ 65 Secret: "foobar", 66 Type: "totp", 67 Label: "app token", 68 Issuer: "Self", 69 }, 70 want: map[string]interface{}{ 71 "code": "otpauth://totp/app+token?secret=MZXW6YTBOI&issuer=Self&digits=6&period=30", 72 "encoded": "b3RwYXV0aDovL3RvdHAvYXBwK3Rva2VuP3NlY3JldD1NWlhXNllUQk9JJmlzc3Vlcj1TZWxmJmRpZ2l0cz02JnBlcmlvZD0zMA==", 73 }, 74 }, 75 { 76 name: "invalid token code without type", 77 code: &Code{ 78 Label: "app token", 79 Secret: "foobar", 80 }, 81 shouldErr: true, 82 err: fmt.Errorf("token type must be either totp or hotp"), 83 }, 84 { 85 name: "invalid token code without label", 86 code: &Code{ 87 Type: "totp", 88 }, 89 shouldErr: true, 90 err: fmt.Errorf("token label must be set"), 91 }, 92 { 93 name: "invalid token code without secret", 94 code: &Code{ 95 Type: "totp", 96 Label: "app token", 97 }, 98 shouldErr: true, 99 err: fmt.Errorf("token secret must be set"), 100 }, 101 { 102 name: "invalid token code with secret too short", 103 code: &Code{ 104 Type: "totp", 105 Label: "app token", 106 Secret: "12345", 107 }, 108 shouldErr: true, 109 err: fmt.Errorf("token secret must be at least 6 characters long"), 110 }, 111 { 112 name: "invalid token code with invalid digits value", 113 code: &Code{ 114 Type: "totp", 115 Label: "app token", 116 Secret: "foobar", 117 Digits: 100, 118 }, 119 shouldErr: true, 120 err: fmt.Errorf("digits must be between 4 and 8 numbers long"), 121 }, 122 { 123 name: "invalid token code with invalid period value", 124 code: &Code{ 125 Type: "totp", 126 Label: "app token", 127 Secret: "foobar", 128 Period: 360, 129 }, 130 shouldErr: true, 131 err: fmt.Errorf("token period must be between 30 and 180 seconds"), 132 }, 133 { 134 name: "invalid hotp token code without counter", 135 code: &Code{ 136 Type: "hotp", 137 Label: "app token", 138 Secret: "foobar", 139 }, 140 shouldErr: true, 141 err: fmt.Errorf("hotp token counter must be set"), 142 }, 143 { 144 name: "invalid token code with invalid algorithm value", 145 code: &Code{ 146 Type: "totp", 147 Label: "app token", 148 Secret: "foobar", 149 Algorithm: "foobar", 150 }, 151 shouldErr: true, 152 err: fmt.Errorf("token algo must be SHA1, SHA256, or SHA512"), 153 }, 154 { 155 name: "empty code", 156 shouldErr: true, 157 err: fmt.Errorf("token label must be set"), 158 }, 159 } 160 161 for _, tc := range testcases { 162 t.Run(tc.name, func(t *testing.T) { 163 msgs := []string{fmt.Sprintf("test name: %s", tc.name)} 164 if tc.code == nil { 165 tc.code = NewCode() 166 } 167 err := tc.code.Build() 168 if tests.EvalErrWithLog(t, err, "", tc.shouldErr, tc.err, msgs) { 169 return 170 } 171 got := map[string]interface{}{ 172 "code": tc.code.Get(), 173 "encoded": tc.code.GetEncoded(), 174 } 175 tests.EvalObjectsWithLog(t, "qr code", tc.want, got, msgs) 176 }) 177 } 178 }