mi-v1/cmd/mi/middleware.go

128 lines
2.6 KiB
Go
Raw Normal View History

2020-01-11 19:11:30 +00:00
package main
import (
2020-01-12 19:05:49 +00:00
"context"
2020-01-11 19:11:30 +00:00
"encoding/hex"
"flag"
"net/http"
"time"
"github.com/google/uuid"
"github.com/o1egl/paseto/v2"
"golang.org/x/crypto/ed25519"
2020-01-14 22:37:35 +00:00
"golang.org/x/net/trace"
2020-01-11 19:11:30 +00:00
)
var (
// Paseto
pasetoPublicKey = flag.String("paseto-public-key", "", "Paseto public key (see tools/paseto-key-gen.go)")
pasetoPrivateKey = flag.String("paseto-private-key", "", "Paseto private key")
)
2020-01-14 22:37:35 +00:00
type GoTraceMiddleware struct{ next http.Handler }
func (gtm GoTraceMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
tr := trace.New("http", r.URL.Path)
ctx = trace.NewContext(ctx, tr)
r = r.WithContext(ctx)
gtm.next.ServeHTTP(w, r)
tr.Finish()
}
2020-01-11 19:11:30 +00:00
type PasetoMiddleware struct {
next http.Handler
pubKey ed25519.PublicKey
privKey ed25519.PrivateKey
v2 paseto.V2
}
func MakeMiddleware(pub, priv string, next http.Handler) (*PasetoMiddleware, error) {
var result PasetoMiddleware
result.next = next
publicKey, err := hex.DecodeString(pub)
if err != nil {
return nil, err
}
result.pubKey = ed25519.PublicKey(publicKey)
privateKey, err := hex.DecodeString(priv)
if err != nil {
return nil, err
}
result.privKey = ed25519.PrivateKey(privateKey)
return &result, nil
}
func (pm PasetoMiddleware) CreateToken(data [][2]string, expiration time.Time) (string, error) {
claims := paseto.JSONToken{
Expiration: expiration,
Jti: uuid.New().String(),
Subject: "Within",
IssuedAt: time.Now(),
}
for _, datum := range data {
claims.Set(datum[0], datum[1])
}
tok, err := pm.v2.Sign(pm.privKey, claims, nil)
if err != nil {
return "", err
}
return tok, nil
}
2020-01-12 19:05:49 +00:00
var publicRoutes map[string]bool
func init() {
publicRoutes = map[string]bool{
2020-01-12 23:31:49 +00:00
"/webhooks/": true,
"/static/": true,
"/static/main.js": true,
"/static/gruvbox.css": true,
2020-01-14 13:51:35 +00:00
"/static/favicon.ico": true,
"/static/favicon.png": true,
2020-01-14 22:37:35 +00:00
"/debug/requests": true,
"/debug/events": true,
2020-01-18 18:20:39 +00:00
"/sign-in": true,
2020-01-12 19:05:49 +00:00
}
}
type ctxKey int
const (
tokenKey ctxKey = iota
)
2020-01-11 19:11:30 +00:00
func (pm PasetoMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
tok := r.Header.Get("Authorization")
var newJsonToken paseto.JSONToken
var newFooter string
2020-01-11 20:18:59 +00:00
var err error
2020-01-11 19:11:30 +00:00
2020-01-12 19:05:49 +00:00
if r.URL.EscapedPath() == "/.within/botinfo" || r.URL.EscapedPath() == "/" {
2020-01-11 20:18:59 +00:00
goto ok
}
2020-01-12 19:05:49 +00:00
for k := range publicRoutes {
2020-01-12 23:31:49 +00:00
if r.URL.EscapedPath() == k {
2020-01-12 19:05:49 +00:00
goto ok
}
2020-01-12 02:14:56 +00:00
}
2020-01-11 20:18:59 +00:00
err = pm.v2.Verify(tok, pm.pubKey, &newJsonToken, &newFooter)
2020-01-11 19:11:30 +00:00
if err != nil {
http.Error(w, "Not allowed", http.StatusForbidden)
return
}
2020-01-12 19:05:49 +00:00
r = r.WithContext(context.WithValue(r.Context(), tokenKey, newJsonToken))
2020-01-11 20:18:59 +00:00
ok:
2020-01-11 19:11:30 +00:00
pm.next.ServeHTTP(w, r)
}