From 09686bd066a96d068c0a67eaad00ba9363cecac3 Mon Sep 17 00:00:00 2001 From: James Elliott Date: Sun, 1 Oct 2023 19:08:17 +1100 Subject: [PATCH] test: add tests This adds tests and validates another element of te requirements. --- webauthn/types.go | 22 +++-- webauthn/types_test.go | 182 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 webauthn/types_test.go diff --git a/webauthn/types.go b/webauthn/types.go index b38d4f5..482a5b2 100644 --- a/webauthn/types.go +++ b/webauthn/types.go @@ -104,14 +104,26 @@ func (config *Config) validate() error { var err error - if _, err = url.Parse(config.RPID); err != nil { - return fmt.Errorf(errFmtFieldNotValidURI, "RPID", err) + var uri *url.URL + + if len(config.RPID) != 0 { + if uri, err = url.Parse(config.RPID); err != nil { + return fmt.Errorf(errFmtFieldNotValidURI, "RPID", err) + } + + if uri.IsAbs() { + return fmt.Errorf("field '%s' is an absolute URI but it must not be an absolute URI", "RPID") + } } - if config.RPIcon != "" { - if _, err = url.Parse(config.RPIcon); err != nil { + if len(config.RPIcon) != 0 { + if uri, err = url.Parse(config.RPIcon); err != nil { return fmt.Errorf(errFmtFieldNotValidURI, "RPIcon", err) } + + if !uri.IsAbs() { + return fmt.Errorf("field '%s' is not an absolute URI but it must be an absolute URI", "RPIcon") + } } defaultTimeoutConfig := defaultTimeout @@ -138,7 +150,7 @@ func (config *Config) validate() error { config.Timeouts.Registration.TimeoutUVD = defaultTimeoutUVDConfig } - if len(config.RPOrigin) > 0 { + if len(config.RPOrigin) != 0 { if len(config.RPOrigins) != 0 { return fmt.Errorf("deprecated field 'RPOrigin' can't be defined at the same tme as the replacement field 'RPOrigins'") } diff --git a/webauthn/types_test.go b/webauthn/types_test.go new file mode 100644 index 0000000..e0d41fd --- /dev/null +++ b/webauthn/types_test.go @@ -0,0 +1,182 @@ +package webauthn + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestConfigValidateErr(t *testing.T) { + testCases := []struct { + name string + have *Config + err string + check func(t *testing.T, have *Config) + }{ + { + "ShouldNotErrorOnStandardConfig", + &Config{ + RPID: "example.com", + RPDisplayName: "example", + RPOrigins: []string{ + "https://example.com", + }, + }, + "", + nil, + }, + { + "ShouldErrorOnAbsoluteRPID", + &Config{ + RPID: "https://example.com", + RPDisplayName: "example", + RPOrigins: []string{ + "https://example.com", + }, + }, + "field 'RPID' is an absolute URI but it must not be an absolute URI", + nil, + }, + { + "ShouldSkipValidation", + &Config{ + validated: true, + }, + "", + nil, + }, + { + "ShouldErrorOnBadRPIcon", + &Config{ + RPID: "example.com", + RPIcon: "exa$##$#@$@#%^@#mple.com", + RPDisplayName: "example", + RPOrigins: []string{ + "https://example.com", + }, + }, + "field 'RPIcon' is not a valid URI: parse \"exa$##$#@$@#%^@#mple.com\": invalid URL escape \"%^@\"", + nil, + }, + { + "ShouldErrorOnBadRPIconAbsolute", + &Config{ + RPID: "example.com", + RPIcon: "example.com", + RPDisplayName: "example", + RPOrigins: []string{ + "https://example.com", + }, + }, + "field 'RPIcon' is not an absolute URI but it must be an absolute URI", + nil, + }, + { + "ShouldSetFallbackRPOriginAndNotErr", + &Config{ + RPID: "example.com", + RPDisplayName: "example", + RPOrigin: "https://example.com", + RPOrigins: []string{}, + }, + "", + func(t *testing.T, have *Config) { + require.Len(t, have.RPOrigins, 1) + assert.Equal(t, "https://example.com", have.RPOrigins[0]) + }, + }, + { + "ShouldNotErrorOnConfigWithoutRPID", + &Config{ + RPDisplayName: "example", + RPOrigins: []string{ + "https://example.com", + }, + }, + "", + nil, + }, + { + "ShouldErrorOnNoDisplayName", + &Config{ + RPID: "example.com", + RPOrigins: []string{ + "https://example.com", + }, + }, + "the field 'RPDisplayName' must be configured but it is empty", + nil, + }, + { + "ShouldErrorOnNoOrigins", + &Config{ + RPID: "example.com", + RPDisplayName: "example", + RPOrigins: []string{}, + }, + "must provide at least one value to the 'RPOrigins' field", + nil, + }, + { + "ShouldErrorOnInvalidRPID", + &Config{ + RPID: "exa$##$#@$@#%^@#mple.com", + RPDisplayName: "example", + RPOrigins: []string{ + "https://example.com", + }, + }, + "field 'RPID' is not a valid URI: parse \"exa$##$#@$@#%^@#mple.com\": invalid URL escape \"%^@\"", + nil, + }, + { + "ShouldErrorOnDeprecatedAndNewRPOrigins", + &Config{ + RPID: "example.com", + RPDisplayName: "example", + RPOrigin: "https://example.com", + RPOrigins: []string{ + "https://example.com", + }, + }, + "deprecated field 'RPOrigin' can't be defined at the same tme as the replacement field 'RPOrigins'", + nil, + }, + { + "ShouldSetDefaultTimeoutValues", + &Config{ + RPID: "example.com", + RPDisplayName: "example", + RPOrigins: []string{ + "https://example.com", + }, + Timeout: int(time.Second.Milliseconds()), + }, + "", + func(t *testing.T, have *Config) { + assert.Equal(t, time.Second, have.Timeouts.Login.Timeout) + assert.Equal(t, time.Second, have.Timeouts.Login.TimeoutUVD) + assert.Equal(t, time.Second, have.Timeouts.Registration.Timeout) + assert.Equal(t, time.Second, have.Timeouts.Registration.TimeoutUVD) + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.have.validate() + + if len(tc.err) == 0 { + assert.NoError(t, err) + } else { + assert.EqualError(t, err, tc.err) + } + + if tc.check != nil { + tc.check(t, tc.have) + } + }) + } +}