From a4ef42eb16d1a0d620029b2a12a0413d3b06dfc1 Mon Sep 17 00:00:00 2001 From: summer Date: Fri, 13 Aug 2021 10:27:55 +0800 Subject: [PATCH] add authentication --- go.mod | 2 +- go.sum | 2 ++ whitedew.go | 81 +++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index c603598..c714a79 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.15 require ( github.com/elazarl/goproxy v0.0.0-20210110162100-a92cc753f88e // indirect - github.com/gin-gonic/gin v1.7.2 + github.com/gin-gonic/gin v1.7.3 github.com/parnurzeal/gorequest v0.2.16 github.com/pkg/errors v0.9.1 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect diff --git a/go.sum b/go.sum index 902a790..b57a408 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA= github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/gin-gonic/gin v1.7.3 h1:aMBzLJ/GMEYmv1UWs2FFTcPISLrQH2mRgL9Glz8xows= +github.com/gin-gonic/gin v1.7.3/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= diff --git a/whitedew.go b/whitedew.go index 2607386..9a9ed19 100644 --- a/whitedew.go +++ b/whitedew.go @@ -1,11 +1,16 @@ package whitedew import ( + "crypto/hmac" + "crypto/sha1" + "encoding/hex" "encoding/json" "fmt" - "github.com/gin-gonic/gin" "log" + "net/http" "reflect" + + "github.com/gin-gonic/gin" ) type Plugin interface { @@ -30,8 +35,8 @@ func NewServer() *Server { } type Config struct { - CQHost string - Auth string + CQHost string + Secret string CacheDir string } @@ -54,23 +59,23 @@ func New() *WhiteDew { return &w } -func (w *WhiteDew)SetCQServer(url string) { +func (w *WhiteDew) SetCQServer(url string) { w.Config.CQHost = url } -func (w *WhiteDew)SetAuth(auth string) { - w.Config.Auth = auth +func (w *WhiteDew) SetAuth(secret string) { + w.Config.Secret = secret } -func (w *WhiteDew)SetCacheDir(dir string) { +func (w *WhiteDew) SetCacheDir(dir string) { w.Config.CacheDir = dir } -func (w *WhiteDew)AddPlugin(plugin Plugin) { +func (w *WhiteDew) AddPlugin(plugin Plugin) { w.pluginManager = append(w.pluginManager, plugin) } -func (w *WhiteDew)messageEventHandler(msgStr []byte, session *Session) { +func (w *WhiteDew) messageEventHandler(msgStr []byte, session *Session) { action := session.Action var handlers []HandlerFunc if action != "" { @@ -89,15 +94,15 @@ func parseNotice(msgStr []byte) MetaEvent { return tmp } -func (w *WhiteDew)defaultEventHandler(msgStr []byte, _ *Session) { +func (w *WhiteDew) defaultEventHandler(msgStr []byte, _ *Session) { log.Println("meta_message" + string(msgStr)) } -func (w *WhiteDew)metaEventHandler(msgStr []byte, session *Session) { +func (w *WhiteDew) metaEventHandler(msgStr []byte, session *Session) { } -func (w *WhiteDew)universalEventHandler(msgStr []byte) { +func (w *WhiteDew) universalEventHandler(msgStr []byte) { evt := parseNotice(msgStr) var noticeType string if evt.GetNoticeType() == "notify" { @@ -113,24 +118,24 @@ func (w *WhiteDew)universalEventHandler(msgStr []byte) { if handlers != nil { for _, handler := range handlers { agent := NewAgent(w.Config.CQHost) - handler.Handle(agent,rowEvent.(Event)) + handler.Handle(agent, rowEvent.(Event)) } } } -func (w *WhiteDew)SetRowMsgHandler(handlerFunc HandlerFunc) { +func (w *WhiteDew) SetRowMsgHandler(handlerFunc HandlerFunc) { w.rowMsgHandlers = append(w.rowMsgHandlers, handlerFunc) } -func (w *WhiteDew)SetActionHandler(action string, handler HandlerFunc) { +func (w *WhiteDew) SetActionHandler(action string, handler HandlerFunc) { w.actionPool[action] = append(w.actionPool[action], handler) } -func (w *WhiteDew)SetEventHandler(event string, handler Handler) { +func (w *WhiteDew) SetEventHandler(event string, handler Handler) { w.eventPool[event] = append(w.eventPool[event], handler) } -func (w *WhiteDew)dispatchEvent(msgStr []byte) { +func (w *WhiteDew) dispatchEvent(msgStr []byte) { postType := GetEventPostType(msgStr) msg := ParseMsg(msgStr) var session *Session @@ -147,18 +152,46 @@ func (w *WhiteDew)dispatchEvent(msgStr []byte) { } } -func (w *WhiteDew)eventHandler(c *gin.Context) { - msgStr, err := c.GetRawData() +func (w *WhiteDew) eventHandler(c *gin.Context) { + + jsonData, err := c.GetRawData() if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"reason": "bad requests"}) return } - go w.dispatchEvent(msgStr) + + // 验证 secret + if w.Config.Secret != "" { + + signature := c.Request.Header["X-Signature"] + if signature == nil { + c.JSON(http.StatusBadRequest, gin.H{"reason": "Signature is required"}) + return + } + + mac := hmac.New(sha1.New, []byte(w.Config.Secret)) + _, err = mac.Write(jsonData) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{}) + return + } + sig := hex.EncodeToString(mac.Sum(nil)) + if sig != signature[0][5:] { + c.JSON(http.StatusForbidden, gin.H{"reason": "authenticate failed"}) + return + } + } + + log.Println(jsonData) + go w.dispatchEvent(jsonData) } -func (w *WhiteDew)Run(path string, port int) { - w.server.engine.Any(path, w.eventHandler) - for _,plugin := range w.pluginManager { +func (w *WhiteDew) Run(path string, port int) { + for _, plugin := range w.pluginManager { plugin.Init(w) } + + w.server.engine.POST(path, w.eventHandler) + log.Fatalln(w.server.engine.Run(fmt.Sprintf(":%d", port))) -} \ No newline at end of file +}