diff --git a/server/feishu-sync/internal/logic/webhooklogic.go b/server/feishu-sync/internal/logic/webhooklogic.go index 5bff2621..5f26c04c 100644 --- a/server/feishu-sync/internal/logic/webhooklogic.go +++ b/server/feishu-sync/internal/logic/webhooklogic.go @@ -2,8 +2,13 @@ package logic import ( "context" + "crypto/aes" + "crypto/cipher" "crypto/sha256" + "encoding/base64" + "encoding/hex" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -53,20 +58,35 @@ func (l *WebhookLogic) Webhook(w http.ResponseWriter, r *http.Request) { logx.Error("读取请求body失败", err) return } + defer r.Body.Close() //计算签名 timestamp := r.Header.Get("X-Lark-Request-Timestamp") nonce := r.Header.Get("X-Lark-Request-Nonce") encryptKey := "DmiHQ2bHhKiR3KK4tIjLShbs13eErxKA" signature := r.Header.Get("X-Lark-Signature") - sign := l.calculateSignature(timestamp, nonce, encryptKey, bodyBytes) + sign := l.CalculateFeiShuWebhookSignature(timestamp, nonce, encryptKey, bodyBytes) if signature != sign { logx.Error("非法的消息,签名验证不通过", sign, "====", signature) return } - defer r.Body.Close() + var encryptMsg EncryptWebhookMsg + if err = json.Unmarshal(bodyBytes, &encryptMsg); err != nil { + logx.Error("反序列化body失败", err) + return + } + if encryptMsg.Encrypt == "" { + logx.Error("消息加密信息是空的") + return + } + //解密 + realMsgBytes, err := l.DecryptFeiShuWebhookMsg(encryptMsg.Encrypt, encryptKey) + if err != nil { + logx.Error(err) + return + } //如果只是验证http连接的消息 var webhookMsg WebhookMsg - if err = json.Unmarshal(bodyBytes, &webhookMsg); err != nil { + if err = json.Unmarshal(realMsgBytes, &webhookMsg); err != nil { logx.Error("反序列化请求body失败", err) return } @@ -79,7 +99,6 @@ func (l *WebhookLogic) Webhook(w http.ResponseWriter, r *http.Request) { w.Write(b) return } - headerByte, err := json.Marshal(webhookMsg.Header) if err != nil { logx.Error("序列化请求体header失败:", err) @@ -111,7 +130,7 @@ func (l *WebhookLogic) Webhook(w http.ResponseWriter, r *http.Request) { } // 计算签名 -func (l *WebhookLogic) calculateSignature(timestamp, nonce, encryptKey string, body []byte) string { +func (l *WebhookLogic) CalculateFeiShuWebhookSignature(timestamp, nonce, encryptKey string, body []byte) string { var b strings.Builder b.WriteString(timestamp) b.WriteString(nonce) @@ -124,3 +143,42 @@ func (l *WebhookLogic) calculateSignature(timestamp, nonce, encryptKey string, b sig := fmt.Sprintf("%x", bs) return sig } + +// 解密事件消息 +func (l *WebhookLogic) DecryptFeiShuWebhookMsg(encrypt string, encryptKey string) ([]byte, error) { + h := sha256.New() + _, err := h.Write([]byte(encryptKey)) + if err != nil { + return nil, err + } + key := hex.EncodeToString(h.Sum(nil)) + buf, err := base64.StdEncoding.DecodeString(encrypt) + if err != nil { + return nil, fmt.Errorf("base64StdEncode Error[%v]", err) + } + if len(buf) < aes.BlockSize { + return nil, errors.New("cipher too short") + } + keyBs := sha256.Sum256([]byte(key)) + block, err := aes.NewCipher(keyBs[:sha256.Size]) + if err != nil { + return nil, fmt.Errorf("AESNewCipher Error[%v]", err) + } + iv := buf[:aes.BlockSize] + buf = buf[aes.BlockSize:] + // CBC mode always works in whole blocks. + if len(buf)%aes.BlockSize != 0 { + return nil, errors.New("ciphertext is not a multiple of the block size") + } + mode := cipher.NewCBCDecrypter(block, iv) + mode.CryptBlocks(buf, buf) + n := strings.Index(string(buf), "{") + if n == -1 { + n = 0 + } + m := strings.LastIndex(string(buf), "}") + if m == -1 { + m = len(buf) - 1 + } + return buf[n : m+1], nil +}