From a6ffc639a11466698ac51a306656ec5fdba4f9e1 Mon Sep 17 00:00:00 2001 From: William Petit Date: Wed, 20 May 2020 14:07:58 +0200 Subject: [PATCH 01/16] Dokku deployment recipe --- .dockerignore | 5 +++++ Makefile | 23 ++++++++++++++++++++++- misc/containers/hydra/Dockerfile | 3 +++ misc/dokku/passwordless/Dockerfile | 22 ++++++++++++++++++++++ misc/dokku/sso/Dockerfile | 19 +++++++++++++++++++ 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 misc/dokku/passwordless/Dockerfile create mode 100644 misc/dokku/sso/Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4aa0571 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +/release +/data +/bin +/.vscode +/vendor \ No newline at end of file diff --git a/Makefile b/Makefile index 76d5aa7..374e0bd 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,13 @@ +DOKKU_HOST := dokku@dev.lookingfora.name +SHELL := /bin/bash + build: vendor CGO_ENABLED=0 go build -mod=vendor -v -o bin/server ./cmd/server test: go test -v -race ./... -release: +release: vendor @$(SHELL) ./misc/script/release.sh vendor: @@ -46,6 +49,24 @@ hydra-interactive: hydra \ /bin/sh +dokku-build: + docker build \ + -t hydra-passwordless-dokku:latest \ + . + +dokku-run: + docker run -it --rm -p 4444:4444 -p 3002:3002 hydra-passwordless-dokku:latest + +dokku-deploy: dokku-deploy-passwordless dokku-deploy-sso + +dokku-deploy-passwordless: + $(if $(shell git config remote.dokku-passwordless.url),, git remote add dokku-passwordless $(DOKKU_HOST):passwordless) + git push -f dokku-passwordless $(shell git rev-parse HEAD):refs/heads/master + +dokku-deploy-sso: + $(if $(shell git config remote.dokku-sso.url),, git remote add dokku-sso $(DOKKU_HOST):sso) + git push -f dokku-sso $(shell git rev-parse HEAD):refs/heads/master + clean: rm -rf release rm -rf data diff --git a/misc/containers/hydra/Dockerfile b/misc/containers/hydra/Dockerfile index f7eabe6..f511eae 100644 --- a/misc/containers/hydra/Dockerfile +++ b/misc/containers/hydra/Dockerfile @@ -8,9 +8,12 @@ RUN chmod a+x /usr/local/bin/docker-entrypoint COPY first-run.sh /usr/local/bin/docker-first-run RUN chmod a+x /usr/local/bin/docker-first-run +VOLUME /home/ory/.container-lifecycle + RUN mkdir -p /home/ory && chown -R ory: /home/ory USER ory ENTRYPOINT ["/usr/local/bin/docker-entrypoint"] + CMD ["hydra", "serve", "all"] \ No newline at end of file diff --git a/misc/dokku/passwordless/Dockerfile b/misc/dokku/passwordless/Dockerfile new file mode 100644 index 0000000..a58ff53 --- /dev/null +++ b/misc/dokku/passwordless/Dockerfile @@ -0,0 +1,22 @@ +FROM golang:1.13 AS build + +ARG HTTP_PROXY= +ARG HTTPS_PROXY= +ARG http_proxy= +ARG https_proxy= + +RUN apt-get update && apt-get install -y build-essential git bash + +COPY . /src + +WORKDIR /src + +RUN make ARCH_TARGETS=amd64 release + +FROM busybox + +COPY --from=build /src/release/server-linux-amd64 /app + +WORKDIR /app + +CMD ["bin/server", "-workdir", "/app", "-config", "server.yml"] \ No newline at end of file diff --git a/misc/dokku/sso/Dockerfile b/misc/dokku/sso/Dockerfile new file mode 100644 index 0000000..80e0a58 --- /dev/null +++ b/misc/dokku/sso/Dockerfile @@ -0,0 +1,19 @@ +FROM oryd/hydra:v1.4.2-alpine + +USER root + +COPY misc/containers/hydra/docker-entrypoint.sh /usr/local/bin/docker-entrypoint +RUN chmod a+x /usr/local/bin/docker-entrypoint + +COPY misc/containers/hydra/first-run.sh /usr/local/bin/docker-first-run +RUN chmod a+x /usr/local/bin/docker-first-run + +VOLUME /home/ory/.container-lifecycle + +RUN mkdir -p /home/ory && chown -R ory: /home/ory + +USER ory + +ENTRYPOINT ["/usr/local/bin/docker-entrypoint"] + +CMD ["hydra", "serve", "all"] \ No newline at end of file From 389eb3885bddb1f329527010b558fa6144c395e1 Mon Sep 17 00:00:00 2001 From: William Petit Date: Wed, 20 May 2020 19:08:53 +0200 Subject: [PATCH 02/16] Allow configuration overriding with environment variables --- cmd/server/main.go | 6 +++- go.mod | 1 + go.sum | 4 +++ internal/config/config.go | 49 +++++++++++++++++++------------- misc/containers/hydra/Dockerfile | 2 -- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 29f22c7..01a7e04 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -85,6 +85,10 @@ func main() { os.Exit(0) } + if err := config.WithEnvironment(conf); err != nil { + log.Fatalf("%+v", errors.Wrap(err, "could not override config with environment")) + } + // Create service container ctn, err := getServiceContainer(conf) if err != nil { @@ -109,4 +113,4 @@ func main() { if err := http.ListenAndServe(conf.HTTP.Address, r); err != nil { log.Fatalf("%+v", errors.Wrapf(err, "could not listen on '%s'", conf.HTTP.Address)) } -} \ No newline at end of file +} diff --git a/go.mod b/go.mod index 4214f09..b2d3d77 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.14 require ( github.com/PuerkitoBio/goquery v1.5.1 // indirect github.com/aymerick/douceur v0.2.0 + github.com/caarlos0/env/v6 v6.2.2 github.com/coreos/go-oidc v2.2.1+incompatible // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5 // indirect diff --git a/go.sum b/go.sum index d8bb659..7d51295 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,9 @@ github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5z github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs= +github.com/caarlos0/env/v6 v6.2.2 h1:R0NIFXaB/LhwuGrjnsldzpnVNjFU/U+hTVHt+cq0yDY= +github.com/caarlos0/env/v6 v6.2.2/go.mod h1:3LpmfcAYCG6gCiSgDLaFR5Km1FRpPwFvBbRcjHar6Sw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= @@ -132,6 +135,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= gitlab.com/wpetit/goweb v0.0.0-20200418152305-76dea96a46ce h1:B3inZUHFr/FpA3jb+ZeSSHk3FSpB0xkQ0TjePhRokxw= diff --git a/internal/config/config.go b/internal/config/config.go index 50aca7c..d12e6b0 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -7,6 +7,7 @@ import ( "github.com/pkg/errors" + "github.com/caarlos0/env/v6" "gopkg.in/yaml.v2" ) @@ -33,32 +34,32 @@ func NewFromFile(filepath string) (*Config, error) { } type HTTPConfig struct { - Address string `yaml:"address"` - CookieAuthenticationKey string `yaml:"cookieAuthenticationKey"` - CookieEncryptionKey string `yaml:"cookieEncryptionKey"` - TokenSigningKey string `yaml:"tokenSigningKey"` - TokenEncryptionKey string `yaml:"tokenEncryptionKey"` - BasePublicURL string `yaml:"basePublicUrl"` - CookieMaxAge int `yaml:"cookieMaxAge"` - TemplateDir string `yaml:"templateDir"` - PublicDir string `yaml:"publicDir"` - PublicAddress string `yaml:"publicAddress"` - PublicScheme string `yaml:"publicScheme"` + Address string `yaml:"address" env:"HTTP_ADDRESS"` + CookieAuthenticationKey string `yaml:"cookieAuthenticationKey" env:"HTTP_COOKIE_AUTHENTICATION_KEY"` + CookieEncryptionKey string `yaml:"cookieEncryptionKey" env:"HTTP_COOKIE_ENCRYPTION_KEY"` + TokenSigningKey string `yaml:"tokenSigningKey" env:"HTTP_TOKEN_SIGNING_KEY"` + TokenEncryptionKey string `yaml:"tokenEncryptionKey" env:"HTTP_TOKEN_ENCRYPTION_KEY"` + BasePublicURL string `yaml:"basePublicUrl" env:"HTTP_BASE_PUBLIC_URL"` + CookieMaxAge int `yaml:"cookieMaxAge" env:"HTTP_COOKIE_MAX_AGE"` + TemplateDir string `yaml:"templateDir" env:"HTTP_TEMPLATE_DIR"` + PublicDir string `yaml:"publicDir" env:"HTTP_PUBLIC_DIR"` + PublicAddress string `yaml:"publicAddress" env:"HTTP_PUBLIC_ADDRESS"` + PublicScheme string `yaml:"publicScheme" env:"HTTP_PUBLIC_SCHEME"` } type SMTPConfig struct { - Host string `yaml:"host"` - Port int `yaml:"port"` - UseStartTLS bool `yaml:"useStartTLS"` - User string `yaml:"user"` - Password string `yaml:"password"` - InsecureSkipVerify bool `yaml:"insecureSkipVerify"` - SenderAddress string `yaml:"senderAddress"` - SenderName string `yaml:"senderName"` + Host string `yaml:"host" env:"SMTP_HOST"` + Port int `yaml:"port" env:"SMTP_PORT"` + UseStartTLS bool `yaml:"useStartTLS" env:"SMTP_USE_START_TLS"` + User string `yaml:"user" env:"SMTP_USER"` + Password string `yaml:"password" env:"SMTP_PASSWORD"` + InsecureSkipVerify bool `yaml:"insecureSkipVerify" env:"SMTP_INSECURE_SKIP_VERIFY"` + SenderAddress string `yaml:"senderAddress" env:"SMTP_SENDER_ADDRESS"` + SenderName string `yaml:"senderName" env:"SMTP_SENDER_NAME"` } type HydraConfig struct { - BaseURL string `yaml:"baseURL"` + BaseURL string `yaml:"baseURL" env:"HYDRA_BASE_URL"` } func NewDumpDefault() *Config { @@ -106,3 +107,11 @@ func Dump(config *Config, w io.Writer) error { return nil } + +func WithEnvironment(conf *Config) error { + if err := env.Parse(conf); err != nil { + return err + } + + return nil +} diff --git a/misc/containers/hydra/Dockerfile b/misc/containers/hydra/Dockerfile index f511eae..d6d8e65 100644 --- a/misc/containers/hydra/Dockerfile +++ b/misc/containers/hydra/Dockerfile @@ -8,8 +8,6 @@ RUN chmod a+x /usr/local/bin/docker-entrypoint COPY first-run.sh /usr/local/bin/docker-first-run RUN chmod a+x /usr/local/bin/docker-first-run -VOLUME /home/ory/.container-lifecycle - RUN mkdir -p /home/ory && chown -R ory: /home/ory USER ory From 44338f06e3058e199d7f1b74eef99e8e52defd7b Mon Sep 17 00:00:00 2001 From: William Petit Date: Thu, 21 May 2020 13:12:17 +0200 Subject: [PATCH 03/16] Add "fake ssl termination" capability to the hydra client Replicating de "--fake-ssl-termination" option of the official hydra client --- cmd/server/container.go | 10 ++++++++-- internal/config/config.go | 9 ++++++++- internal/hydra/client.go | 23 +++++++++++++++++++---- internal/hydra/provider.go | 4 ++-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/cmd/server/container.go b/cmd/server/container.go index 2feb23b..8c0a9ae 100644 --- a/cmd/server/container.go +++ b/cmd/server/container.go @@ -3,7 +3,6 @@ package main import ( "log" "net/http" - "time" "gitlab.com/wpetit/goweb/cqrs" "gitlab.com/wpetit/goweb/template/html" @@ -104,7 +103,14 @@ func getServiceContainer(conf *config.Config) (*service.Container, error) { // Create and expose config service provider ctn.Provide(config.ServiceName, config.ServiceProvider(conf)) - ctn.Provide(hydra.ServiceName, hydra.ServiceProvider(conf.Hydra.BaseURL, 30*time.Second)) + ctn.Provide( + hydra.ServiceName, + hydra.ServiceProvider( + conf.Hydra.BaseURL, + conf.Hydra.FakeSSLTermination, + conf.Hydra.HTTPClientTimeout, + ), + ) ctn.Provide(mail.ServiceName, mail.ServiceProvider( mail.WithServer(conf.SMTP.Host, conf.SMTP.Port), diff --git a/internal/config/config.go b/internal/config/config.go index d12e6b0..5c76227 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -60,6 +60,11 @@ type SMTPConfig struct { type HydraConfig struct { BaseURL string `yaml:"baseURL" env:"HYDRA_BASE_URL"` + // Fake upstream SSL termination adding the "X-Forwarded-Proto: https" to the OIDC client + // HTTP request headers. + // Required by ory/hydra in some networks topologies + FakeSSLTermination bool `yaml:"fakeSSLTermination" env:"HYDRA_FAKE_SSL_TERMINATION"` + HTTPClientTimeout time.Duration `yaml:"httpClientTimeout" env:"HYDRA_HTTP_CLIENT_TIMEOUT"` } func NewDumpDefault() *Config { @@ -90,7 +95,9 @@ func NewDefault() *Config { SenderName: "noreply", }, Hydra: HydraConfig{ - BaseURL: "http://localhost:4445/", + BaseURL: "http://localhost:4445/", + FakeSSLTermination: false, + HTTPClientTimeout: time.Second * 30, //nolint: gomnb }, } } diff --git a/internal/hydra/client.go b/internal/hydra/client.go index 4dc5c16..50050ee 100644 --- a/internal/hydra/client.go +++ b/internal/hydra/client.go @@ -188,11 +188,26 @@ func fromURL(url url.URL, path string, query url.Values) string { return url.String() } -func NewClient(baseURL *url.URL, httpTimeout time.Duration) *Client { +type fakeSSLTerminationTransport struct { + T http.RoundTripper +} + +func (t *fakeSSLTerminationTransport) RoundTrip(req *http.Request) (*http.Response, error) { + req.Header.Add("X-Forwarded-Proto", "https") + return t.T.RoundTrip(req) +} + +func NewClient(baseURL *url.URL, fakeSSLTermination bool, httpTimeout time.Duration) *Client { + httpClient := &http.Client{ + Timeout: httpTimeout, + } + + if fakeSSLTermination { + httpClient.Transport = &fakeSSLTerminationTransport{http.DefaultTransport} + } + return &Client{ baseURL: baseURL, - http: &http.Client{ - Timeout: 30 * time.Second, - }, + http: httpClient, } } diff --git a/internal/hydra/provider.go b/internal/hydra/provider.go index 195038e..63df1ee 100644 --- a/internal/hydra/provider.go +++ b/internal/hydra/provider.go @@ -8,7 +8,7 @@ import ( "gitlab.com/wpetit/goweb/service" ) -func ServiceProvider(rawBaseURL string, httpTimeout time.Duration) service.Provider { +func ServiceProvider(rawBaseURL string, fakeSSLTermination bool, httpTimeout time.Duration) service.Provider { var ( baseURL *url.URL err error @@ -19,7 +19,7 @@ func ServiceProvider(rawBaseURL string, httpTimeout time.Duration) service.Provi err = errors.Wrap(err, "could not parse base url") } - client := NewClient(baseURL, httpTimeout) + client := NewClient(baseURL, fakeSSLTermination, httpTimeout) return func(ctn *service.Container) (interface{}, error) { if err != nil { From 2851c879b6960a0e10fa6d72c20c33ffc63faa63 Mon Sep 17 00:00:00 2001 From: William Petit Date: Tue, 26 May 2020 11:11:53 +0200 Subject: [PATCH 04/16] Basic logout flow and better UX --- Makefile | 4 +- .../template/layouts/email_sent.html.tmpl | 2 +- cmd/server/template/layouts/error.html.tmpl | 20 ++++++ cmd/server/template/layouts/home.html.tmpl | 22 +++++++ cmd/server/template/layouts/login.html.tmpl | 10 ++- .../layouts/verification_email.html.tmpl | 4 +- docker-compose.yml | 4 ++ internal/command/send_confirmation_email.go | 13 ++-- internal/hydra/client.go | 52 ++++++++++++++- internal/hydra/request.go | 11 ++-- internal/hydra/response.go | 5 ++ internal/query/verify_user.go | 12 ++-- internal/route/consent.go | 43 ++++-------- internal/route/helper.go | 18 +++++ internal/route/home.go | 20 ++++++ internal/route/login.go | 66 ++++++++++++++----- internal/route/logout.go | 28 ++++++++ internal/route/mount.go | 2 +- internal/route/verify.go | 19 +++++- internal/token/generate.go | 8 ++- internal/token/verify.go | 10 +-- 21 files changed, 298 insertions(+), 75 deletions(-) create mode 100644 cmd/server/template/layouts/error.html.tmpl create mode 100644 cmd/server/template/layouts/home.html.tmpl create mode 100644 internal/route/home.go diff --git a/Makefile b/Makefile index 374e0bd..d3b07b4 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,9 @@ create-default-client: hydra \ hydra clients create \ -c http://localhost:3002/oauth2/callback \ - --post-logout-callbacks http://localhost:3002 + --post-logout-callbacks http://localhost:3002 \ + -n "Default App" \ + -a "openid" -a "email" list-clients: diff --git a/cmd/server/template/layouts/email_sent.html.tmpl b/cmd/server/template/layouts/email_sent.html.tmpl index b7923b4..a5e4640 100644 --- a/cmd/server/template/layouts/email_sent.html.tmpl +++ b/cmd/server/template/layouts/email_sent.html.tmpl @@ -1,4 +1,4 @@ -{{define "title"}}Connexion{{end}} +{{define "title"}}Courriel envoyé.{{end}} {{define "body"}}
diff --git a/cmd/server/template/layouts/error.html.tmpl b/cmd/server/template/layouts/error.html.tmpl new file mode 100644 index 0000000..c2f1a7c --- /dev/null +++ b/cmd/server/template/layouts/error.html.tmpl @@ -0,0 +1,20 @@ +{{define "title"}}Erreur{{end}} +{{define "body"}} +
+
+
+
+
+
+
+

{{ .ErrorTitle }}

+

{{ .ErrorDescription }}

+
+
+
+
+
+
+
+{{end}} +{{template "base" .}} \ No newline at end of file diff --git a/cmd/server/template/layouts/home.html.tmpl b/cmd/server/template/layouts/home.html.tmpl new file mode 100644 index 0000000..dacdfe3 --- /dev/null +++ b/cmd/server/template/layouts/home.html.tmpl @@ -0,0 +1,22 @@ +{{define "title"}}Connexion{{end}} +{{define "body"}} +
+
+
+
+
+

+ Hydra Passwordless +

+

+ Version: {{ .BuildInfo.ProjectVersion }} | + Réf.: {{ .BuildInfo.GitRef }} | + Date de construction: {{ .BuildInfo.BuildDate }} +

+
+
+
+
+
+{{end}} +{{template "base" .}} \ No newline at end of file diff --git a/cmd/server/template/layouts/login.html.tmpl b/cmd/server/template/layouts/login.html.tmpl index 3777b93..b695b82 100644 --- a/cmd/server/template/layouts/login.html.tmpl +++ b/cmd/server/template/layouts/login.html.tmpl @@ -7,7 +7,7 @@
{{template "flash" .}}

- Connexion + Connexion à {{ .ClientName }}

Veuillez entrer votre adresse courriel. @@ -21,6 +21,14 @@ name="email" placeholder="john.doe@email.com" />

+
+

+ +

+
{{ .csrfField }} diff --git a/cmd/server/template/layouts/verification_email.html.tmpl b/cmd/server/template/layouts/verification_email.html.tmpl index fce611d..2890fb4 100644 --- a/cmd/server/template/layouts/verification_email.html.tmpl +++ b/cmd/server/template/layouts/verification_email.html.tmpl @@ -4,8 +4,8 @@
-

Bonjour {{ .Email }}

-

Vous avez demandé à accéder à l'application "{{ .AppTitle }}". Cliquez sur le lien ci dessous pour vous authentifier.

+

Bonjour,

+

Vous avez demandé à accéder à l'application "{{ .ClientName }}". Cliquez sur le lien ci dessous pour vous authentifier.

diff --git a/docker-compose.yml b/docker-compose.yml index 6b532d6..cf672a5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,6 +16,10 @@ services: DSN: mysql://hydra:hydra@tcp(mysql:3306)/hydra URLS_LOGIN: http://localhost:3000/login URLS_CONSENT: http://localhost:3000/consent + URLS_LOGOUT: http://localhost:3000/logout + SUPPORTED_SCOPES: email + SUPPORTED_CLAIMS: email,email_verified + SECRETS_SYSTEM: fAAya66yXNib52lbXpo16bxy1jD4NZrX ports: - 4444:4444 - 4445:4445 diff --git a/internal/command/send_confirmation_email.go b/internal/command/send_confirmation_email.go index 7552169..3c0b098 100644 --- a/internal/command/send_confirmation_email.go +++ b/internal/command/send_confirmation_email.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "fmt" - "log" "forge.cadoles.com/wpetit/hydra-passwordless/internal/config" "forge.cadoles.com/wpetit/hydra-passwordless/internal/hydra" @@ -23,6 +22,9 @@ type SendConfirmationEmailRequest struct { Challenge string DefaultScheme string DefaultAddress string + RememberMe bool + ClientName string + ClientURI string } func HandleSendConfirmationEmailRequest(ctx context.Context, cmd cqrs.Command) error { @@ -48,6 +50,7 @@ func HandleSendConfirmationEmailRequest(ctx context.Context, cmd cqrs.Command) e conf.HTTP.TokenEncryptionKey, req.Email, req.Challenge, + req.RememberMe, ) if err != nil { return errors.Wrap(err, "could not generate jwt") @@ -67,13 +70,11 @@ func HandleSendConfirmationEmailRequest(ctx context.Context, cmd cqrs.Command) e scheme = conf.HTTP.PublicScheme } - log.Println(req, scheme) - verificationLink := fmt.Sprintf("%s//%s/verify?token=%s", scheme, address, token) - log.Println(verificationLink) - data := template.Data{ + "ClientName": req.ClientName, + "ClientURI": req.ClientURI, "BuildInfo": info, "VerificationLink": verificationLink, } @@ -92,7 +93,7 @@ func HandleSendConfirmationEmailRequest(ctx context.Context, cmd cqrs.Command) e err = ml.Send( mail.WithSender(conf.SMTP.SenderAddress, conf.SMTP.SenderName), mail.WithRecipients(req.Email), - mail.WithSubject(fmt.Sprintf("[Authentification]")), + mail.WithSubject(fmt.Sprintf("[%s] Connexion", req.ClientName)), mail.WithBody(mail.ContentTypeHTML, html, nil), mail.WithAlternativeBody(mail.ContentTypeText, "", nil), ) diff --git a/internal/hydra/client.go b/internal/hydra/client.go index 50050ee..ebcf8e7 100644 --- a/internal/hydra/client.go +++ b/internal/hydra/client.go @@ -70,7 +70,57 @@ func (c *Client) RejectLoginRequest(challenge string, req *RejectRequest) (*Reje } func (c *Client) LogoutRequest(challenge string) (*LogoutResponse, error) { - return nil, nil + u := fromURL(*c.baseURL, "/oauth2/auth/requests/logout", url.Values{ + "logout_challenge": []string{challenge}, + }) + + res, err := c.http.Get(u) + if err != nil { + return nil, errors.Wrap(err, "could not retrieve logout response") + } + + if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest { + return nil, errors.Wrapf(ErrUnexpectedHydraResponse, "hydra responded with status code '%d'", res.StatusCode) + } + + defer res.Body.Close() + + decoder := json.NewDecoder(res.Body) + logoutRes := &LogoutResponse{} + + if err := decoder.Decode(logoutRes); err != nil { + return nil, errors.Wrap(err, "could not decode json response") + } + + return logoutRes, nil +} + +func (c *Client) AcceptLogoutRequest(challenge string) (*AcceptResponse, error) { + u := fromURL(*c.baseURL, "/oauth2/auth/requests/logout/accept", url.Values{ + "logout_challenge": []string{challenge}, + }) + + res := &AcceptResponse{} + + if err := c.putJSON(u, nil, res); err != nil { + return nil, err + } + + return res, nil +} + +func (c *Client) RejectLogoutRequest(challenge string, req *RejectRequest) (*RejectResponse, error) { + u := fromURL(*c.baseURL, "/oauth2/auth/requests/logout/reject", url.Values{ + "logout_challenge": []string{challenge}, + }) + + res := &RejectResponse{} + + if err := c.putJSON(u, req, res); err != nil { + return nil, err + } + + return res, nil } func (c *Client) ConsentRequest(challenge string) (*ConsentResponse, error) { diff --git a/internal/hydra/request.go b/internal/hydra/request.go index 8a1df21..3e59d04 100644 --- a/internal/hydra/request.go +++ b/internal/hydra/request.go @@ -1,12 +1,15 @@ package hydra type AcceptLoginRequest struct { - Subject string `json:"subject"` - Remember bool `json:"remember"` - RememberFor int `json:"remember_for"` - ACR string `json:"acr"` + Subject string `json:"subject"` + Remember bool `json:"remember"` + RememberFor int `json:"remember_for"` + ACR string `json:"acr"` + Context map[string]interface{} `json:"context"` } +type AcceptLogoutRequest struct{} + type AcceptConsentRequest struct { GrantScope []string `json:"grant_scope"` GrantAccessTokenAudience []string `json:"grant_access_token_audience"` diff --git a/internal/hydra/response.go b/internal/hydra/response.go index d5647d2..5f10ded 100644 --- a/internal/hydra/response.go +++ b/internal/hydra/response.go @@ -68,6 +68,10 @@ type RejectResponse struct { } type LogoutResponse struct { + Subject string `json:"subject"` + SessionID string `json:"sid"` + RPInitiated bool `json:"rp_initiated"` + RequestURL string `json:"request_url"` } type ConsentResponse struct { @@ -80,4 +84,5 @@ type ConsentResponse struct { OidcContext OidcContextResponseFragment `json:"oidc_context"` RequestedAccessTokenAudience []string `json:"requested_access_token_audience"` SessionID string `json:"session_id"` + Context map[string]interface{} `json:"context"` } diff --git a/internal/query/verify_user.go b/internal/query/verify_user.go index 1795679..0b46246 100644 --- a/internal/query/verify_user.go +++ b/internal/query/verify_user.go @@ -15,8 +15,9 @@ type VerifyUserRequest struct { } type VerifyUserData struct { - Email string - Challenge string + Email string + Challenge string + RememberMe bool } func HandleVerifyUserRequest(ctx context.Context, qry cqrs.Query) (interface{}, error) { @@ -28,7 +29,7 @@ func HandleVerifyUserRequest(ctx context.Context, qry cqrs.Query) (interface{}, ctn := container.Must(ctx) conf := config.Must(ctn) - email, challenge, err := token.Verify( + email, challenge, rememberMe, err := token.Verify( conf.HTTP.TokenSigningKey, conf.HTTP.TokenEncryptionKey, req.Token, @@ -39,8 +40,9 @@ func HandleVerifyUserRequest(ctx context.Context, qry cqrs.Query) (interface{}, } data := &VerifyUserData{ - Email: email, - Challenge: challenge, + Email: email, + Challenge: challenge, + RememberMe: rememberMe, } return data, nil diff --git a/internal/route/consent.go b/internal/route/consent.go index e2381e5..7ff73a7 100644 --- a/internal/route/consent.go +++ b/internal/route/consent.go @@ -10,7 +10,6 @@ import ( func serveConsentPage(w http.ResponseWriter, r *http.Request) { ctn := container.Must(r.Context()) - //tmpl := template.Must(ctn) hydr := hydra.Must(ctn) challenge, err := hydr.ConsentChallenge(r) @@ -24,43 +23,29 @@ func serveConsentPage(w http.ResponseWriter, r *http.Request) { panic(errors.Wrap(err, "could not retrieve consent challenge")) } - res, err := hydr.ConsentRequest(challenge) + consentRes, err := hydr.ConsentRequest(challenge) if err != nil { panic(errors.Wrap(err, "could not retrieve hydra consent response")) } - if res.Skip { - res, err := hydr.AcceptConsentRequest(challenge, &hydra.AcceptConsentRequest{ - GrantScope: res.RequestedScope, - GrantAccessTokenAudience: res.RequestedAccessTokenAudience, - }) - if err != nil { - panic(errors.Wrap(err, "could not accept hydra consent request")) - } + scopes := []string{"email"} + scopes = append(scopes, consentRes.RequestedScope...) - http.Redirect(w, r, res.RedirectTo, http.StatusTemporaryRedirect) - return + acceptConsentReq := &hydra.AcceptConsentRequest{ + GrantScope: scopes, + GrantAccessTokenAudience: consentRes.RequestedAccessTokenAudience, + Session: hydra.AcceptConsentSession{ + IDToken: map[string]interface{}{ + "email": consentRes.Context["email"], + "email_verified": true, + }, + }, } - res2, err := hydr.AcceptConsentRequest(challenge, &hydra.AcceptConsentRequest{ - GrantScope: res.RequestedScope, - GrantAccessTokenAudience: res.RequestedAccessTokenAudience, - }) + acceptRes, err := hydr.AcceptConsentRequest(challenge, acceptConsentReq) if err != nil { panic(errors.Wrap(err, "could not accept hydra consent request")) } - http.Redirect(w, r, res2.RedirectTo, http.StatusTemporaryRedirect) - - // spew.Dump(res) - - // data := extendTemplateData(w, r, template.Data{ - // csrf.TemplateTag: csrf.TemplateField(r), - // "RequestedScope": res.RequestedScope, - // "ConsentChallenge": challenge, - // }) - - // if err := tmpl.RenderPage(w, "consent.html.tmpl", data); err != nil { - // panic(errors.Wrapf(err, "could not render '%s' page", r.URL.Path)) - // } + http.Redirect(w, r, acceptRes.RedirectTo, http.StatusTemporaryRedirect) } diff --git a/internal/route/helper.go b/internal/route/helper.go index cf7c774..548fe4a 100644 --- a/internal/route/helper.go +++ b/internal/route/helper.go @@ -22,3 +22,21 @@ func extendTemplateData(w http.ResponseWriter, r *http.Request, data template.Da return data } + +func renderErrorPage(w http.ResponseWriter, r *http.Request, statusCode int, title, description string) error { + ctn := container.Must(r.Context()) + tmpl := template.Must(ctn) + + data := extendTemplateData(w, r, template.Data{ + "ErrorTitle": title, + "ErrorDescription": description, + }) + + w.WriteHeader(statusCode) + + if err := tmpl.RenderPage(w, "error.html.tmpl", data); err != nil { + return errors.Wrap(err, "could not render error page") + } + + return nil +} diff --git a/internal/route/home.go b/internal/route/home.go new file mode 100644 index 0000000..5b58e36 --- /dev/null +++ b/internal/route/home.go @@ -0,0 +1,20 @@ +package route + +import ( + "net/http" + + "github.com/pkg/errors" + "gitlab.com/wpetit/goweb/middleware/container" + "gitlab.com/wpetit/goweb/service/template" +) + +func serveHomePage(w http.ResponseWriter, r *http.Request) { + ctn := container.Must(r.Context()) + tmpl := template.Must(ctn) + + data := extendTemplateData(w, r, template.Data{}) + + if err := tmpl.RenderPage(w, "home.html.tmpl", data); err != nil { + panic(errors.Wrapf(err, "could not render '%s' page", r.URL.Path)) + } +} diff --git a/internal/route/login.go b/internal/route/login.go index bb21f3a..1a1fa17 100644 --- a/internal/route/login.go +++ b/internal/route/login.go @@ -21,7 +21,15 @@ func serveLoginPage(w http.ResponseWriter, r *http.Request) { challenge, err := hydr.LoginChallenge(r) if err != nil { if err == hydra.ErrChallengeNotFound { - http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) + err := renderErrorPage( + w, r, + http.StatusBadRequest, + "Requête invalide", + "Certaines informations requises afin de réaliser votre requête sont absentes.", + ) + if err != nil { + panic(errors.Wrapf(err, "could not render '%s' page", r.URL.Path)) + } return } @@ -35,15 +43,20 @@ func serveLoginPage(w http.ResponseWriter, r *http.Request) { } if res.Skip { - res, err := hydr.RejectLoginRequest(challenge, &hydra.RejectRequest{ - Error: "email_not_validated", - ErrorDescription: "The email adress could not be verified.", - }) - if err != nil { - panic(errors.Wrap(err, "could not reject hydra authentication request")) + accept := &hydra.AcceptLoginRequest{ + Subject: res.Subject, + Context: map[string]interface{}{ + "email": res.Subject, + }, } - http.Redirect(w, r, res.RedirectTo, http.StatusTemporaryRedirect) + res, err := hydr.AcceptLoginRequest(challenge, accept) + if err != nil { + panic(errors.Wrap(err, "could not retrieve hydra accept response")) + } + + http.Redirect(w, r, res.RedirectTo, http.StatusSeeOther) + return } @@ -53,6 +66,8 @@ func serveLoginPage(w http.ResponseWriter, r *http.Request) { csrf.TemplateTag: csrf.TemplateField(r), "LoginChallenge": challenge, "Email": "", + "ClientName": res.Client.ClientName, + "ClientURI": res.Client.ClientURI, }) if err := tmpl.RenderPage(w, "login.html.tmpl", data); err != nil { @@ -64,6 +79,7 @@ func handleLoginForm(w http.ResponseWriter, r *http.Request) { ctx := r.Context() ctn := container.Must(ctx) tmpl := template.Must(ctn) + hydr := hydra.Must(ctn) bus := cqrs.Must(ctn) if err := r.ParseForm(); err != nil { @@ -72,9 +88,30 @@ func handleLoginForm(w http.ResponseWriter, r *http.Request) { return } - email := r.Form.Get("email") challenge := r.Form.Get("challenge") + if challenge == "" { + err := renderErrorPage( + w, r, + http.StatusBadRequest, + "Requête invalide", + "Certaines informations requises sont manquantes pour pouvoir réaliser votre requête.", + ) + if err != nil { + panic(errors.Wrapf(err, "could not render '%s' page", r.URL.Path)) + } + + return + } + + res, err := hydr.LoginRequest(challenge) + if err != nil { + panic(errors.Wrap(err, "could not retrieve hydra login response")) + } + + email := r.Form.Get("email") + rememberMe := r.Form.Get("rememberMe") + renderFlashError := func(message string) { sess, err := session.Must(ctn).Get(w, r) if err != nil { @@ -91,6 +128,8 @@ func handleLoginForm(w http.ResponseWriter, r *http.Request) { csrf.TemplateTag: csrf.TemplateField(r), "LoginChallenge": challenge, "Email": email, + "ClientName": res.Client.ClientName, + "ClientURI": res.Client.ClientURI, }) if err := tmpl.RenderPage(w, "login.html.tmpl", data); err != nil { @@ -104,17 +143,14 @@ func handleLoginForm(w http.ResponseWriter, r *http.Request) { return } - if challenge == "" { - http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) - - return - } - cmd := &command.SendConfirmationEmailRequest{ Email: email, Challenge: challenge, DefaultScheme: r.URL.Scheme, DefaultAddress: r.Host, + RememberMe: rememberMe == "on", + ClientName: res.Client.ClientName, + ClientURI: res.Client.ClientURI, } if _, err := bus.Exec(ctx, cmd); err != nil { panic(errors.Wrap(err, "could not execute command")) diff --git a/internal/route/logout.go b/internal/route/logout.go index 204a91e..bf95bde 100644 --- a/internal/route/logout.go +++ b/internal/route/logout.go @@ -2,8 +2,36 @@ package route import ( "net/http" + + "forge.cadoles.com/wpetit/hydra-passwordless/internal/hydra" + "github.com/pkg/errors" + "gitlab.com/wpetit/goweb/middleware/container" ) func serveLogoutPage(w http.ResponseWriter, r *http.Request) { + ctn := container.Must(r.Context()) + hydr := hydra.Must(ctn) + challenge, err := hydr.LogoutChallenge(r) + if err != nil { + if err == hydra.ErrChallengeNotFound { + http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) + + return + } + + panic(errors.Wrap(err, "could not retrieve logout challenge")) + } + + _, err = hydr.LogoutRequest(challenge) + if err != nil { + panic(errors.Wrap(err, "could not retrieve hydra logout response")) + } + + acceptRes, err := hydr.AcceptLogoutRequest(challenge) + if err != nil { + panic(errors.Wrap(err, "could not retrieve hydra accept logout response")) + } + + http.Redirect(w, r, acceptRes.RedirectTo, http.StatusSeeOther) } diff --git a/internal/route/mount.go b/internal/route/mount.go index 9b28ccb..b75583d 100644 --- a/internal/route/mount.go +++ b/internal/route/mount.go @@ -23,7 +23,7 @@ func Mount(r *chi.Mux, config *config.Config) error { r.Group(func(r chi.Router) { r.Use(csrfMiddleware) - + r.Get("/", serveHomePage) r.Get("/login", serveLoginPage) r.Post("/login", handleLoginForm) r.Get("/logout", serveLogoutPage) diff --git a/internal/route/verify.go b/internal/route/verify.go index 70b6cb0..db0a0f6 100644 --- a/internal/route/verify.go +++ b/internal/route/verify.go @@ -32,6 +32,18 @@ func handleVerification(w http.ResponseWriter, r *http.Request) { if err != nil { logger.Error(ctx, "could not verify token", logger.E(err)) + err := renderErrorPage( + w, r, + http.StatusBadRequest, + "Lien invalide", + "Le lien de connexion utilisé est invalide ou a expiré.", + ) + if err != nil { + panic(errors.Wrapf(err, "could not render '%s' page", r.URL.Path)) + } + + return + http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) } @@ -43,7 +55,12 @@ func handleVerification(w http.ResponseWriter, r *http.Request) { hydr := hydra.Must(ctn) accept := &hydra.AcceptLoginRequest{ - Subject: verifyUserData.Email, + Subject: verifyUserData.Email, + Remember: verifyUserData.RememberMe, + RememberFor: 3600, + Context: map[string]interface{}{ + "email": verifyUserData.Email, + }, } res, err := hydr.AcceptLoginRequest(verifyUserData.Challenge, accept) diff --git a/internal/token/generate.go b/internal/token/generate.go index d4d8151..53f5c3f 100644 --- a/internal/token/generate.go +++ b/internal/token/generate.go @@ -11,10 +11,11 @@ const ( ) type privateClaims struct { - Challenge string `json:"challenge"` + Challenge string `json:"challenge"` + RememberMe bool `json:"remember"` } -func Generate(signingKey, encryptionKey, email, challenge string) (string, error) { +func Generate(signingKey, encryptionKey, email, challenge string, rememberMe bool) (string, error) { sig, err := jose.NewSigner( jose.SigningKey{ Algorithm: jose.HS256, @@ -44,7 +45,8 @@ func Generate(signingKey, encryptionKey, email, challenge string) (string, error } privateClaims := privateClaims{ - Challenge: challenge, + Challenge: challenge, + RememberMe: rememberMe, } raw, err := jwt.SignedAndEncrypted(sig, enc).Claims(claims).Claims(privateClaims).CompactSerialize() diff --git a/internal/token/verify.go b/internal/token/verify.go index cd22868..a9315ab 100644 --- a/internal/token/verify.go +++ b/internal/token/verify.go @@ -5,23 +5,23 @@ import ( "gopkg.in/square/go-jose.v2/jwt" ) -func Verify(signingKey, encryptionKey, raw string) (string, string, error) { +func Verify(signingKey, encryptionKey, raw string) (string, string, bool, error) { token, err := jwt.ParseSignedAndEncrypted(raw) if err != nil { - return "", "", errors.Wrap(err, "could not parse token") + return "", "", false, errors.Wrap(err, "could not parse token") } nested, err := token.Decrypt([]byte(encryptionKey)) if err != nil { - return "", "", errors.Wrap(err, "could not decrypt token") + return "", "", false, errors.Wrap(err, "could not decrypt token") } baseClaims := jwt.Claims{} privateClaims := privateClaims{} if err := nested.Claims([]byte(signingKey), &baseClaims, &privateClaims); err != nil { - return "", "", errors.Wrap(err, "could not validate claims") + return "", "", false, errors.Wrap(err, "could not validate claims") } - return baseClaims.Subject, privateClaims.Challenge, nil + return baseClaims.Subject, privateClaims.Challenge, privateClaims.RememberMe, nil } From a13caf3e4d64ede091214f1ab7c9975c458bd75c Mon Sep 17 00:00:00 2001 From: William Petit Date: Wed, 17 Jun 2020 23:46:44 +0200 Subject: [PATCH 05/16] Remove default SMTP password --- internal/config/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 5c76227..8769d5c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -89,8 +89,8 @@ func NewDefault() *Config { SMTP: SMTPConfig{ Host: "localhost", Port: 2525, - User: "hydra-passwordless", - Password: "hydra-passwordless", + User: "", + Password: "", SenderAddress: "noreply@localhost", SenderName: "noreply", }, From 3a1d08661b554c5bbd923ca3f366efc5cbe1f2bd Mon Sep 17 00:00:00 2001 From: William Petit Date: Wed, 17 Jun 2020 23:47:49 +0200 Subject: [PATCH 06/16] Add Docker Hub packaging tasks --- Makefile | 23 +++++++++++++++++++++++ misc/docker/Dockerfile | 24 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 misc/docker/Dockerfile diff --git a/Makefile b/Makefile index d3b07b4..23b1008 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ DOKKU_HOST := dokku@dev.lookingfora.name SHELL := /bin/bash +DOCKER_IMAGE_NAME ?= bornholm/hydra-passwordless +DOCKER_IMAGE_TAG ?= latest build: vendor CGO_ENABLED=0 go build -mod=vendor -v -o bin/server ./cmd/server @@ -69,6 +71,27 @@ dokku-deploy-sso: $(if $(shell git config remote.dokku-sso.url),, git remote add dokku-sso $(DOKKU_HOST):sso) git push -f dokku-sso $(shell git rev-parse HEAD):refs/heads/master +docker-build: + docker build \ + --build-arg="HTTP_PROXY=$(HTTP_PROXY)" \ + --build-arg="HTTPS_PROXY=${HTTP_PROXY}" \ + --build-arg="https_proxy=${https_proxy}" \ + --build-arg="http_proxy=${http_proxy}" \ + -t hydra-passwordless:latest \ + -f ./misc/docker/Dockerfile \ + . + +docker-run: + docker run \ + -it --rm \ + -p 3000:3000 \ + hydra-passwordless:latest + +docker-release: docker-build + docker image tag hydra-passwordless:latest $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG) + docker login + docker push $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG) + clean: rm -rf release rm -rf data diff --git a/misc/docker/Dockerfile b/misc/docker/Dockerfile new file mode 100644 index 0000000..10190a7 --- /dev/null +++ b/misc/docker/Dockerfile @@ -0,0 +1,24 @@ +FROM golang:1.14 AS build + +ARG HTTP_PROXY= +ARG HTTPS_PROXY= +ARG http_proxy= +ARG https_proxy= + +RUN apt-get update && apt-get install -y build-essential git bash + +COPY . /src + +WORKDIR /src + +RUN make ARCH_TARGETS=amd64 release + +FROM busybox + +COPY --from=build /src/release/server-linux-amd64 /app + +WORKDIR /app + +EXPOSE 3000 + +CMD ["bin/server", "-workdir", "/app", "-config", "server.yml"] \ No newline at end of file From 754922b2503ca8569df7c3c4de7d1709c01c413b Mon Sep 17 00:00:00 2001 From: William Petit Date: Thu, 9 Jul 2020 14:00:17 +0200 Subject: [PATCH 07/16] Generate pseudo-random Message-Id header for each outgoing emails --- internal/mail/send.go | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/internal/mail/send.go b/internal/mail/send.go index 05da094..38a00eb 100644 --- a/internal/mail/send.go +++ b/internal/mail/send.go @@ -2,11 +2,21 @@ package mail import ( "crypto/tls" + "fmt" + "math/rand" + "net/mail" + "strconv" + "strings" + "time" "github.com/pkg/errors" gomail "gopkg.in/mail.v2" ) +var ( + ErrUnexpectedEmailAddressFormat = errors.New("unexpected email address format") +) + type SendFunc func(*SendOption) type SendOption struct { @@ -124,6 +134,20 @@ func (m *Mailer) Send(funcs ...SendFunc) error { message.SetHeader(h.Field, h.Values...) } + froms := message.GetHeader("From") + + var sendDomain string + + if len(froms) > 0 { + sendDomain, err = extractEmailDomain(froms[0]) + if err != nil { + return err + } + } + + messageID := generateMessageID(sendDomain) + message.SetHeader("Message-Id", messageID) + message.SetBody(opt.Body.Type, opt.Body.Content, opt.Body.PartSetting) for _, b := range opt.AlternativeBodies { @@ -158,3 +182,26 @@ func (m *Mailer) openConnection() (gomail.SendCloser, error) { return conn, nil } + +func extractEmailDomain(email string) (string, error) { + address, err := mail.ParseAddress(email) + if err != nil { + return "", errors.Wrapf(err, "could not parse email address '%s'", email) + } + + addressParts := strings.SplitN(address.Address, "@", 2) + if len(addressParts) != 2 { // nolint: gomnd + return "", errors.WithStack(ErrUnexpectedEmailAddressFormat) + } + + domain := addressParts[1] + + return domain, nil +} + +func generateMessageID(domain string) string { + // Based on https://www.jwz.org/doc/mid.html + timestamp := strconv.FormatInt(time.Now().UnixNano(), 36) + random := strconv.FormatInt(rand.Int63(), 36) + return fmt.Sprintf("<%s.%s@%s>", timestamp, random, domain) +} From 31019c5138d1884e63ea6c4a83777eca2bf288db Mon Sep 17 00:00:00 2001 From: William Petit Date: Thu, 9 Jul 2020 16:40:14 +0200 Subject: [PATCH 08/16] Hide Hydra login request errors to the end user --- internal/route/verify.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/internal/route/verify.go b/internal/route/verify.go index db0a0f6..149b788 100644 --- a/internal/route/verify.go +++ b/internal/route/verify.go @@ -43,8 +43,6 @@ func handleVerification(w http.ResponseWriter, r *http.Request) { } return - - http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) } verifyUserData, ok := result.Data().(*query.VerifyUserData) @@ -65,7 +63,19 @@ func handleVerification(w http.ResponseWriter, r *http.Request) { res, err := hydr.AcceptLoginRequest(verifyUserData.Challenge, accept) if err != nil { - panic(errors.Wrap(err, "could not retrieve hydra accept response")) + logger.Error(ctx, "could not retrieve hydra accept response", logger.E(err)) + + err := renderErrorPage( + w, r, + http.StatusBadRequest, + "Lien invalide", + "Le lien de connexion utilisé est invalide ou a expiré.", + ) + if err != nil { + panic(errors.Wrapf(err, "could not render '%s' page", r.URL.Path)) + } + + return } http.Redirect(w, r, res.RedirectTo, http.StatusSeeOther) From f47fbcf39ad518171d837b2c055914ccf348aa9b Mon Sep 17 00:00:00 2001 From: William Petit Date: Thu, 9 Jul 2020 16:41:01 +0200 Subject: [PATCH 09/16] Update dependencies --- go.mod | 5 ----- go.sum | 16 +++++++++------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index b2d3d77..08b9e95 100644 --- a/go.mod +++ b/go.mod @@ -6,17 +6,12 @@ require ( github.com/PuerkitoBio/goquery v1.5.1 // indirect github.com/aymerick/douceur v0.2.0 github.com/caarlos0/env/v6 v6.2.2 - github.com/coreos/go-oidc v2.2.1+incompatible // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5 // indirect github.com/go-chi/chi v4.1.0+incompatible github.com/gorilla/csrf v1.6.2 github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/sessions v1.2.0 github.com/pkg/errors v0.9.1 - github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect gitlab.com/wpetit/goweb v0.0.0-20200418152305-76dea96a46ce - golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/mail.v2 v2.3.1 gopkg.in/square/go-jose.v2 v2.5.1 diff --git a/go.sum b/go.sum index 7d51295..1448d74 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,7 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.49.0 h1:CH+lkubJzcPYB1Ggupcq0+k8Ni2ILdG2lYjDIgavDBQ= cloud.google.com/go v0.49.0/go.mod h1:hGvAdzcWNbyuxS3nWhD7H2cIJxjRRTRLQVB0bdputVY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -20,33 +21,31 @@ github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtix github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= github.com/alecthomas/chroma v0.7.0 h1:z+0HgTUmkpRDRz0SRSdMaqOLfJV4F+N1FPDZUZIDUzw= github.com/alecthomas/chroma v0.7.0/go.mod h1:1U/PfCsTALWWYHDnsIQkxEBM0+6LLe0v8+RSVMOwxeY= +github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo= github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= github.com/alecthomas/kong v0.1.17-0.20190424132513-439c674f7ae0/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= github.com/alecthomas/kong-hcl v0.1.8-0.20190615233001-b21fea9723c8/go.mod h1:MRgZdU3vrFd05IQ89AxUZ0aYdF39BYoNFa324SodPCA= +github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY= github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs= github.com/caarlos0/env/v6 v6.2.2 h1:R0NIFXaB/LhwuGrjnsldzpnVNjFU/U+hTVHt+cq0yDY= github.com/caarlos0/env/v6 v6.2.2/go.mod h1:3LpmfcAYCG6gCiSgDLaFR5Km1FRpPwFvBbRcjHar6Sw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= -github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5 h1:RAV05c0xOkJ3dZGS0JFybxFKZ2WMLabgx3uXnd7rpGs= -github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4= github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= @@ -60,6 +59,7 @@ github.com/go-chi/chi v4.1.0+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxm github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE= @@ -125,16 +125,16 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU= -github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -248,11 +248,13 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1 h1:aQktFqmDE2yjveXJlVIfslDFmFnUXSqG0i6KRcJAeMc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= From a0677f23e557fa9884cae20704077427bef4b5b4 Mon Sep 17 00:00:00 2001 From: William Petit Date: Tue, 8 Sep 2020 11:38:38 +0200 Subject: [PATCH 10/16] Allow remember be duration to be customized via config --- internal/config/config.go | 16 +++++++++++++--- internal/route/verify.go | 9 ++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 8769d5c..26deabb 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -12,9 +12,10 @@ import ( ) type Config struct { - HTTP HTTPConfig `yaml:"http"` - SMTP SMTPConfig `yaml:"smtp"` - Hydra HydraConfig `yaml:"hydra"` + HTTP HTTPConfig `yaml:"http"` + SMTP SMTPConfig `yaml:"smtp"` + Hydra HydraConfig `yaml:"hydra"` + Session SessionConfig `yaml:"session"` } // NewFromFile retrieves the configuration from the given file @@ -67,6 +68,11 @@ type HydraConfig struct { HTTPClientTimeout time.Duration `yaml:"httpClientTimeout" env:"HYDRA_HTTP_CLIENT_TIMEOUT"` } +type SessionConfig struct { + DefaultDuration int `yaml:"defaultDuration" env:"HYDRA_SESSION_DEFAULT_DURATION"` + RememberMeDuration int `yaml:"rememberMeDuration" env:"HYDRA_SESSION_REMEMBER_ME_DURATION"` +} + func NewDumpDefault() *Config { config := NewDefault() return config @@ -99,6 +105,10 @@ func NewDefault() *Config { FakeSSLTermination: false, HTTPClientTimeout: time.Second * 30, //nolint: gomnb }, + Session: SessionConfig{ + DefaultDuration: int((time.Hour * 1).Seconds()), // 1 hour + RememberMeDuration: int((time.Hour * 24 * 30).Seconds()), // 30 days + }, } } diff --git a/internal/route/verify.go b/internal/route/verify.go index 149b788..d80e477 100644 --- a/internal/route/verify.go +++ b/internal/route/verify.go @@ -3,6 +3,7 @@ package route import ( "net/http" + "forge.cadoles.com/wpetit/hydra-passwordless/internal/config" "forge.cadoles.com/wpetit/hydra-passwordless/internal/hydra" "forge.cadoles.com/wpetit/hydra-passwordless/internal/query" "github.com/pkg/errors" @@ -14,6 +15,7 @@ import ( func handleVerification(w http.ResponseWriter, r *http.Request) { ctn := container.Must(r.Context()) bus := cqrs.Must(ctn) + conf := config.Must(ctn) token := r.URL.Query().Get("token") if token == "" { @@ -52,10 +54,15 @@ func handleVerification(w http.ResponseWriter, r *http.Request) { hydr := hydra.Must(ctn) + rememberFor := conf.Session.DefaultDuration + if verifyUserData.RememberMe { + rememberFor = conf.Session.RememberMeDuration + } + accept := &hydra.AcceptLoginRequest{ Subject: verifyUserData.Email, Remember: verifyUserData.RememberMe, - RememberFor: 3600, + RememberFor: rememberFor, Context: map[string]interface{}{ "email": verifyUserData.Email, }, From 38ac4422dddc21872b2b53b26d0fc8db875ff04b Mon Sep 17 00:00:00 2001 From: William Petit Date: Tue, 8 Sep 2020 11:40:25 +0200 Subject: [PATCH 11/16] Do not use vendoring --- Makefile | 13 ++++--------- misc/script/release.sh | 1 - 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 23b1008..5285aa1 100644 --- a/Makefile +++ b/Makefile @@ -3,18 +3,15 @@ SHELL := /bin/bash DOCKER_IMAGE_NAME ?= bornholm/hydra-passwordless DOCKER_IMAGE_TAG ?= latest -build: vendor - CGO_ENABLED=0 go build -mod=vendor -v -o bin/server ./cmd/server +build: + CGO_ENABLED=0 go build -v -o bin/server ./cmd/server test: go test -v -race ./... -release: vendor +release: @$(SHELL) ./misc/script/release.sh -vendor: - go mod vendor - tidy: go mod tidy @@ -40,7 +37,6 @@ create-default-client: -n "Default App" \ -a "openid" -a "email" - list-clients: docker-compose exec \ -e HYDRA_URL=http://localhost:4445 \ @@ -95,7 +91,6 @@ docker-release: docker-build clean: rm -rf release rm -rf data - rm -rf vendor rm -rf bin -.PHONY: lint watch build vendor tidy release \ No newline at end of file +.PHONY: lint watch build tidy release \ No newline at end of file diff --git a/misc/script/release.sh b/misc/script/release.sh index 5cbe882..b5e30aa 100644 --- a/misc/script/release.sh +++ b/misc/script/release.sh @@ -24,7 +24,6 @@ function build { echo "building $dirname..." CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" go build \ - -mod=vendor \ -ldflags="-s -w -X 'main.GitRef=$(current_commit_ref)' -X 'main.ProjectVersion=$(current_version)' -X 'main.BuildDate=$(current_date)'" \ -gcflags=-trimpath="${PWD}" \ -asmflags=-trimpath="${PWD}" \ From 41748363d19d410470dc45d568304222e278c37e Mon Sep 17 00:00:00 2001 From: William Petit Date: Tue, 13 Oct 2020 10:35:41 +0200 Subject: [PATCH 12/16] Sentry integration --- cmd/server/main.go | 34 ++++++++++ go.mod | 1 + go.sum | 127 ++++++++++++++++++++++++++++++++++++++ internal/config/config.go | 17 +++++ internal/route/verify.go | 7 ++- 5 files changed, 185 insertions(+), 1 deletion(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 01a7e04..347a46c 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -4,6 +4,7 @@ import ( "net/http" "forge.cadoles.com/wpetit/hydra-passwordless/internal/route" + "github.com/getsentry/sentry-go" "github.com/go-chi/chi" "github.com/go-chi/chi/middleware" "gitlab.com/wpetit/goweb/middleware/container" @@ -15,6 +16,7 @@ import ( "os" "forge.cadoles.com/wpetit/hydra-passwordless/internal/config" + sentryhttp "github.com/getsentry/sentry-go/http" "github.com/pkg/errors" ) @@ -89,6 +91,30 @@ func main() { log.Fatalf("%+v", errors.Wrap(err, "could not override config with environment")) } + useSentry := conf.Sentry.DSN != "" + + if useSentry { + var sentryEnv string + if conf.Sentry.Environment == "" { + sentryEnv, _ = os.Hostname() + } else { + sentryEnv = conf.Sentry.Environment + } + + err := sentry.Init(sentry.ClientOptions{ + Dsn: conf.Sentry.DSN, + Debug: conf.Debug, + SampleRate: conf.Sentry.ServerSampleRate, + Release: ProjectVersion + "-" + GitRef, + Environment: sentryEnv, + }) + if err != nil { + log.Fatalf("%+v", errors.Wrap(err, "could not initialize sentry")) + } + + defer sentry.Flush(conf.Sentry.ServerFlushTimeout) + } + // Create service container ctn, err := getServiceContainer(conf) if err != nil { @@ -101,6 +127,14 @@ func main() { r.Use(middleware.Logger) r.Use(middleware.Recoverer) + if useSentry { + sentryMiddleware := sentryhttp.New(sentryhttp.Options{ + Repanic: true, + }) + + r.Use(sentryMiddleware.Handle) + } + // Expose service container on router r.Use(container.ServiceContainer(ctn)) diff --git a/go.mod b/go.mod index 08b9e95..353ea01 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/PuerkitoBio/goquery v1.5.1 // indirect github.com/aymerick/douceur v0.2.0 github.com/caarlos0/env/v6 v6.2.2 + github.com/getsentry/sentry-go v0.7.0 github.com/go-chi/chi v4.1.0+incompatible github.com/gorilla/csrf v1.6.2 github.com/gorilla/css v1.0.0 // indirect diff --git a/go.sum b/go.sum index 1448d74..6cfe490 100644 --- a/go.sum +++ b/go.sum @@ -14,12 +14,19 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= +github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= @@ -34,31 +41,59 @@ github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkx github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/caarlos0/env/v6 v6.2.2 h1:R0NIFXaB/LhwuGrjnsldzpnVNjFU/U+hTVHt+cq0yDY= github.com/caarlos0/env/v6 v6.2.2/go.mod h1:3LpmfcAYCG6gCiSgDLaFR5Km1FRpPwFvBbRcjHar6Sw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/getsentry/sentry-go v0.7.0 h1:MR2yfR4vFfv/2+iBuSnkdQwVg7N9cJzihZ6KJu7srwQ= +github.com/getsentry/sentry-go v0.7.0/go.mod h1:pLFpD2Y5RHIKF9Bw3KH6/68DeN2K/XBJd8awjdPnUwg= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi v4.1.0+incompatible h1:ETj3cggsVIY2Xao5ExCu6YhEh5MD6JTfcBzS37R260w= github.com/go-chi/chi v4.1.0+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -71,12 +106,15 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.2-0.20191216170541-340f1ebe299e h1:4WfjkTUTsO6siF8ghDQQk6t7x/FPsv3w6MXkc47do7Q= github.com/google/go-cmp v0.3.2-0.20191216170541-340f1ebe299e/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -85,6 +123,7 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/csrf v1.6.0/go.mod h1:7tSf8kmjNYr7IWDCYhd3U8Ck34iQ/Yw5CJu7bAkHEGI= github.com/gorilla/csrf v1.6.2 h1:QqQ/OWwuFp4jMKgBFAzJVW3FMULdyUW7JoM4pEWuqKg= github.com/gorilla/csrf v1.6.2/go.mod h1:7tSf8kmjNYr7IWDCYhd3U8Ck34iQ/Yw5CJu7bAkHEGI= @@ -96,29 +135,73 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= +github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= +github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= +github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= +github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= +github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -127,8 +210,19 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -136,17 +230,34 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= gitlab.com/wpetit/goweb v0.0.0-20200418152305-76dea96a46ce h1:B3inZUHFr/FpA3jb+ZeSSHk3FSpB0xkQ0TjePhRokxw= gitlab.com/wpetit/goweb v0.0.0-20200418152305-76dea96a46ce/go.mod h1:Gfv7cBOw1T2XwXMsLm1d9kAjMAdNtLMjPv+yCzRO9qk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -170,14 +281,18 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= @@ -192,7 +307,9 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -201,6 +318,8 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 h1:gSbV7h1NRL2G1xTg/owz62CST1oJBmxy4QpMMregXVQ= golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -211,11 +330,14 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -262,13 +384,18 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/config/config.go b/internal/config/config.go index 26deabb..e9bd000 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -12,10 +12,12 @@ import ( ) type Config struct { + Debug bool `yaml:"debug"` HTTP HTTPConfig `yaml:"http"` SMTP SMTPConfig `yaml:"smtp"` Hydra HydraConfig `yaml:"hydra"` Session SessionConfig `yaml:"session"` + Sentry SentryConfig `yaml:"sentry"` } // NewFromFile retrieves the configuration from the given file @@ -73,6 +75,14 @@ type SessionConfig struct { RememberMeDuration int `yaml:"rememberMeDuration" env:"HYDRA_SESSION_REMEMBER_ME_DURATION"` } +type SentryConfig struct { + DSN string `yaml:"dsn" env:"SENTRY_DSN"` + // Server events sampling rate, see https://docs.sentry.io/platforms/go/configuration/options/ + ServerSampleRate float64 `yaml:"serverSampleRate" env:"SENTRY_SERVER_SAMPLE_RATE"` + ServerFlushTimeout time.Duration `yaml:"serverFlushTimeout" env:"SENTRY_SERVER_FLUSH_TIMEOUT"` + Environment string `yaml:"environment" env:"SENTRY_ENVIRONMENT"` +} + func NewDumpDefault() *Config { config := NewDefault() return config @@ -80,6 +90,7 @@ func NewDumpDefault() *Config { func NewDefault() *Config { return &Config{ + Debug: false, HTTP: HTTPConfig{ Address: ":3000", CookieAuthenticationKey: "", @@ -109,6 +120,12 @@ func NewDefault() *Config { DefaultDuration: int((time.Hour * 1).Seconds()), // 1 hour RememberMeDuration: int((time.Hour * 24 * 30).Seconds()), // 30 days }, + Sentry: SentryConfig{ + DSN: "", + ServerSampleRate: 1, + ServerFlushTimeout: 2 * time.Second, + Environment: "", + }, } } diff --git a/internal/route/verify.go b/internal/route/verify.go index d80e477..f903b58 100644 --- a/internal/route/verify.go +++ b/internal/route/verify.go @@ -6,6 +6,7 @@ import ( "forge.cadoles.com/wpetit/hydra-passwordless/internal/config" "forge.cadoles.com/wpetit/hydra-passwordless/internal/hydra" "forge.cadoles.com/wpetit/hydra-passwordless/internal/query" + "github.com/getsentry/sentry-go" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/cqrs" "gitlab.com/wpetit/goweb/logger" @@ -32,6 +33,7 @@ func handleVerification(w http.ResponseWriter, r *http.Request) { result, err := bus.Query(ctx, qry) if err != nil { + sentry.CaptureException(err) logger.Error(ctx, "could not verify token", logger.E(err)) err := renderErrorPage( @@ -49,7 +51,9 @@ func handleVerification(w http.ResponseWriter, r *http.Request) { verifyUserData, ok := result.Data().(*query.VerifyUserData) if !ok { - panic(errors.New("unexpected result data")) + err := errors.New("unexpected result data") + sentry.CaptureException(err) + panic(err) } hydr := hydra.Must(ctn) @@ -70,6 +74,7 @@ func handleVerification(w http.ResponseWriter, r *http.Request) { res, err := hydr.AcceptLoginRequest(verifyUserData.Challenge, accept) if err != nil { + sentry.CaptureException(err) logger.Error(ctx, "could not retrieve hydra accept response", logger.E(err)) err := renderErrorPage( From 33dbb6ea478a347bd272afcb96036cfe3abd1259 Mon Sep 17 00:00:00 2001 From: William Petit Date: Fri, 25 Mar 2022 15:11:29 +0100 Subject: [PATCH 13/16] BaseURL configuration variable generalization --- Makefile | 4 ++- cmd/server/template/blocks/base.html.tmpl | 2 +- cmd/server/template/layouts/consent.html.tmpl | 2 +- cmd/server/template/layouts/login.html.tmpl | 2 +- internal/command/send_confirmation_email.go | 29 +++++-------------- internal/config/config.go | 7 ++--- internal/route/helper.go | 18 +++++++++++- internal/route/login.go | 25 +++++++++++----- misc/docker/Dockerfile | 2 +- 9 files changed, 51 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index 5285aa1..788b982 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ DOKKU_HOST := dokku@dev.lookingfora.name SHELL := /bin/bash DOCKER_IMAGE_NAME ?= bornholm/hydra-passwordless -DOCKER_IMAGE_TAG ?= latest +DOCKER_IMAGE_TAG ?= $(shell date +%Y%m%d%H%M) build: CGO_ENABLED=0 go build -v -o bin/server ./cmd/server @@ -85,8 +85,10 @@ docker-run: docker-release: docker-build docker image tag hydra-passwordless:latest $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG) + docker image tag hydra-passwordless:latest $(DOCKER_IMAGE_NAME):latest docker login docker push $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG) + docker push $(DOCKER_IMAGE_NAME):latest clean: rm -rf release diff --git a/cmd/server/template/blocks/base.html.tmpl b/cmd/server/template/blocks/base.html.tmpl index 5efee57..dde7bae 100644 --- a/cmd/server/template/blocks/base.html.tmpl +++ b/cmd/server/template/blocks/base.html.tmpl @@ -7,7 +7,7 @@ {{block "title" . -}}{{- end}} {{- block "head_style" . -}} - + {{end}} {{- block "head_script" . -}}{{end}} diff --git a/cmd/server/template/layouts/consent.html.tmpl b/cmd/server/template/layouts/consent.html.tmpl index 0c86046..731a1e4 100644 --- a/cmd/server/template/layouts/consent.html.tmpl +++ b/cmd/server/template/layouts/consent.html.tmpl @@ -13,7 +13,7 @@ Autorisez vous l'application à utiliser ces informations vous concernant ?

-
+ {{range .RequestedScope}}