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  }