diff --git a/channel/ding-talk.go b/channel/ding-talk.go deleted file mode 100644 index 9c86d4a..0000000 --- a/channel/ding-talk.go +++ /dev/null @@ -1 +0,0 @@ -package channel diff --git a/channel/ding.go b/channel/ding.go new file mode 100644 index 0000000..fbea720 --- /dev/null +++ b/channel/ding.go @@ -0,0 +1,86 @@ +package channel + +import ( + "bytes" + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "message-pusher/model" + "net/http" + "net/url" + "time" +) + +type dingMessageRequest struct { + MessageType string `json:"msgtype"` + Text struct { + Content string `json:"content"` + } `json:"text"` + Markdown struct { + Title string `json:"title"` + Text string `json:"text"` + } `json:"markdown"` +} + +type dingMessageResponse struct { + Code int `json:"errcode"` + Message string `json:"errmsg"` +} + +func SendDingMessage(message *Message, user *model.User) error { + if user.DingWebhookURL == "" { + return errors.New("未配置钉钉群机器人消息推送方式") + } + messageRequest := dingMessageRequest{ + MessageType: "text", + } + if message.Content == "" { + messageRequest.MessageType = "text" + messageRequest.Text.Content = message.Description + } else { + messageRequest.MessageType = "markdown" + messageRequest.Markdown.Title = message.Title + messageRequest.Markdown.Text = message.Content + } + + timestamp := time.Now().UnixMilli() + sign, err := dingSign(user.DingWebhookSecret, timestamp) + if err != nil { + return err + } + jsonData, err := json.Marshal(messageRequest) + if err != nil { + return err + } + resp, err := http.Post(fmt.Sprintf("%s×tamp=%d&sign=%s", user.DingWebhookURL, timestamp, sign), "application/json", + bytes.NewBuffer(jsonData)) + if err != nil { + return err + } + var res dingMessageResponse + err = json.NewDecoder(resp.Body).Decode(&res) + if err != nil { + return err + } + if res.Code != 0 { + return errors.New(res.Message) + } + return nil +} + +func dingSign(secret string, timestamp int64) (string, error) { + // https://open.dingtalk.com/document/robots/customize-robot-security-settings + // timestamp + key -> sha256 -> URL encode + stringToSign := fmt.Sprintf("%d\n%s", timestamp, secret) + h := hmac.New(sha256.New, []byte(secret)) + _, err := h.Write([]byte(stringToSign)) + if err != nil { + return "", err + } + signature := base64.StdEncoding.EncodeToString(h.Sum(nil)) + signature = url.QueryEscape(signature) + return signature, nil +} diff --git a/channel/email.go b/channel/email.go index 21f375d..b87d55e 100644 --- a/channel/email.go +++ b/channel/email.go @@ -14,5 +14,5 @@ func SendEmailMessage(message *Message, user *model.User) error { if subject == "" { subject = message.Title } - return common.SendEmail(subject, user.Email, message.Content) + return common.SendEmail(subject, user.Email, message.HTMLContent) } diff --git a/channel/main.go b/channel/main.go index 21661b8..af22929 100644 --- a/channel/main.go +++ b/channel/main.go @@ -10,7 +10,7 @@ const ( TypeWeChatTestAccount = "test" TypeWeChatCorpAccount = "corp" TypeLark = "lark" - TypeDingTalk = "ding" + TypeDing = "ding" TypeTelegram = "telegram" ) @@ -34,10 +34,9 @@ func (message *Message) Send(user *model.User) error { return SendWeChatCorpMessage(message, user) case TypeLark: return SendLarkMessage(message, user) - case TypeDingTalk: - case TypeTelegram: + case TypeDing: + return SendDingMessage(message, user) default: return errors.New("不支持的消息通道:" + message.Channel) } - return nil } diff --git a/model/user.go b/model/user.go index 7757ac6..273cfdc 100644 --- a/model/user.go +++ b/model/user.go @@ -29,6 +29,8 @@ type User struct { WeChatCorpAccountUserId string `json:"wechat_corp_account_user_id" gorm:"column:wechat_corp_account_user_id"` LarkWebhookURL string `json:"lark_webhook_url"` LarkWebhookSecret string `json:"lark_webhook_secret"` + DingWebhookURL string `json:"ding_webhook_url"` + DingWebhookSecret string `json:"ding_webhook_secret"` } func GetMaxUserId() int {