diff --git a/internal/auth/delivery/http/auth_http.go b/internal/auth/delivery/http/auth_http.go index dcf15e6..ed1e0c3 100644 --- a/internal/auth/delivery/http/auth_http.go +++ b/internal/auth/delivery/http/auth_http.go @@ -23,16 +23,16 @@ type ( NewHandlerOptions struct { Auth auth.UseCase Clients client.UseCase - Config domain.Config Matcher language.Matcher Profiles profile.UseCase + Config domain.Config } Handler struct { clients client.UseCase - config domain.Config matcher language.Matcher useCase auth.UseCase + config domain.Config } ) diff --git a/internal/auth/usecase.go b/internal/auth/usecase.go index e6c9155..39f8677 100644 --- a/internal/auth/usecase.go +++ b/internal/auth/usecase.go @@ -13,8 +13,8 @@ type ( Me domain.Me RedirectURI *url.URL CodeChallengeMethod domain.CodeChallengeMethod - Scope domain.Scopes CodeChallenge string + Scope domain.Scopes } ExchangeOptions struct { diff --git a/internal/client/repository/http/http_client.go b/internal/client/repository/http/http_client.go index ff10730..ac9a3c5 100644 --- a/internal/client/repository/http/http_client.go +++ b/internal/client/repository/http/http_client.go @@ -83,8 +83,10 @@ func extract(r io.Reader, u *url.URL, dst *domain.Client, header string) { } for _, logo := range httputil.ExtractProperty(bytes.NewReader(body), u, itemType, propertyLogo) { - var logoURL *url.URL - var err error + var ( + logoURL *url.URL + err error + ) switch l := logo.(type) { case string: diff --git a/internal/client/repository/http/http_client_test.go b/internal/client/repository/http/http_client_test.go index c5eb739..d1fb87a 100644 --- a/internal/client/repository/http/http_client_test.go +++ b/internal/client/repository/http/http_client_test.go @@ -73,7 +73,7 @@ func TestGet(t *testing.T) { func testHandler(tb testing.TB, client domain.Client) http.Handler { tb.Helper() - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set(common.HeaderContentType, common.MIMETextHTMLCharsetUTF8) w.Header().Set(common.HeaderLink, `<`+client.RedirectURI[0].String()+`>; rel="redirect_uri"`) fmt.Fprintf(w, testBody, client.Name[0], client.URL[0], client.Logo[0], client.RedirectURI[1]) diff --git a/internal/client/usecase/client_ucase_test.go b/internal/client/usecase/client_ucase_test.go index 6674b8d..808d17c 100644 --- a/internal/client/usecase/client_ucase_test.go +++ b/internal/client/usecase/client_ucase_test.go @@ -22,10 +22,10 @@ func TestDiscovery(t *testing.T) { } for _, tc := range []struct { - name string + expError error in *domain.Client out *domain.Client - expError error + name string }{{ name: "default", in: testClient, diff --git a/internal/common/common.go b/internal/common/common.go index ab0f875..9a5a60f 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -1,5 +1,7 @@ package common +const charsetUTF8 = "charset=UTF-8" + const ( MIMEApplicationForm string = "application/x-www-form-urlencoded" MIMEApplicationJSON string = "application/json" @@ -8,8 +10,6 @@ const ( MIMETextHTMLCharsetUTF8 string = MIMETextHTML + "; " + charsetUTF8 MIMETextPlain string = "text/plain" MIMETextPlainCharsetUTF8 string = MIMETextPlain + "; " + charsetUTF8 - - charsetUTF8 = "charset=UTF-8" ) const ( diff --git a/internal/domain/config.go b/internal/domain/config.go index dc0205e..a9b0f6c 100644 --- a/internal/domain/config.go +++ b/internal/domain/config.go @@ -13,8 +13,8 @@ type ( Config struct { Server ConfigServer `envPrefix:"SERVER_"` Database ConfigDatabase `envPrefix:"DATABASE_"` - Name string `env:"NAME" envDefault:"IndieAuth"` - RunMode string `env:"RUN_MODE" envDefault:"dev"` + Name string `env:"NAME" envDefault:"IndieAuth"` + RunMode string `env:"RUN_MODE" envDefault:"dev"` IndieAuth ConfigIndieAuth `envPrefix:"INDIEAUTH_"` JWT ConfigJWT `envPrefix:"JWT_"` Code ConfigCode `envPrefix:"CODE_"` @@ -23,12 +23,12 @@ type ( ConfigServer struct { CertificateFile string `env:"CERT_FILE"` - Domain string `env:"DOMAIN" envDefault:"localhost"` - Host string `env:"HOST" envDefault:"0.0.0.0"` + Domain string `env:"DOMAIN" envDefault:"localhost"` + Host string `env:"HOST" envDefault:"0.0.0.0"` KeyFile string `env:"KEY_FILE"` - Port string `env:"PORT" envDefault:"3000"` - Protocol string `env:"PROTOCOL" envDefault:"http"` - RootURL string `env:"ROOT_URL" envDefault:"{{protocol}}://{{domain}}:{{port}}/"` + Port string `env:"PORT" envDefault:"3000"` + Protocol string `env:"PROTOCOL" envDefault:"http"` + RootURL string `env:"ROOT_URL" envDefault:"{{protocol}}://{{domain}}:{{port}}/"` } ConfigDatabase struct { @@ -45,16 +45,16 @@ type ( } ConfigJWT struct { - Algorithm string `env:"ALGORITHM" envDefault:"HS256"` + Algorithm string `env:"ALGORITHM" envDefault:"HS256"` Secret string `env:"SECRET"` - Expiry time.Duration `env:"EXPIRY" envDefault:"1h"` + Expiry time.Duration `env:"EXPIRY" envDefault:"1h"` NonceLength uint8 `env:"NONCE_LENGTH" envDefault:"22"` } ConfigIndieAuth struct { Password string `env:"PASSWORD"` Username string `env:"USERNAME"` - Enabled bool `env:"ENABLED" envDefault:"true"` // true + Enabled bool `env:"ENABLED" envDefault:"true"` // true } ConfigTicketAuth struct { @@ -64,7 +64,7 @@ type ( ConfigRelMeAuth struct { Providers []ConfigRelMeAuthProvider `envPrefix:"PROVIDERS_"` - Enabled bool `env:"ENABLED" envDefault:"true"` // true + Enabled bool `env:"ENABLED" envDefault:"true"` // true } ConfigRelMeAuthProvider struct { diff --git a/internal/domain/error.go b/internal/domain/error.go index 48b2434..6844c04 100644 --- a/internal/domain/error.go +++ b/internal/domain/error.go @@ -15,8 +15,6 @@ type ( // Error describes the format of a typical IndieAuth error. //nolint:tagliatelle // RFC 6749 section 5.2 Error struct { - frame xerrors.Frame `json:"-"` - // A single error code. Code ErrorCode `json:"error"` @@ -33,6 +31,8 @@ type ( // authorization request. The exact value received from the // client. State string `json:"-"` + + frame xerrors.Frame `json:"-"` } // ErrorCode represent error code described in RFC 6749. @@ -135,7 +135,9 @@ var ( // // RFC 6749 section 4.1.2.1: The authorization server does not support // obtaining an authorization code using this method. - ErrorCodeUnsupportedResponseType = ErrorCode{errorCode: "unsupported_response_type"} // "unsupported_response_type" + ErrorCodeUnsupportedResponseType = ErrorCode{ + errorCode: "unsupported_response_type", + } // "unsupported_response_type" // ErrorCodeInvalidToken describes the invalid_token error code. // diff --git a/internal/domain/metadata.go b/internal/domain/metadata.go index e1fac9f..4995012 100644 --- a/internal/domain/metadata.go +++ b/internal/domain/metadata.go @@ -60,8 +60,7 @@ type Metadata struct { GrantTypesSupported []GrantType // JSON array containing the methods supported for PKCE. This parameter - // parameter differs from RFC8414 in that it is not optional as PKCE is - // REQUIRED. + // differs from RFC8414 in that it is not optional as PKCE is REQUIRED. CodeChallengeMethodsSupported []CodeChallengeMethod // List of client authentication methods supported by this introspection endpoint. diff --git a/internal/domain/provider.go b/internal/domain/provider.go index bb37d9b..0b72525 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -8,7 +8,6 @@ import ( // Provider represent 3rd party RelMeAuth provider. type Provider struct { - Scopes []string AuthURL string ClientID string ClientSecret string @@ -18,6 +17,7 @@ type Provider struct { TokenURL string UID string URL string + Scopes []string } //nolint:gochecknoglobals // structs cannot be contants @@ -95,6 +95,8 @@ func (p Provider) AuthCodeURL(state string) string { return "" } + q := u.Query() + for key, val := range map[string]string{ "client_id": p.ClientID, "redirect_uri": p.RedirectURL, @@ -102,8 +104,10 @@ func (p Provider) AuthCodeURL(state string) string { "scope": strings.Join(p.Scopes, " "), "state": state, } { - u.Query().Set(key, val) + q.Set(key, val) } + u.RawQuery = q.Encode() + return u.String() } diff --git a/internal/domain/session.go b/internal/domain/session.go index a8f7e37..fbf34c5 100644 --- a/internal/domain/session.go +++ b/internal/domain/session.go @@ -13,10 +13,10 @@ type Session struct { RedirectURI *url.URL `json:"redirect_uri"` Me Me `json:"me"` Profile *Profile `json:"profile,omitempty"` - Scope Scopes `json:"scope"` CodeChallengeMethod CodeChallengeMethod `json:"code_challenge_method,omitempty"` CodeChallenge string `json:"code_challenge,omitempty"` Code string `json:"-"` + Scope Scopes `json:"scope"` } // TestSession returns valid random generated session for tests. diff --git a/internal/domain/token.go b/internal/domain/token.go index 1d71e1d..a656d9c 100644 --- a/internal/domain/token.go +++ b/internal/domain/token.go @@ -20,19 +20,19 @@ type ( Expiry time.Time ClientID ClientID Me Me - Scope Scopes AccessToken string RefreshToken string + Scope Scopes } // NewTokenOptions contains options for NewToken function. NewTokenOptions struct { - Expiration time.Duration Issuer ClientID Subject Me + Algorithm string Scope Scopes Secret []byte - Algorithm string + Expiration time.Duration NonceLength uint8 } ) diff --git a/internal/httputil/httputil.go b/internal/httputil/httputil.go index 1975704..212c1f1 100644 --- a/internal/httputil/httputil.go +++ b/internal/httputil/httputil.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "net/http" "net/url" "strings" @@ -37,7 +36,7 @@ func ExtractFromMetadata(client *http.Client, u string) (*domain.Metadata, error return nil, err } - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } diff --git a/internal/httputil/httputil_test.go b/internal/httputil/httputil_test.go index 065e285..2bb8f74 100644 --- a/internal/httputil/httputil_test.go +++ b/internal/httputil/httputil_test.go @@ -1,7 +1,7 @@ package httputil_test import ( - "io/ioutil" + "io" "net/http" "net/url" "strings" @@ -32,10 +32,7 @@ func TestExtractEndpointsFromBody(t *testing.T) { t.Fatal(err) } - in := &http.Response{ - Body: ioutil.NopCloser(strings.NewReader(testBody)), - Request: req, - } + in := &http.Response{Body: io.NopCloser(strings.NewReader(testBody))} out, err := httputil.ExtractEndpointsFromBody(in.Body, req.URL, "lipsum") if err != nil { @@ -60,10 +57,7 @@ func TestExtractProperty(t *testing.T) { t.Fatal(err) } - in := &http.Response{ - Body: ioutil.NopCloser(strings.NewReader(testBody)), - Request: req, - } + in := &http.Response{Body: io.NopCloser(strings.NewReader(testBody))} if out := httputil.ExtractProperty(in.Body, req.URL, "h-app", "name"); out == nil || out[0] != "Sample Name" { t.Errorf(`ExtractProperty(%s, %s, %s) = %+s, want %+s`, req.URL, "h-app", "name", out, diff --git a/internal/metadata/repository/http/http_metadata_test.go b/internal/metadata/repository/http/http_metadata_test.go index 3da05e4..a147f7e 100644 --- a/internal/metadata/repository/http/http_metadata_test.go +++ b/internal/metadata/repository/http/http_metadata_test.go @@ -55,10 +55,10 @@ func TestGet(t *testing.T) { testMetadata := domain.TestMetadata(t) for _, tc := range []struct { - name string header map[string]string body map[string]string out *domain.Metadata + name string }{ { name: "header", @@ -83,11 +83,11 @@ func TestGet(t *testing.T) { t.Parallel() mux := http.NewServeMux() - mux.HandleFunc("/metadata", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/metadata", func(w http.ResponseWriter, _ *http.Request) { w.Header().Set(common.HeaderContentType, common.MIMEApplicationJSONCharsetUTF8) _ = json.NewEncoder(w).Encode(NewResponse(t, *testMetadata)) }) - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) { links := make([]string, 0) for k, v := range tc.header { links = append(links, `<`+v+`>; rel="`+k+`"`) @@ -170,14 +170,11 @@ func NewResponse(tb testing.TB, src domain.Metadata) *Response { out.ScopesSupported = append(out.ScopesSupported, scope.String()) } - for _, method := range src.IntrospectionEndpointAuthMethodsSupported { - out.IntrospectionEndpointAuthMethodsSupported = append(out.IntrospectionEndpointAuthMethodsSupported, - method) - } + out.IntrospectionEndpointAuthMethodsSupported = append(out.IntrospectionEndpointAuthMethodsSupported, + src.IntrospectionEndpointAuthMethodsSupported...) - for _, method := range src.RevocationEndpointAuthMethodsSupported { - out.RevocationEndpointAuthMethodsSupported = append(out.RevocationEndpointAuthMethodsSupported, method) - } + out.RevocationEndpointAuthMethodsSupported = append(out.RevocationEndpointAuthMethodsSupported, + src.RevocationEndpointAuthMethodsSupported...) return out } diff --git a/internal/middleware/basic_auth.go b/internal/middleware/basic_auth.go index 43ecad8..b5c7427 100644 --- a/internal/middleware/basic_auth.go +++ b/internal/middleware/basic_auth.go @@ -23,7 +23,7 @@ const DefaultRealm string = "Restricted" const basic string = "basic" -// nolint: gochecknoglobals +//nolint:gochecknoglobals var DefaultBasicAuthConfig = BasicAuthConfig{ Skipper: DefaultSkipper, Realm: DefaultRealm, diff --git a/internal/middleware/extractor.go b/internal/middleware/extractor.go index a9c2d83..ce7380f 100644 --- a/internal/middleware/extractor.go +++ b/internal/middleware/extractor.go @@ -58,7 +58,7 @@ func createExtractors(lookups, authScheme string) ([]ValuesExtractor, error) { for _, source := range sources { parts := strings.Split(source, ":") - if len(parts) < 2 { + if len(parts) <= 1 { return nil, fmt.Errorf("extractor source for lookup could not be split into needed parts: %v", source) } @@ -105,7 +105,7 @@ func valuesFromHeader(header, valuePrefix string) ValuesExtractor { // this header = textproto.CanonicalMIMEHeaderKey(header) - return func(w http.ResponseWriter, r *http.Request) ([]string, error) { + return func(_ http.ResponseWriter, r *http.Request) ([]string, error) { values := r.Header.Values(header) if len(values) == 0 { return nil, errHeaderExtractorValueMissing @@ -147,7 +147,7 @@ func valuesFromHeader(header, valuePrefix string) ValuesExtractor { // valuesFromQuery returns a function that extracts values from the query string. func valuesFromQuery(param string) ValuesExtractor { - return func(w http.ResponseWriter, r *http.Request) ([]string, error) { + return func(_ http.ResponseWriter, r *http.Request) ([]string, error) { result := r.URL.Query()[param] if len(result) == 0 { @@ -162,7 +162,7 @@ func valuesFromQuery(param string) ValuesExtractor { // valuesFromCookie returns a function that extracts values from the named cookie. func valuesFromCookie(name string) ValuesExtractor { - return func(w http.ResponseWriter, r *http.Request) ([]string, error) { + return func(_ http.ResponseWriter, r *http.Request) ([]string, error) { cookies := r.Cookies() if len(cookies) == 0 { return nil, errCookieExtractorValueMissing @@ -190,7 +190,7 @@ func valuesFromCookie(name string) ValuesExtractor { // valuesFromForm returns a function that extracts values from the form field. func valuesFromForm(name string) ValuesExtractor { - return func(w http.ResponseWriter, r *http.Request) ([]string, error) { + return func(_ http.ResponseWriter, r *http.Request) ([]string, error) { if r.Form == nil { _ = r.ParseMultipartForm(32 << 20) // same what `r.FormValue(name)` does } diff --git a/internal/ticket/delivery/http/ticket_http.go b/internal/ticket/delivery/http/ticket_http.go index 486dc93..95f8c55 100644 --- a/internal/ticket/delivery/http/ticket_http.go +++ b/internal/ticket/delivery/http/ticket_http.go @@ -89,7 +89,6 @@ func (h *Handler) handleFunc(w http.ResponseWriter, r *http.Request) { h.handleRender(w, r) case http.MethodPost: - switch head { default: http.NotFound(w, r) diff --git a/internal/ticket/usecase/ticket_ucase.go b/internal/ticket/usecase/ticket_ucase.go index 7439369..4e9e238 100644 --- a/internal/ticket/usecase/ticket_ucase.go +++ b/internal/ticket/usecase/ticket_ucase.go @@ -79,7 +79,7 @@ func (useCase *ticketUseCase) Generate(ctx context.Context, tkt domain.Ticket) e return ticket.ErrTicketEndpointNotExist } - if err := useCase.tickets.Create(ctx, tkt); err != nil { + if err = useCase.tickets.Create(ctx, tkt); err != nil { return fmt.Errorf("cannot save ticket in store: %w", err) } diff --git a/internal/ticket/usecase/ticket_ucase_test.go b/internal/ticket/usecase/ticket_ucase_test.go index a67bc9b..880b84e 100644 --- a/internal/ticket/usecase/ticket_ucase_test.go +++ b/internal/ticket/usecase/ticket_ucase_test.go @@ -36,7 +36,7 @@ func TestRedeem(t *testing.T) { })) t.Cleanup(tokenServer.Close) - subjectServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + subjectServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set(common.HeaderContentType, common.MIMETextHTMLCharsetUTF8) fmt.Fprint(w, ``) })) diff --git a/internal/user/repository/http/http_user.go b/internal/user/repository/http/http_user.go index 9901119..831ac3a 100644 --- a/internal/user/repository/http/http_user.go +++ b/internal/user/repository/http/http_user.go @@ -64,7 +64,8 @@ func (repo *httpUserRepository) Get(ctx context.Context, me domain.Me) (*domain. TokenEndpoint: nil, } - if metadata, err := httputil.ExtractFromMetadata(repo.client, me.String()); err == nil { + var metadata *domain.Metadata + if metadata, err = httputil.ExtractFromMetadata(repo.client, me.String()); err == nil { user.AuthorizationEndpoint = metadata.AuthorizationEndpoint user.Micropub = metadata.MicropubEndpoint user.Microsub = metadata.MicrosubEndpoint @@ -128,8 +129,8 @@ func extractProfile(u *url.URL, dst *domain.Profile, body []byte) { continue } - if u, err := url.Parse(rawURL); err == nil && !containsUrl(dst.URL, u) { - dst.URL = append(dst.URL, u) + if parsedURL, err := url.Parse(rawURL); err == nil && !containsUrl(dst.URL, u) { + dst.URL = append(dst.URL, parsedURL) } } diff --git a/internal/user/repository/http/http_user_test.go b/internal/user/repository/http/http_user_test.go index 9a269d5..34c7aba 100644 --- a/internal/user/repository/http/http_user_test.go +++ b/internal/user/repository/http/http_user_test.go @@ -60,7 +60,7 @@ func testHandler(tb testing.TB, user *domain.User) http.Handler { tb.Helper() mux := http.NewServeMux() - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) { w.Header().Set(common.HeaderLink, strings.Join([]string{ `<` + user.AuthorizationEndpoint.String() + `>; rel="authorization_endpoint"`, `<` + user.IndieAuthMetadata.String() + `>; rel="indieauth-metadata"`, @@ -72,7 +72,7 @@ func testHandler(tb testing.TB, user *domain.User) http.Handler { w.Header().Set(common.HeaderContentType, common.MIMETextHTMLCharsetUTF8) fmt.Fprintf(w, testBody, user.Name[0], user.URL[0].String(), user.Photo[0].String(), user.Email[0]) }) - mux.HandleFunc(user.IndieAuthMetadata.Path, func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc(user.IndieAuthMetadata.Path, func(w http.ResponseWriter, _ *http.Request) { w.Header().Set(common.HeaderContentType, common.MIMEApplicationJSONCharsetUTF8) fmt.Fprint(w, `{ "issuer": "`+user.Me.String()+`",