1
0

lark.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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. "strconv"
  13. "time"
  14. )
  15. type larkMessageRequestCardElementText struct {
  16. Content string `json:"content"`
  17. Tag string `json:"tag"`
  18. }
  19. type larkMessageRequestCardElement struct {
  20. Tag string `json:"tag"`
  21. Text larkMessageRequestCardElementText `json:"text"`
  22. }
  23. type larkMessageRequest struct {
  24. MessageType string `json:"msg_type"`
  25. Timestamp string `json:"timestamp"`
  26. Sign string `json:"sign"`
  27. Content struct {
  28. Text string `json:"text"`
  29. } `json:"content"`
  30. Card struct {
  31. Config struct {
  32. WideScreenMode bool `json:"wide_screen_mode"`
  33. EnableForward bool `json:"enable_forward"`
  34. }
  35. Elements []larkMessageRequestCardElement `json:"elements"`
  36. } `json:"card"`
  37. }
  38. type larkMessageResponse struct {
  39. Code int `json:"code"`
  40. Message string `json:"msg"`
  41. }
  42. func SendLarkMessage(message *Message, user *model.User) error {
  43. if user.LarkWebhookURL == "" {
  44. return errors.New("未配置飞书群机器人消息推送方式")
  45. }
  46. messageRequest := larkMessageRequest{
  47. MessageType: "text",
  48. }
  49. if message.Content == "" {
  50. messageRequest.MessageType = "text"
  51. messageRequest.Content.Text = message.Description
  52. } else {
  53. messageRequest.MessageType = "interactive"
  54. messageRequest.Card.Config.WideScreenMode = true
  55. messageRequest.Card.Config.EnableForward = true
  56. messageRequest.Card.Elements = append(messageRequest.Card.Elements, larkMessageRequestCardElement{
  57. Tag: "div",
  58. Text: larkMessageRequestCardElementText{
  59. Content: message.Content,
  60. Tag: "lark_md",
  61. },
  62. })
  63. }
  64. now := time.Now()
  65. timestamp := now.Unix()
  66. sign, err := larkSign(user.LarkWebhookSecret, timestamp)
  67. if err != nil {
  68. return err
  69. }
  70. messageRequest.Sign = sign
  71. messageRequest.Timestamp = strconv.FormatInt(timestamp, 10)
  72. jsonData, err := json.Marshal(messageRequest)
  73. if err != nil {
  74. return err
  75. }
  76. resp, err := http.Post(user.LarkWebhookURL, "application/json",
  77. bytes.NewBuffer(jsonData))
  78. if err != nil {
  79. return err
  80. }
  81. var res larkMessageResponse
  82. err = json.NewDecoder(resp.Body).Decode(&res)
  83. if err != nil {
  84. return err
  85. }
  86. if res.Code != 0 {
  87. return errors.New(res.Message)
  88. }
  89. return nil
  90. }
  91. func larkSign(secret string, timestamp int64) (string, error) {
  92. // https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN?lang=zh-CN
  93. // timestamp + key -> sha256 -> base64 encode
  94. stringToSign := fmt.Sprintf("%v", timestamp) + "\n" + secret
  95. var data []byte
  96. h := hmac.New(sha256.New, []byte(stringToSign))
  97. _, err := h.Write(data)
  98. if err != nil {
  99. return "", err
  100. }
  101. signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
  102. return signature, nil
  103. }