service/vendor/github.com/CatchZeng/dingtalk/internal/security/security.go

83 lines
2.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package security
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"io"
"math"
"net/url"
"strconv"
"time"
)
// https://oapi.dingtalk.com/robot/send?access_token=xxx
const dingTalkOAPI = "oapi.dingtalk.com"
var dingTalkURL url.URL = url.URL{
Scheme: "https",
Host: dingTalkOAPI,
Path: "robot/send",
}
// URL get DingTalk URL with accessToken & secret
// If no signature is set, the secret is set to ""
// 如果没有加签secret 设置为 "" 即可
func URL(accessToken string, secret string) (string, error) {
timestamp := strconv.FormatInt(time.Now().Unix()*1000, 10)
return URLWithTimestamp(timestamp, accessToken, secret)
}
// URLWithTimestamp get DingTalk URL with timestamp & accessToken & secret
func URLWithTimestamp(timestamp string, accessToken string, secret string) (string, error) {
dtu := dingTalkURL
value := url.Values{}
value.Set("access_token", accessToken)
if secret == "" {
dtu.RawQuery = value.Encode()
return dtu.String(), nil
}
sign, err := sign(timestamp, secret)
if err != nil {
dtu.RawQuery = value.Encode()
return dtu.String(), err
}
value.Set("timestamp", timestamp)
value.Set("sign", sign)
dtu.RawQuery = value.Encode()
return dtu.String(), nil
}
// Validate validate
// https://ding-doc.dingtalk.com/doc#/serverapi2/elzz1p
func Validate(signStr, timestamp, secret string) (bool, error) {
t, err := strconv.ParseInt(timestamp, 10, 64)
if err != nil {
return false, err
}
timeGap := time.Since(time.Unix(t, 0))
if math.Abs(timeGap.Hours()) > 1 {
return false, fmt.Errorf("specified timestamp is expired")
}
ourSign, err := sign(timestamp, secret)
if err != nil {
return false, err
}
return ourSign == signStr, nil
}
func sign(timestamp string, secret string) (string, error) {
stringToSign := fmt.Sprintf("%s\n%s", timestamp, secret)
h := hmac.New(sha256.New, []byte(secret))
if _, err := io.WriteString(h, stringToSign); err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
}