🎨 Format code of domains

This commit is contained in:
Maxim Lebedev 2022-01-12 23:04:40 +05:00
parent 257759e47c
commit 4127eca29d
Signed by: toby3d
GPG Key ID: 1F14E25B7C119FC5
9 changed files with 97 additions and 79 deletions

View File

@ -76,7 +76,7 @@ func (c *Client) ValidateRedirectURI(redirectURI *URL) bool {
return false return false
} }
func (c *Client) GetName() string { func (c Client) GetName() string {
if len(c.Name) < 1 { if len(c.Name) < 1 {
return "" return ""
} }
@ -84,7 +84,7 @@ func (c *Client) GetName() string {
return c.Name[0] return c.Name[0]
} }
func (c *Client) GetURL() *URL { func (c Client) GetURL() *URL {
if len(c.URL) < 1 { if len(c.URL) < 1 {
return nil return nil
} }
@ -92,7 +92,7 @@ func (c *Client) GetURL() *URL {
return c.URL[0] return c.URL[0]
} }
func (c *Client) GetLogo() *URL { func (c Client) GetLogo() *URL {
if len(c.Logo) < 1 { if len(c.Logo) < 1 {
return nil return nil
} }

View File

@ -25,6 +25,7 @@ var (
localhostIPv6 = netaddr.MustParseIP("::1") localhostIPv6 = netaddr.MustParseIP("::1")
) )
//nolint: funlen
func NewClientID(raw string) (*ClientID, error) { func NewClientID(raw string) (*ClientID, error) {
clientID := http.AcquireURI() clientID := http.AcquireURI()
if err := clientID.Parse(nil, []byte(raw)); err != nil { if err := clientID.Parse(nil, []byte(raw)); err != nil {
@ -146,16 +147,20 @@ func (cid *ClientID) UnmarshalJSON(v []byte) error {
return nil return nil
} }
func (cid ClientID) MarshalJSON() ([]byte, error) {
return []byte(strconv.Quote(cid.String())), nil
}
// URI returns copy of parsed *fasthttp.URI. // URI returns copy of parsed *fasthttp.URI.
// This copy MUST be released via fasthttp.ReleaseURI. // This copy MUST be released via fasthttp.ReleaseURI.
func (cid *ClientID) URI() *http.URI { func (cid ClientID) URI() *http.URI {
u := http.AcquireURI() u := http.AcquireURI()
cid.clientID.CopyTo(u) cid.clientID.CopyTo(u)
return u return u
} }
func (cid *ClientID) URL() *url.URL { func (cid ClientID) URL() *url.URL {
return &url.URL{ return &url.URL{
Scheme: string(cid.clientID.Scheme()), Scheme: string(cid.clientID.Scheme()),
Host: string(cid.clientID.Host()), Host: string(cid.clientID.Host()),
@ -167,6 +172,6 @@ func (cid *ClientID) URL() *url.URL {
} }
// String returns string representation of client ID. // String returns string representation of client ID.
func (cid *ClientID) String() string { func (cid ClientID) String() string {
return cid.clientID.String() return cid.clientID.String()
} }

View File

@ -49,7 +49,7 @@ type (
ConfigJWT struct { ConfigJWT struct {
Expiry time.Duration `yaml:"expiry"` // 1h Expiry time.Duration `yaml:"expiry"` // 1h
Secret interface{} `yaml:"secret"` Secret string `yaml:"secret"`
Algorithm string `yaml:"algorithm"` // HS256 Algorithm string `yaml:"algorithm"` // HS256
NonceLength int `yaml:"nonceLength"` // 22 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. // TestConfig returns a valid *viper.Viper with the generated test data filled in.
func TestConfig(tb testing.TB) *Config { func TestConfig(tb testing.TB) *Config {
tb.Helper() tb.Helper()
@ -111,7 +94,7 @@ func TestConfig(tb testing.TB) *Config {
JWT: ConfigJWT{ JWT: ConfigJWT{
Expiry: time.Hour, Expiry: time.Hour,
NonceLength: 22, NonceLength: 22,
Secret: []byte("hackme"), Secret: "hackme",
Algorithm: "HS256", Algorithm: "HS256",
}, },
IndieAuth: ConfigIndieAuth{ 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,
})
}

View File

@ -18,6 +18,7 @@ type Me struct {
me *http.URI me *http.URI
} }
//nolint: funlen
func NewMe(raw string) (*Me, error) { func NewMe(raw string) (*Me, error) {
me := http.AcquireURI() me := http.AcquireURI()
if err := me.Parse(nil, []byte(raw)); err != nil { if err := me.Parse(nil, []byte(raw)); err != nil {
@ -137,9 +138,13 @@ func (m *Me) UnmarshalJSON(v []byte) error {
return nil 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. // URI returns copy of parsed Me in *fasthttp.URI representation.
// This copy MUST be released via fasthttp.ReleaseURI. // This copy MUST be released via fasthttp.ReleaseURI.
func (m *Me) URI() *http.URI { func (m Me) URI() *http.URI {
if m.me == nil { if m.me == nil {
return nil return nil
} }
@ -151,7 +156,7 @@ func (m *Me) URI() *http.URI {
} }
// URL returns copy of parsed Me in *url.URL representation. // 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 { if m.me == nil {
return nil return nil
} }
@ -167,7 +172,7 @@ func (m *Me) URL() *url.URL {
} }
// String returns string representation of Me. // String returns string representation of Me.
func (m *Me) String() string { func (m Me) String() string {
if m.me == nil { if m.me == nil {
return "" return ""
} }

View File

@ -15,24 +15,18 @@ type ResponseType struct {
//nolint: gochecknoglobals // NOTE(toby3d): structs cannot be constants //nolint: gochecknoglobals // NOTE(toby3d): structs cannot be constants
var ( var (
ResponseTypeUndefined ResponseType = ResponseType{ ResponseTypeUndefined ResponseType = ResponseType{slug: ""}
slug: "",
}
// Deprecated(toby3d): Only accept response_type=code requests, and for // Deprecated(toby3d): Only accept response_type=code requests, and for
// backwards-compatible support, treat response_type=id requests as // backwards-compatible support, treat response_type=id requests as
// response_type=code requests: // response_type=code requests:
// https://aaronparecki.com/2020/12/03/1/indieauth-2020#response-type // https://aaronparecki.com/2020/12/03/1/indieauth-2020#response-type
ResponseTypeID ResponseType = ResponseType{ ResponseTypeID ResponseType = ResponseType{slug: "id"}
slug: "id",
}
// Indicates to the authorization server that an authorization code // Indicates to the authorization server that an authorization code
// should be returned as the response: // should be returned as the response:
// https://indieauth.net/source/#authorization-request-li-1 // https://indieauth.net/source/#authorization-request-li-1
ResponseTypeCode ResponseType = ResponseType{ ResponseTypeCode ResponseType = ResponseType{slug: "code"}
slug: "code",
}
) )
var ErrResponseTypeUnknown = errors.New("unknown grant type") var ErrResponseTypeUnknown = errors.New("unknown grant type")

View File

@ -42,9 +42,7 @@ var (
// which include the following properties: name, `photo, url. // which include the following properties: name, `photo, url.
// //
// NOTE(toby3d): https://indieauth.net/source/#profile-information // NOTE(toby3d): https://indieauth.net/source/#profile-information
ScopeProfile = Scope{ ScopeProfile = Scope{slug: "profile"}
slug: "profile",
}
// This scope requests access to the user's email address in the // This scope requests access to the user's email address in the
// following property: email. // following property: email.
@ -54,9 +52,7 @@ var (
// and must be requested along with the profile scope if desired. // and must be requested along with the profile scope if desired.
// //
// NOTE(toby3d): https://indieauth.net/source/#profile-information // NOTE(toby3d): https://indieauth.net/source/#profile-information
ScopeEmail = Scope{ ScopeEmail = Scope{slug: "email"}
slug: "email",
}
) )
//nolint: gochecknoglobals // NOTE(toby3d): maps cannot be constants //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. // UnmarshalForm parses the value of the form key into the Scope domain.
func (s *Scope) UnmarshalForm(v []byte) (err error) { func (s *Scopes) UnmarshalForm(v []byte) error {
scope, err := ParseScope(string(v)) scopes := make(Scopes, 0)
if err != nil {
return fmt.Errorf("scope: %w", err) 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 *s = scopes
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
return nil return nil
} }

View File

@ -6,19 +6,47 @@ import (
"github.com/goccy/go-json" "github.com/goccy/go-json"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
http "github.com/valyala/fasthttp"
"source.toby3d.me/toby3d/form"
"source.toby3d.me/website/indieauth/internal/domain" "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) { func TestScopes_UnmarshalJSON(t *testing.T) {
t.Parallel() t.Parallel()
result := &struct { result := make(map[string]domain.Scopes)
Scope domain.Scopes `json:"scope"` require.NoError(t, json.Unmarshal([]byte(`{"scope":"read update delete"}`), &result))
}{} assert.Equal(t, domain.Scopes{domain.ScopeRead, domain.ScopeUpdate, domain.ScopeDelete}, result["scope"])
require.NoError(t, json.Unmarshal([]byte(`{"scope": "read update delete"}`), result)) }
for _, scope := range []domain.Scope{domain.ScopeRead, domain.ScopeUpdate, domain.ScopeDelete} { func TestScopes_MarshalJSON(t *testing.T) {
assert.Contains(t, result.Scope, scope) 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))
} }

View File

@ -28,14 +28,14 @@ type (
Issuer *ClientID Issuer *ClientID
NonceLength int NonceLength int
Scope Scopes Scope Scopes
Secret interface{} Secret []byte
Subject *Me Subject *Me
} }
) )
var DefaultNewTokenOptions = NewTokenOptions{ var DefaultNewTokenOptions = NewTokenOptions{
NonceLength: 32,
Algorithm: "HS256", Algorithm: "HS256",
NonceLength: 32,
} }
func NewToken(opts NewTokenOptions) (*Token, error) { func NewToken(opts NewTokenOptions) (*Token, error) {
@ -83,7 +83,7 @@ func NewToken(opts NewTokenOptions) (*Token, error) {
func TestToken(tb testing.TB) *Token { func TestToken(tb testing.TB) *Token {
tb.Helper() tb.Helper()
nonce, err := random.String(42) nonce, err := random.String(22)
require.NoError(tb, err) require.NoError(tb, err)
t := jwt.New() t := jwt.New()
@ -98,7 +98,7 @@ func TestToken(tb testing.TB) *Token {
// NOTE(toby3d): required // NOTE(toby3d): required
t.Set(jwt.IssuerKey, cid.String()) 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) // TODO(toby3d): t.Set(jwt.AudienceKey, nil)
t.Set(jwt.ExpirationKey, now.Add(1*time.Hour)) t.Set(jwt.ExpirationKey, now.Add(1*time.Hour))
t.Set(jwt.NotBeforeKey, 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. // 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 == "" { if t.AccessToken == "" {
return return
} }
@ -129,7 +129,7 @@ func (t *Token) SetAuthHeader(r *http.Request) {
r.Header.Set(http.HeaderAuthorization, t.String()) r.Header.Set(http.HeaderAuthorization, t.String())
} }
func (t *Token) String() string { func (t Token) String() string {
if t.AccessToken == "" { if t.AccessToken == "" {
return "" return ""
} }

View File

@ -61,7 +61,7 @@ func (u *URL) UnmarshalJSON(v []byte) error {
return nil return nil
} }
func (u *URL) URL() *url.URL { func (u URL) URL() *url.URL {
if u.URI == nil { if u.URI == nil {
return nil return nil
} }