Skip to content

Commit

Permalink
feat: switch to chi renderer for errors
Browse files Browse the repository at this point in the history
Signed-off-by: Manfred Touron <94029+moul@users.noreply.github.com>
  • Loading branch information
moul committed Jul 6, 2020
1 parent 264af3c commit a825ad3
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 36 deletions.
2 changes: 1 addition & 1 deletion go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 19 additions & 31 deletions pkg/sgtm/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,16 @@ import (
"crypto/sha256"
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"

"github.com/moogar0880/problems"
"go.uber.org/zap"
"golang.org/x/oauth2"
"moul.io/godev"
)

var (
invalidStateProblem = problems.NewDetailedProblem(http.StatusBadRequest, "invalid state")
codeExchangeProblem = problems.NewDetailedProblem(http.StatusInternalServerError, "oauth code exchange")
// internalProblem = problems.NewDetailedProblem(http.StatusInternalServerError, "internal problem")
)

const (
oauthTokenCookie = "oauth-token"
// sessionError
)

func (svc *Service) httpAuthLogin(w http.ResponseWriter, r *http.Request) {
Expand All @@ -45,8 +39,7 @@ func (svc *Service) httpAuthCallback(w http.ResponseWriter, r *http.Request) {
got := r.URL.Query().Get("state")
expected := svc.authGenerateState(r)
if expected != got {
svc.logger.Warn("invalid oauth2 state", zap.String("expected", expected), zap.String("got", got))
problems.StatusProblemHandler(invalidStateProblem)(w, r)
svc.errRender(w, r, fmt.Errorf("invalid oauth2 state"), http.StatusBadRequest)
return
}
}
Expand All @@ -58,8 +51,7 @@ func (svc *Service) httpAuthCallback(w http.ResponseWriter, r *http.Request) {
var err error
token, err = conf.Exchange(context.Background(), code)
if err != nil {
svc.logger.Warn("code exchange failed", zap.Error(err))
problems.StatusProblemHandler(codeExchangeProblem)(w, r)
svc.errRender(w, r, err, http.StatusUnprocessableEntity)
return
}
cookie := http.Cookie{
Expand All @@ -70,31 +62,27 @@ func (svc *Service) httpAuthCallback(w http.ResponseWriter, r *http.Request) {
Path: "/",
//Domain: r.Host,
}
fmt.Println(godev.PrettyJSON(cookie))
svc.logger.Debug("set user cookie", zap.Any("cookie", cookie))
http.SetCookie(w, &cookie)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
}

// FIXME: configure jwt, embed username, email, create account if not exists, set roles in jwt
/*
// get user's info
{
res, err := conf.Client(context.Background(), token).Get("https://discordapp.com/api/v6/users/@me")
if err != nil {
svc.logger.Warn("init discord client", zap.Error(err))
problems.StatusProblemHandler(internalProblem)(w, r)
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
svc.logger.Warn("init discord client", zap.Error(err))
problems.StatusProblemHandler(internalProblem)(w, r)
return
}
_, _ = w.Write(body)
// get user's info
{
res, err := conf.Client(context.Background(), token).Get("https://discordapp.com/api/v6/users/@me")
if err != nil {
svc.errRender(w, r, err, http.StatusUnprocessableEntity)
return
}
*/
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
svc.errRender(w, r, err, http.StatusUnprocessableEntity)
return
}
_, _ = w.Write(body)
}
}

func (svc *Service) authConfigFromReq(r *http.Request) *oauth2.Config {
Expand Down
16 changes: 15 additions & 1 deletion pkg/sgtm/driver_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/jsonp"
"github.com/go-chi/render"
packr "github.com/gobuffalo/packr/v2"
"github.com/gogo/gateway"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
Expand Down Expand Up @@ -147,6 +148,7 @@ func (svc *Service) httpServer() (*http.Server, error) {
r.Use(middleware.Timeout(svc.opts.ServerRequestTimeout))
r.Use(middleware.RealIP)
r.Use(middleware.RequestID)
r.Use(render.SetContentType(render.ContentTypeJSON))

runtimeMux := runtime.NewServeMux(
runtime.WithMarshalerOption(runtime.MIMEWildcard, &gateway.JSONPb{
Expand Down Expand Up @@ -189,12 +191,24 @@ func (svc *Service) httpServer() (*http.Server, error) {
Date time.Time
OAuthToken string
}{
Title: "SGTM!",
Title: "SGTM",
Date: time.Now(),
}
if cookie, err := r.Cookie(oauthTokenCookie); err == nil {
data.OAuthToken = cookie.Value
}
if svc.opts.DevMode {
src, err := box.FindString("index.tmpl.html")
if err != nil {
svc.errRender(w, r, err, http.StatusInternalServerError)
return
}
tmpl, err = template.New("index").Parse(src)
if err != nil {
svc.errRender(w, r, err, http.StatusInternalServerError)
return
}
}
if err := tmpl.Execute(w, data); err != nil {
svc.logger.Warn("failed to reply", zap.Error(err))
}
Expand Down
43 changes: 43 additions & 0 deletions pkg/sgtm/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package sgtm

import (
"net/http"

"github.com/go-chi/render"
"go.uber.org/zap"
)

func (svc *Service) errRender(w http.ResponseWriter, r *http.Request, err error, status int) {
if status == 0 {
status = http.StatusUnprocessableEntity
}
renderer := &errResponse{
Type: "about:blank",
Title: http.StatusText(status),
Status: status,
Detail: err.Error(),
Instance: "",
}
svc.logger.Warn(
"user error",
zap.String("title", renderer.Title),
zap.Error(err),
)
if err := render.Render(w, r, renderer); err != nil {
svc.logger.Warn("cannot render error", zap.Error(err))
}
}

// based on github.com/moogar0880/problems.DefaultProblem
type errResponse struct {
Type string `json:"type"`
Title string `json:"title"`
Status int `json:"status,omitempty"`
Detail string `json:"detail,omitempty"`
Instance string `json:"instance,omitempty"`
}

func (e *errResponse) Render(w http.ResponseWriter, r *http.Request) error {
render.Status(r, e.Status)
return nil
}
28 changes: 27 additions & 1 deletion rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,26 @@ GO_INSTALL_OPTS ?=
GO_TEST_OPTS ?= -test.timeout=30s
GOMOD_DIR ?= .
GOCOVERAGE_FILE ?= ./coverage.txt
GOTESTJSON_FILE ?= ./go-test.json
GOBUILDLOG_FILE ?= ./go-build.log
GOINSTALLLOG_FILE ?= ./go-install.log

ifdef GOBINS
.PHONY: go.install
go.install:
ifeq ($(CI),true)
@rm -f /tmp/goinstall.log
@set -e; for dir in $(GOBINS); do ( set -xe; \
cd $$dir; \
$(GO) install -v $(GO_INSTALL_OPTS) .; \
); done 2>&1 | tee $(GOINSTALLLOG_FILE)

else
@set -e; for dir in $(GOBINS); do ( set -xe; \
cd $$dir; \
$(GO) install $(GO_INSTALL_OPTS) .; \
); done
endif
INSTALL_STEPS += go.install

.PHONY: go.release
Expand All @@ -92,15 +104,29 @@ endif

.PHONY: go.unittest
go.unittest:
ifeq ($(CI),true)
@echo "mode: atomic" > /tmp/gocoverage
@rm -f $(GOTESTJSON_FILE)
@set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do (set -e; (set -euf pipefail; \
cd $$dir; \
($(GO) test ./... $(GO_TEST_OPTS) -cover -coverprofile=/tmp/profile.out -covermode=atomic -race -json | tee -a $(GOTESTJSON_FILE) 3>&1 1>&2 2>&3 | tee -a $(GOBUILDLOG_FILE); \
); \
if [ -f /tmp/profile.out ]; then \
cat /tmp/profile.out | sed "/mode: atomic/d" >> /tmp/gocoverage; \
rm -f /tmp/profile.out; \
fi)); done
@mv /tmp/gocoverage $(GOCOVERAGE_FILE)
else
@echo "mode: atomic" > /tmp/gocoverage
@set -e; for dir in `find $(GOMOD_DIR) -type f -name "go.mod" | grep -v /vendor/ | sed 's@/[^/]*$$@@' | sort | uniq`; do (set -e; (set -xe; \
cd $$dir; \
$(GO) test $(GO_TEST_OPTS) -cover -coverprofile=/tmp/profile.out -covermode=atomic -race ./...); \
$(GO) test ./... $(GO_TEST_OPTS) -cover -coverprofile=/tmp/profile.out -covermode=atomic -race); \
if [ -f /tmp/profile.out ]; then \
cat /tmp/profile.out | sed "/mode: atomic/d" >> /tmp/gocoverage; \
rm -f /tmp/profile.out; \
fi); done
@mv /tmp/gocoverage $(GOCOVERAGE_FILE)
endif

.PHONY: go.checkdoc
go.checkdoc:
Expand Down

0 comments on commit a825ad3

Please sign in to comment.