ding.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. package channel
  2. import (
  3. "bytes"
  4. "crypto/hmac"
  5. "crypto/sha256"
  6. "encoding/base64"
  7. "encoding/json"
  8. "errors"
  9. "fmt"
  10. "message-pusher/model"
  11. "net/http"
  12. "net/url"
  13. "time"
  14. )
  15. type dingMessageRequest struct {
  16. MessageType string `json:"msgtype"`
  17. Text struct {
  18. Content string `json:"content"`
  19. } `json:"text"`
  20. Markdown struct {
  21. Title string `json:"title"`
  22. Text string `json:"text"`
  23. } `json:"markdown"`
  24. }
  25. type dingMessageResponse struct {
  26. Code int `json:"errcode"`
  27. Message string `json:"errmsg"`
  28. }
  29. func SendDingMessage(message *model.Message, user *model.User) error {
  30. if user.DingWebhookURL == "" {
  31. return errors.New("未配置钉钉群机器人消息推送方式")
  32. }
  33. messageRequest := dingMessageRequest{
  34. MessageType: "text",
  35. }
  36. if message.Content == "" {
  37. messageRequest.MessageType = "text"
  38. messageRequest.Text.Content = message.Description
  39. } else {
  40. messageRequest.MessageType = "markdown"
  41. messageRequest.Markdown.Title = message.Title
  42. messageRequest.Markdown.Text = message.Content
  43. }
  44. timestamp := time.Now().UnixMilli()
  45. sign, err := dingSign(user.DingWebhookSecret, timestamp)
  46. if err != nil {
  47. return err
  48. }
  49. jsonData, err := json.Marshal(messageRequest)
  50. if err != nil {
  51. return err
  52. }
  53. resp, err := http.Post(fmt.Sprintf("%s&timestamp=%d&sign=%s", user.DingWebhookURL, timestamp, sign), "application/json",
  54. bytes.NewBuffer(jsonData))
  55. if err != nil {
  56. return err
  57. }
  58. var res dingMessageResponse
  59. err = json.NewDecoder(resp.Body).Decode(&res)
  60. if err != nil {
  61. return err
  62. }
  63. if res.Code != 0 {
  64. return errors.New(res.Message)
  65. }
  66. return nil
  67. }
  68. func dingSign(secret string, timestamp int64) (string, error) {
  69. // https://open.dingtalk.com/document/robots/customize-robot-security-settings
  70. // timestamp + key -> sha256 -> URL encode
  71. stringToSign := fmt.Sprintf("%d\n%s", timestamp, secret)
  72. h := hmac.New(sha256.New, []byte(secret))
  73. _, err := h.Write([]byte(stringToSign))
  74. if err != nil {
  75. return "", err
  76. }
  77. signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
  78. signature = url.QueryEscape(signature)
  79. return signature, nil
  80. }