🚚 Moved GrantType into separated grant package

This commit is contained in:
Maxim Lebedev 2024-05-06 18:24:04 +05:00
parent 62bc20e243
commit 70d6163099
Signed by: toby3d
GPG Key ID: 1F14E25B7C119FC5
5 changed files with 184 additions and 188 deletions

View File

@ -0,0 +1,96 @@
package grant
import (
"errors"
"fmt"
"strconv"
"strings"
"source.toby3d.me/toby3d/auth/internal/common"
)
// Type represent fixed grant_type parameter.
//
// NOTE(toby3d): Encapsulate enums in structs for extra compile-time safety:
// https://threedots.tech/post/safer-enums-in-go/#struct-based-enums
type Type struct {
grantType string
}
//nolint:gochecknoglobals // structs cannot be constants
var (
Und = Type{} // "und"
AuthorizationCode = Type{"authorization_code"} // "authorization_code"
RefreshToken = Type{"refresh_token"} // "refresh_token"
// TicketAuth extension.
Ticket = Type{"ticket"}
)
var ErrTypeUnknown error = errors.New("unknown grant type")
//nolint:gochecknoglobals // maps cannot be constants
var uidsTypes = map[string]Type{
AuthorizationCode.grantType: AuthorizationCode,
RefreshToken.grantType: RefreshToken,
Ticket.grantType: Ticket,
}
// ParseType parse grant_type value as Type struct enum.
func ParseType(uid string) (Type, error) {
if out, ok := uidsTypes[uid]; ok {
return out, nil
}
return Und, fmt.Errorf("%w: %s", ErrTypeUnknown, uid)
}
// UnmarshalForm implements custom unmarshler for form values.
func (t *Type) UnmarshalForm(v []byte) error {
parsed, err := ParseType(strings.ToLower(string(v)))
if err != nil {
return fmt.Errorf("Type: UnmarshalForm: cannot parse value '%s': %w", string(v), err)
}
*t = parsed
return nil
}
// UnmarshalJSON implements custom unmarshler for JSON.
func (t *Type) UnmarshalJSON(v []byte) error {
unquoted, err := strconv.Unquote(string(v))
if err != nil {
return fmt.Errorf("Type: UnmarshalJSON: cannot unquote value '%s': %w", string(v), err)
}
parsed, err := ParseType(strings.ToLower(unquoted))
if err != nil {
return fmt.Errorf("Type: UnmarshalJSON: cannot parse value '%s': %w", unquoted, err)
}
*t = parsed
return nil
}
func (t Type) MarshalJSON() ([]byte, error) {
if t == Und {
return nil, nil
}
return []byte(strconv.Quote(t.grantType)), nil
}
// String returns string representation of grant type.
func (t Type) String() string {
if t == Und {
return common.Und
}
return t.grantType
}
func (t Type) GoString() string {
return "grant.Type(" + t.String() + ")"
}

View File

@ -0,0 +1,82 @@
package grant_test
import (
"testing"
"source.toby3d.me/toby3d/auth/internal/domain/grant"
)
func TestParseType(t *testing.T) {
t.Parallel()
for name, tc := range map[string]struct {
input string
expect grant.Type
}{
"authorization_code": {input: "authorization_code", expect: grant.AuthorizationCode},
"ticket": {input: "ticket", expect: grant.Ticket},
} {
t.Run(name, func(t *testing.T) {
t.Parallel()
actual, err := grant.ParseType(tc.input)
if err != nil {
t.Fatalf("%+v", err)
}
if actual != tc.expect {
t.Errorf("ParseType(%s) = %v, want %v", tc.input, actual, tc.expect)
}
})
}
}
func TestType_UnmarshalForm(t *testing.T) {
t.Parallel()
input := []byte("authorization_code")
actual := grant.Und
if err := actual.UnmarshalForm(input); err != nil {
t.Fatalf("%+v", err)
}
if actual != grant.AuthorizationCode {
t.Errorf("UnmarshalForm(%s) = %v, want %v", input, actual, grant.AuthorizationCode)
}
}
func TestType_UnmarshalJSON(t *testing.T) {
t.Parallel()
input := []byte(`"authorization_code"`)
actual := grant.Und
if err := actual.UnmarshalJSON(input); err != nil {
t.Fatalf("%+v", err)
}
if actual != grant.AuthorizationCode {
t.Errorf("UnmarshalJSON(%s) = %v, want %v", input, actual, grant.AuthorizationCode)
}
}
func TestType_String(t *testing.T) {
t.Parallel()
for name, tc := range map[string]struct {
input grant.Type
expect string
}{
"authorization_code": {input: grant.AuthorizationCode, expect: "authorization_code"},
"ticket": {input: grant.Ticket, expect: "ticket"},
} {
t.Run(name, func(t *testing.T) {
t.Parallel()
if actual := tc.input.String(); actual != tc.expect {
t.Errorf("String() = %v, want %v", actual, tc.expect)
}
})
}
}

View File

@ -1,95 +0,0 @@
package domain
import (
"fmt"
"strconv"
"strings"
"source.toby3d.me/toby3d/auth/internal/common"
)
// GrantType represent fixed grant_type parameter.
//
// NOTE(toby3d): Encapsulate enums in structs for extra compile-time safety:
// https://threedots.tech/post/safer-enums-in-go/#struct-based-enums
type GrantType struct {
grantType string
}
//nolint:gochecknoglobals // structs cannot be constants
var (
GrantTypeUnd = GrantType{grantType: ""} // "und"
GrantTypeAuthorizationCode = GrantType{grantType: "authorization_code"} // "authorization_code"
GrantTypeRefreshToken = GrantType{grantType: "refresh_token"} // "refresh_token"
// TicketAuth extension.
GrantTypeTicket = GrantType{grantType: "ticket"}
)
var ErrGrantTypeUnknown error = NewError(
ErrorCodeInvalidGrant,
"unknown grant type",
"",
)
//nolint:gochecknoglobals // maps cannot be constants
var uidsGrantTypes = map[string]GrantType{
GrantTypeAuthorizationCode.grantType: GrantTypeAuthorizationCode,
GrantTypeRefreshToken.grantType: GrantTypeRefreshToken,
GrantTypeTicket.grantType: GrantTypeTicket,
}
// ParseGrantType parse grant_type value as GrantType struct enum.
func ParseGrantType(uid string) (GrantType, error) {
if grantType, ok := uidsGrantTypes[uid]; ok {
return grantType, nil
}
return GrantTypeUnd, fmt.Errorf("%w: %s", ErrGrantTypeUnknown, uid)
}
// UnmarshalForm implements custom unmarshler for form values.
func (gt *GrantType) UnmarshalForm(src []byte) error {
responseType, err := ParseGrantType(strings.ToLower(string(src)))
if err != nil {
return fmt.Errorf("GrantType: UnmarshalForm: %w", err)
}
*gt = responseType
return nil
}
// UnmarshalJSON implements custom unmarshler for JSON.
func (gt *GrantType) UnmarshalJSON(v []byte) error {
unquoted, err := strconv.Unquote(string(v))
if err != nil {
return fmt.Errorf("GrantType: UnmarshalJSON: cannot unquote value '%s': %w", string(v), err)
}
parsed, err := ParseGrantType(strings.ToLower(unquoted))
if err != nil {
return fmt.Errorf("GrantType: UnmarshalJSON: cannot parse value '%s': %w", unquoted, err)
}
*gt = parsed
return nil
}
func (gt GrantType) MarshalJSON() ([]byte, error) {
return []byte(strconv.Quote(gt.grantType)), nil
}
// String returns string representation of grant type.
func (gt GrantType) String() string {
if gt.grantType != "" {
return gt.grantType
}
return common.Und
}
func (gt GrantType) GoString() string {
return "domain.GrantType(" + gt.String() + ")"
}

View File

@ -1,89 +0,0 @@
//nolint:dupl
package domain_test
import (
"testing"
"source.toby3d.me/toby3d/auth/internal/domain"
)
func TestParseGrantType(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
in string
out domain.GrantType
}{
{in: "authorization_code", out: domain.GrantTypeAuthorizationCode},
{in: "ticket", out: domain.GrantTypeTicket},
} {
tc := tc
t.Run(tc.in, func(t *testing.T) {
t.Parallel()
result, err := domain.ParseGrantType(tc.in)
if err != nil {
t.Fatalf("%+v", err)
}
if result != tc.out {
t.Errorf("ParseGrantType(%s) = %v, want %v", tc.in, result, tc.out)
}
})
}
}
func TestGrantType_UnmarshalForm(t *testing.T) {
t.Parallel()
input := []byte("authorization_code")
result := domain.GrantTypeUnd
if err := result.UnmarshalForm(input); err != nil {
t.Fatalf("%+v", err)
}
if result != domain.GrantTypeAuthorizationCode {
t.Errorf("UnmarshalForm(%s) = %v, want %v", input, result, domain.GrantTypeAuthorizationCode)
}
}
func TestGrantType_UnmarshalJSON(t *testing.T) {
t.Parallel()
input := []byte(`"authorization_code"`)
result := domain.GrantTypeUnd
if err := result.UnmarshalJSON(input); err != nil {
t.Fatalf("%+v", err)
}
if result != domain.GrantTypeAuthorizationCode {
t.Errorf("UnmarshalJSON(%s) = %v, want %v", input, result, domain.GrantTypeAuthorizationCode)
}
}
func TestGrantType_String(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
name string
in domain.GrantType
out string
}{
{name: "authorization_code", in: domain.GrantTypeAuthorizationCode, out: "authorization_code"},
{name: "ticket", in: domain.GrantTypeTicket, out: "ticket"},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
result := tc.in.String()
if result != tc.out {
t.Errorf("String() = %v, want %v", result, tc.out)
}
})
}
}

View File

@ -3,6 +3,8 @@ package domain
import (
"net/url"
"testing"
"source.toby3d.me/toby3d/auth/internal/domain/grant"
)
type Metadata struct {
@ -57,7 +59,7 @@ type Metadata struct {
// JSON array containing grant type values supported. If omitted, the
// default value differs from RFC8414 and is authorization_code.
GrantTypesSupported []GrantType
GrantTypesSupported []grant.Type
// JSON array containing the methods supported for PKCE. This parameter
// differs from RFC8414 in that it is not optional as PKCE is REQUIRED.
@ -112,9 +114,9 @@ func TestMetadata(tb testing.TB) *Metadata {
ResponseTypeCode,
ResponseTypeID,
},
GrantTypesSupported: []GrantType{
GrantTypeAuthorizationCode,
GrantTypeTicket,
GrantTypesSupported: []grant.Type{
grant.AuthorizationCode,
grant.Ticket,
},
CodeChallengeMethodsSupported: []CodeChallengeMethod{
CodeChallengeMethodMD5,