package channel import ( "bytes" "crypto/hmac" "crypto/sha256" "encoding/base64" "encoding/json" "errors" "fmt" "message-pusher/model" "net/http" "strconv" "strings" "time" ) type larkMessageRequestCardElementText struct { Content string `json:"content"` Tag string `json:"tag"` } type larkMessageRequestCardElement struct { Tag string `json:"tag"` Text larkMessageRequestCardElementText `json:"text"` } type larkTextContent struct { Text string `json:"text"` } type larkCardContent struct { Config struct { WideScreenMode bool `json:"wide_screen_mode"` EnableForward bool `json:"enable_forward"` } Elements []larkMessageRequestCardElement `json:"elements"` } type larkMessageRequest struct { MessageType string `json:"msg_type"` Timestamp string `json:"timestamp"` Sign string `json:"sign"` Content larkTextContent `json:"content"` Card larkCardContent `json:"card"` } type larkMessageResponse struct { Code int `json:"code"` Message string `json:"msg"` } func getLarkAtPrefix(message *model.Message) string { atPrefix := "" if message.To != "" { if message.To == "@all" { atPrefix = "所有人" } else { ids := strings.Split(message.To, "|") for _, id := range ids { atPrefix += fmt.Sprintf(" ", id) } } } return atPrefix } func SendLarkMessage(message *model.Message, user *model.User, channel_ *model.Channel) error { // https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN#e1cdee9f messageRequest := larkMessageRequest{ MessageType: "text", } atPrefix := getLarkAtPrefix(message) if message.Content == "" { messageRequest.MessageType = "text" messageRequest.Content.Text = atPrefix + message.Description } else { messageRequest.MessageType = "interactive" messageRequest.Card.Config.WideScreenMode = true messageRequest.Card.Config.EnableForward = true messageRequest.Card.Elements = append(messageRequest.Card.Elements, larkMessageRequestCardElement{ Tag: "div", Text: larkMessageRequestCardElementText{ Content: atPrefix + message.Content, Tag: "lark_md", }, }) } now := time.Now() timestamp := now.Unix() sign, err := larkSign(channel_.Secret, timestamp) if err != nil { return err } messageRequest.Sign = sign messageRequest.Timestamp = strconv.FormatInt(timestamp, 10) jsonData, err := json.Marshal(messageRequest) if err != nil { return err } resp, err := http.Post(channel_.URL, "application/json", bytes.NewBuffer(jsonData)) if err != nil { return err } var res larkMessageResponse err = json.NewDecoder(resp.Body).Decode(&res) if err != nil { return err } if res.Code != 0 { return errors.New(res.Message) } return nil } func larkSign(secret string, timestamp int64) (string, error) { // https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN?lang=zh-CN // timestamp + key -> sha256 -> base64 encode stringToSign := fmt.Sprintf("%v", timestamp) + "\n" + secret var data []byte h := hmac.New(sha256.New, []byte(stringToSign)) _, err := h.Write(data) if err != nil { return "", err } signature := base64.StdEncoding.EncodeToString(h.Sum(nil)) return signature, nil }