150 lines
2.5 KiB
Go
150 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"time"
|
|
|
|
"git.xeserv.us/xena/route/internal/database"
|
|
"git.xeserv.us/xena/route/internal/middleware"
|
|
"github.com/Xe/ln"
|
|
"github.com/twitchtv/twirp"
|
|
"golang.org/x/net/trace"
|
|
)
|
|
|
|
// errors
|
|
var (
|
|
ErrNotAuthorized = errors.New("server: not authorized")
|
|
)
|
|
|
|
func (s *Server) makeTwirpHooks() *twirp.ServerHooks {
|
|
hooks := &twirp.ServerHooks{}
|
|
|
|
hooks.RequestRouted = func(ctx context.Context) (context.Context, error) {
|
|
ctx = withStartTime(ctx)
|
|
|
|
method, ok := twirp.MethodName(ctx)
|
|
if !ok {
|
|
return ctx, nil
|
|
}
|
|
|
|
pkg, ok := twirp.PackageName(ctx)
|
|
if !ok {
|
|
return ctx, nil
|
|
}
|
|
|
|
svc, ok := twirp.ServiceName(ctx)
|
|
if !ok {
|
|
return ctx, nil
|
|
}
|
|
|
|
ctx = ln.WithF(ctx, ln.F{
|
|
"twirp_method": method,
|
|
"twirp_package": pkg,
|
|
"twirp_service": svc,
|
|
})
|
|
|
|
hdr, ok := middleware.GetHeaders(ctx)
|
|
if !ok {
|
|
return ctx, errors.New("can't get request headers")
|
|
}
|
|
|
|
req, _ := http.NewRequest("GET", "/", nil)
|
|
req.Header = hdr
|
|
|
|
ck, err := req.Cookie("routed")
|
|
if err != nil {
|
|
return ctx, err
|
|
}
|
|
|
|
tok := ck.Value
|
|
|
|
t, err := s.db.Tokens().Get(ctx, tok)
|
|
if err != nil {
|
|
return ctx, err
|
|
}
|
|
|
|
ctx = withAuthToken(ctx, t)
|
|
ctx = ln.WithF(ctx, t.F())
|
|
|
|
return ctx, nil
|
|
}
|
|
|
|
hooks.ResponseSent = func(ctx context.Context) {
|
|
f := ln.F{}
|
|
now := time.Now()
|
|
t, ok := getStartTime(ctx)
|
|
if ok {
|
|
f["response_time"] = now.Sub(t)
|
|
}
|
|
|
|
ln.Log(ctx, f, ln.Action("response sent"))
|
|
}
|
|
|
|
hooks.Error = func(ctx context.Context, e twirp.Error) context.Context {
|
|
f := ln.F{}
|
|
|
|
for k, v := range e.MetaMap() {
|
|
f["twirp_meta_"+k] = v
|
|
}
|
|
|
|
ln.Error(ctx, e, f, ln.Action("twirp error"), ln.F{
|
|
"twirp_error_code": e.Code(),
|
|
"twirp_error_msg": e.Msg(),
|
|
})
|
|
|
|
tr, ok := trace.FromContext(ctx)
|
|
if !ok {
|
|
return ctx
|
|
}
|
|
|
|
tr.SetError()
|
|
|
|
return ctx
|
|
}
|
|
|
|
return hooks
|
|
}
|
|
|
|
func (s *Server) getAuth(ctx context.Context, operation, scope string) (database.Token, error) {
|
|
t, ok := getAuthToken(ctx)
|
|
if !ok {
|
|
return database.Token{}, errors.New("no auth token in context")
|
|
}
|
|
|
|
ok = false
|
|
for _, sc := range t.Scopes {
|
|
// the "admin" scope is implicitly allowed for everything.
|
|
if sc == "admin" {
|
|
ok = true
|
|
break
|
|
}
|
|
|
|
if sc == scope {
|
|
ok = true
|
|
}
|
|
}
|
|
|
|
if !ok {
|
|
return database.Token{}, ErrNotAuthorized
|
|
}
|
|
|
|
ln.WithF(ctx, ln.F{"operation": operation})
|
|
|
|
return t, nil
|
|
}
|
|
|
|
func handleError(ctx context.Context, clitok database.Token, err error, f ln.F) error {
|
|
tr, ok := trace.FromContext(ctx)
|
|
if !ok {
|
|
goto skip
|
|
}
|
|
tr.SetError()
|
|
|
|
skip:
|
|
ln.Error(ctx, err, f, clitok)
|
|
|
|
return err
|
|
}
|