mi-v1/cmd/mi/middleware.go

98 lines
2.0 KiB
Go

package main
import (
"encoding/hex"
"encoding/json"
"flag"
"net/http"
"strings"
"time"
"github.com/google/uuid"
"github.com/o1egl/paseto/v2"
"golang.org/x/crypto/ed25519"
"within.website/ln"
)
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")
)
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
}
func (pm PasetoMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
tok := r.Header.Get("Authorization")
var newJsonToken paseto.JSONToken
var newFooter string
var err error
if r.URL.EscapedPath() == "/.within/botinfo" {
goto ok
}
if strings.HasPrefix(r.URL.EscapedPath(), "/webhooks/") {
goto ok
}
err = pm.v2.Verify(tok, pm.pubKey, &newJsonToken, &newFooter)
if err != nil {
ln.Error(r.Context(), err)
http.Error(w, "Not allowed", http.StatusForbidden)
return
}
if r.URL.EscapedPath() == "/.within/tokeninfo" {
json.NewEncoder(w).Encode(newJsonToken)
return
}
ok:
pm.next.ServeHTTP(w, r)
}