zero-ppanel/apps/admin/internal/middleware/signatureMiddleware.go

89 lines
2.1 KiB
Go

package middleware
import (
"bytes"
"io"
"net/http"
"strings"
"github.com/zero-ppanel/zero-ppanel/apps/admin/internal/config"
"github.com/zero-ppanel/zero-ppanel/pkg/signature"
"github.com/zero-ppanel/zero-ppanel/pkg/xerr"
"github.com/zeromicro/go-zero/rest/httpx"
)
type SignatureMiddleware struct {
conf config.Config
validator *signature.Validator
}
func NewSignatureMiddleware(c config.Config, store signature.NonceStore) *SignatureMiddleware {
return &SignatureMiddleware{
conf: c,
validator: signature.NewValidator(c.AppSignature, store),
}
}
func (m *SignatureMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
appId := r.Header.Get("X-App-Id")
if appId == "" {
next(w, r)
return
}
for _, prefix := range m.conf.AppSignature.SkipPrefixes {
if strings.HasPrefix(r.URL.Path, prefix) {
next(w, r)
return
}
}
timestamp := r.Header.Get("X-Timestamp")
nonce := r.Header.Get("X-Nonce")
sig := r.Header.Get("X-Signature")
if timestamp == "" || nonce == "" || sig == "" {
httpx.WriteJson(w, http.StatusUnauthorized, buildErrResp(xerr.SignatureMissing))
return
}
var bodyBytes []byte
if r.Body != nil {
bodyBytes, _ = io.ReadAll(r.Body)
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
}
sts := signature.BuildStringToSign(r.Method, r.URL.Path, r.URL.RawQuery, bodyBytes, appId, timestamp, nonce)
if err := m.validator.Validate(r.Context(), appId, timestamp, nonce, sig, sts); err != nil {
code := mapSignatureErr(err)
httpx.WriteJson(w, http.StatusUnauthorized, buildErrResp(code))
return
}
next(w, r)
}
}
func mapSignatureErr(err error) int {
switch err {
case signature.ErrSignatureMissing:
return xerr.SignatureMissing
case signature.ErrSignatureExpired:
return xerr.SignatureExpired
case signature.ErrSignatureReplay:
return xerr.SignatureReplay
default:
return xerr.SignatureInvalid
}
}
func buildErrResp(code int) map[string]interface{} {
return map[string]interface{}{
"code": code,
"msg": xerr.MapErrMsg(code),
"data": nil,
}
}