From 4127eca29d408f2bc51a01507a379d4ef9e91b89 Mon Sep 17 00:00:00 2001 From: Maxim Lebedev Date: Wed, 12 Jan 2022 23:04:40 +0500 Subject: [PATCH] :art: Format code of domains --- internal/domain/client.go | 6 ++--- internal/domain/client_id.go | 11 +++++--- internal/domain/config.go | 38 +++++++++++++-------------- internal/domain/me.go | 11 +++++--- internal/domain/response_type.go | 12 +++------ internal/domain/scope.go | 40 ++++++++++------------------- internal/domain/scope_test.go | 44 ++++++++++++++++++++++++++------ internal/domain/token.go | 12 ++++----- internal/domain/url.go | 2 +- 9 files changed, 97 insertions(+), 79 deletions(-) diff --git a/internal/domain/client.go b/internal/domain/client.go index 2b95416..9ad447c 100644 --- a/internal/domain/client.go +++ b/internal/domain/client.go @@ -76,7 +76,7 @@ func (c *Client) ValidateRedirectURI(redirectURI *URL) bool { return false } -func (c *Client) GetName() string { +func (c Client) GetName() string { if len(c.Name) < 1 { return "" } @@ -84,7 +84,7 @@ func (c *Client) GetName() string { return c.Name[0] } -func (c *Client) GetURL() *URL { +func (c Client) GetURL() *URL { if len(c.URL) < 1 { return nil } @@ -92,7 +92,7 @@ func (c *Client) GetURL() *URL { return c.URL[0] } -func (c *Client) GetLogo() *URL { +func (c Client) GetLogo() *URL { if len(c.Logo) < 1 { return nil } diff --git a/internal/domain/client_id.go b/internal/domain/client_id.go index 2d7b2ff..ddfaa67 100644 --- a/internal/domain/client_id.go +++ b/internal/domain/client_id.go @@ -25,6 +25,7 @@ var ( localhostIPv6 = netaddr.MustParseIP("::1") ) +//nolint: funlen func NewClientID(raw string) (*ClientID, error) { clientID := http.AcquireURI() if err := clientID.Parse(nil, []byte(raw)); err != nil { @@ -146,16 +147,20 @@ func (cid *ClientID) UnmarshalJSON(v []byte) error { return nil } +func (cid ClientID) MarshalJSON() ([]byte, error) { + return []byte(strconv.Quote(cid.String())), nil +} + // URI returns copy of parsed *fasthttp.URI. // This copy MUST be released via fasthttp.ReleaseURI. -func (cid *ClientID) URI() *http.URI { +func (cid ClientID) URI() *http.URI { u := http.AcquireURI() cid.clientID.CopyTo(u) return u } -func (cid *ClientID) URL() *url.URL { +func (cid ClientID) URL() *url.URL { return &url.URL{ Scheme: string(cid.clientID.Scheme()), Host: string(cid.clientID.Host()), @@ -167,6 +172,6 @@ func (cid *ClientID) URL() *url.URL { } // String returns string representation of client ID. -func (cid *ClientID) String() string { +func (cid ClientID) String() string { return cid.clientID.String() } diff --git a/internal/domain/config.go b/internal/domain/config.go index 12d5065..df86fca 100644 --- a/internal/domain/config.go +++ b/internal/domain/config.go @@ -49,7 +49,7 @@ type ( ConfigJWT struct { Expiry time.Duration `yaml:"expiry"` // 1h - Secret interface{} `yaml:"secret"` + Secret string `yaml:"secret"` Algorithm string `yaml:"algorithm"` // HS256 NonceLength int `yaml:"nonceLength"` // 22 } @@ -64,23 +64,6 @@ type ( } ) -// GetAddress return host:port address. -func (cs *ConfigServer) GetAddress() string { - return net.JoinHostPort(cs.Host, cs.Port) -} - -// GetRootURL returns generated from template RootURL. -func (cs *ConfigServer) GetRootURL() string { - return fasttemplate.ExecuteString(cs.RootURL, `{{`, `}}`, map[string]interface{}{ - "domain": cs.Domain, - "host": cs.Host, - "port": cs.Port, - "protocol": cs.Protocol, - "staticRootPath": cs.StaticRootPath, - "staticUrlPrefix": cs.StaticURLPrefix, - }) -} - // TestConfig returns a valid *viper.Viper with the generated test data filled in. func TestConfig(tb testing.TB) *Config { tb.Helper() @@ -111,7 +94,7 @@ func TestConfig(tb testing.TB) *Config { JWT: ConfigJWT{ Expiry: time.Hour, NonceLength: 22, - Secret: []byte("hackme"), + Secret: "hackme", Algorithm: "HS256", }, IndieAuth: ConfigIndieAuth{ @@ -123,3 +106,20 @@ func TestConfig(tb testing.TB) *Config { }, } } + +// GetAddress return host:port address. +func (cs ConfigServer) GetAddress() string { + return net.JoinHostPort(cs.Host, cs.Port) +} + +// GetRootURL returns generated from template RootURL. +func (cs ConfigServer) GetRootURL() string { + return fasttemplate.ExecuteString(cs.RootURL, `{{`, `}}`, map[string]interface{}{ + "domain": cs.Domain, + "host": cs.Host, + "port": cs.Port, + "protocol": cs.Protocol, + "staticRootPath": cs.StaticRootPath, + "staticUrlPrefix": cs.StaticURLPrefix, + }) +} diff --git a/internal/domain/me.go b/internal/domain/me.go index 42a4503..8760470 100644 --- a/internal/domain/me.go +++ b/internal/domain/me.go @@ -18,6 +18,7 @@ type Me struct { me *http.URI } +//nolint: funlen func NewMe(raw string) (*Me, error) { me := http.AcquireURI() if err := me.Parse(nil, []byte(raw)); err != nil { @@ -137,9 +138,13 @@ func (m *Me) UnmarshalJSON(v []byte) error { return nil } +func (m Me) MarshalJSON() ([]byte, error) { + return []byte(strconv.Quote(m.String())), nil +} + // URI returns copy of parsed Me in *fasthttp.URI representation. // This copy MUST be released via fasthttp.ReleaseURI. -func (m *Me) URI() *http.URI { +func (m Me) URI() *http.URI { if m.me == nil { return nil } @@ -151,7 +156,7 @@ func (m *Me) URI() *http.URI { } // URL returns copy of parsed Me in *url.URL representation. -func (m *Me) URL() *url.URL { +func (m Me) URL() *url.URL { if m.me == nil { return nil } @@ -167,7 +172,7 @@ func (m *Me) URL() *url.URL { } // String returns string representation of Me. -func (m *Me) String() string { +func (m Me) String() string { if m.me == nil { return "" } diff --git a/internal/domain/response_type.go b/internal/domain/response_type.go index 8d5d23f..eba79e6 100644 --- a/internal/domain/response_type.go +++ b/internal/domain/response_type.go @@ -15,24 +15,18 @@ type ResponseType struct { //nolint: gochecknoglobals // NOTE(toby3d): structs cannot be constants var ( - ResponseTypeUndefined ResponseType = ResponseType{ - slug: "", - } + ResponseTypeUndefined ResponseType = ResponseType{slug: ""} // Deprecated(toby3d): Only accept response_type=code requests, and for // backwards-compatible support, treat response_type=id requests as // response_type=code requests: // https://aaronparecki.com/2020/12/03/1/indieauth-2020#response-type - ResponseTypeID ResponseType = ResponseType{ - slug: "id", - } + ResponseTypeID ResponseType = ResponseType{slug: "id"} // Indicates to the authorization server that an authorization code // should be returned as the response: // https://indieauth.net/source/#authorization-request-li-1 - ResponseTypeCode ResponseType = ResponseType{ - slug: "code", - } + ResponseTypeCode ResponseType = ResponseType{slug: "code"} ) var ErrResponseTypeUnknown = errors.New("unknown grant type") diff --git a/internal/domain/scope.go b/internal/domain/scope.go index f8fb7ea..20fb454 100644 --- a/internal/domain/scope.go +++ b/internal/domain/scope.go @@ -42,9 +42,7 @@ var ( // which include the following properties: name, `photo, url. // // NOTE(toby3d): https://indieauth.net/source/#profile-information - ScopeProfile = Scope{ - slug: "profile", - } + ScopeProfile = Scope{slug: "profile"} // This scope requests access to the user's email address in the // following property: email. @@ -54,9 +52,7 @@ var ( // and must be requested along with the profile scope if desired. // // NOTE(toby3d): https://indieauth.net/source/#profile-information - ScopeEmail = Scope{ - slug: "email", - } + ScopeEmail = Scope{slug: "email"} ) //nolint: gochecknoglobals // NOTE(toby3d): maps cannot be constants @@ -85,29 +81,19 @@ func ParseScope(slug string) (Scope, error) { } // UnmarshalForm parses the value of the form key into the Scope domain. -func (s *Scope) UnmarshalForm(v []byte) (err error) { - scope, err := ParseScope(string(v)) - if err != nil { - return fmt.Errorf("scope: %w", err) +func (s *Scopes) UnmarshalForm(v []byte) error { + scopes := make(Scopes, 0) + + for _, rawScope := range strings.Fields(string(v)) { + scope, err := ParseScope(rawScope) + if err != nil { + return fmt.Errorf("scopes: %w", err) + } + + *s = append(scopes, scope) } - *s = scope - - return nil -} - -func (s *Scope) UnmarshalJSON(v []byte) error { - src, err := strconv.Unquote(string(v)) - if err != nil { - return err - } - - scope, err := ParseScope(src) - if err != nil { - return fmt.Errorf("scope: %w", err) - } - - *s = scope + *s = scopes return nil } diff --git a/internal/domain/scope_test.go b/internal/domain/scope_test.go index f765821..afc7fc6 100644 --- a/internal/domain/scope_test.go +++ b/internal/domain/scope_test.go @@ -6,19 +6,47 @@ import ( "github.com/goccy/go-json" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + http "github.com/valyala/fasthttp" + "source.toby3d.me/toby3d/form" "source.toby3d.me/website/indieauth/internal/domain" ) +func TestScopes_UnmarshalForm(t *testing.T) { + t.Parallel() + + args := http.AcquireArgs() + defer http.ReleaseArgs(args) + args.Set("scope", "read update delete") + + result := struct { + Scope domain.Scopes + }{ + Scope: make(domain.Scopes, 0), + } + + require.NoError(t, form.Unmarshal(args, &result)) + assert.Equal(t, "read update delete", result.Scope.String()) +} + func TestScopes_UnmarshalJSON(t *testing.T) { t.Parallel() - result := &struct { - Scope domain.Scopes `json:"scope"` - }{} - require.NoError(t, json.Unmarshal([]byte(`{"scope": "read update delete"}`), result)) - - for _, scope := range []domain.Scope{domain.ScopeRead, domain.ScopeUpdate, domain.ScopeDelete} { - assert.Contains(t, result.Scope, scope) - } + result := make(map[string]domain.Scopes) + require.NoError(t, json.Unmarshal([]byte(`{"scope":"read update delete"}`), &result)) + assert.Equal(t, domain.Scopes{domain.ScopeRead, domain.ScopeUpdate, domain.ScopeDelete}, result["scope"]) +} + +func TestScopes_MarshalJSON(t *testing.T) { + t.Parallel() + + result, err := json.Marshal(map[string]domain.Scopes{ + "scope": { + domain.ScopeEmail, + domain.ScopeProfile, + domain.ScopeRead, + }, + }) + require.NoError(t, err) + assert.Equal(t, `{"scope":"email profile read"}`, string(result)) } diff --git a/internal/domain/token.go b/internal/domain/token.go index 0d9d928..57e9fa0 100644 --- a/internal/domain/token.go +++ b/internal/domain/token.go @@ -28,14 +28,14 @@ type ( Issuer *ClientID NonceLength int Scope Scopes - Secret interface{} + Secret []byte Subject *Me } ) var DefaultNewTokenOptions = NewTokenOptions{ - NonceLength: 32, Algorithm: "HS256", + NonceLength: 32, } func NewToken(opts NewTokenOptions) (*Token, error) { @@ -83,7 +83,7 @@ func NewToken(opts NewTokenOptions) (*Token, error) { func TestToken(tb testing.TB) *Token { tb.Helper() - nonce, err := random.String(42) + nonce, err := random.String(22) require.NoError(tb, err) t := jwt.New() @@ -98,7 +98,7 @@ func TestToken(tb testing.TB) *Token { // NOTE(toby3d): required t.Set(jwt.IssuerKey, cid.String()) - t.Set(jwt.SubjectKey, me.me.String()) + t.Set(jwt.SubjectKey, me.String()) // TODO(toby3d): t.Set(jwt.AudienceKey, nil) t.Set(jwt.ExpirationKey, now.Add(1*time.Hour)) t.Set(jwt.NotBeforeKey, now.Add(-1*time.Hour)) @@ -121,7 +121,7 @@ func TestToken(tb testing.TB) *Token { } // SetAuthHeader writes an Access Token to the request header. -func (t *Token) SetAuthHeader(r *http.Request) { +func (t Token) SetAuthHeader(r *http.Request) { if t.AccessToken == "" { return } @@ -129,7 +129,7 @@ func (t *Token) SetAuthHeader(r *http.Request) { r.Header.Set(http.HeaderAuthorization, t.String()) } -func (t *Token) String() string { +func (t Token) String() string { if t.AccessToken == "" { return "" } diff --git a/internal/domain/url.go b/internal/domain/url.go index 5cbbd08..b693fe9 100644 --- a/internal/domain/url.go +++ b/internal/domain/url.go @@ -61,7 +61,7 @@ func (u *URL) UnmarshalJSON(v []byte) error { return nil } -func (u *URL) URL() *url.URL { +func (u URL) URL() *url.URL { if u.URI == nil { return nil }