Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/master.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: A
on:
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: go build ./...
- name: Run Tests
run: go test ./...
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v2.5.2

2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/tencentyun/tls-sig-api-v2-golang

go 1.16

require github.com/stretchr/testify v1.7.0
128 changes: 123 additions & 5 deletions tencentyun/TLSSigAPI.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"io/ioutil"
"strconv"
"time"
)
Expand All @@ -20,7 +22,6 @@ import (
* userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。
* expire - UserSig 票据的过期时间,单位是秒,比如 86400 代表生成的 UserSig 票据在一天后就无法再使用了。
*/

func GenUserSig(sdkappid int, key string, userid string, expire int) (string, error) {
return genSig(sdkappid, key, userid, expire, nil)
}
Expand Down Expand Up @@ -90,6 +91,7 @@ func GenPrivateMapKeyWithStringRoomID(sdkappid int, key string, userid string, e
var userbuf []byte = genUserBuf(userid, sdkappid, 0, expire, privilegeMap, 0, roomStr)
return genSig(sdkappid, key, userid, expire, userbuf)
}

func genUserBuf(account string, dwSdkappid int, dwAuthID uint32,
dwExpTime int, dwPrivilegeMap uint32, dwAccountType uint32, roomStr string) []byte {

Expand Down Expand Up @@ -183,6 +185,7 @@ func genUserBuf(account string, dwSdkappid int, dwAuthID uint32,

return userBuf
}

func hmacsha256(sdkappid int, key string, identifier string, currTime int64, expire int, base64UserBuf *string) string {
var contentToBeSigned string
contentToBeSigned = "TLS.identifier:" + identifier + "\n"
Expand All @@ -200,8 +203,7 @@ func hmacsha256(sdkappid int, key string, identifier string, currTime int64, exp

func genSig(sdkappid int, key string, identifier string, expire int, userbuf []byte) (string, error) {
currTime := time.Now().Unix()
var sigDoc map[string]interface{}
sigDoc = make(map[string]interface{})
sigDoc := make(map[string]interface{})
sigDoc["TLS.ver"] = "2.0"
sigDoc["TLS.identifier"] = identifier
sigDoc["TLS.sdkappid"] = sdkappid
Expand All @@ -223,7 +225,123 @@ func genSig(sdkappid int, key string, identifier string, expire int, userbuf []b

var b bytes.Buffer
w := zlib.NewWriter(&b)
w.Write(data)
w.Close()
if _, err = w.Write(data); err != nil {
return "", err
}
if err = w.Close(); err != nil {
return "", err
}
return base64urlEncode(b.Bytes()), nil
}

// VerifyUserSig 检验UserSig在now时间点时是否有效
func VerifyUserSig(sdkappid uint64, key string, userid string, usersig string, now time.Time) error {
sig, err := newUserSig(usersig)
if err != nil {
return err
}
return sig.verify(sdkappid, key, userid, now, nil)
}

// VerifyUserSigWithBuf 检验带UserBuf的UserSig在now时间点是否有效
func VerifyUserSigWithBuf(sdkappid uint64, key string, userid string, usersig string, now time.Time, userbuf []byte) error {
sig, err := newUserSig(usersig)
if err != nil {
return err
}
return sig.verify(sdkappid, key, userid, now, userbuf)
}

type userSig struct {
Version string `json:"TLS.ver,omitempty"`
Identifier string `json:"TLS.identifier,omitempty"`
SdkAppID uint64 `json:"TLS.sdkappid,omitempty"`
Expire int64 `json:"TLS.expire,omitempty"`
Time int64 `json:"TLS.time,omitempty"`
UserBuf []byte `json:"TLS.userbuf,omitempty"`
Sig string `json:"TLS.sig,omitempty"`
}

func newUserSig(usersig string) (userSig, error) {
b, err := base64urlDecode(usersig)
if err != nil {
return userSig{}, err
}
r, err := zlib.NewReader(bytes.NewReader(b))
if err != nil {
return userSig{}, err
}
data, err := ioutil.ReadAll(r)
if err != nil {
return userSig{}, err
}
if err = r.Close(); err != nil {
return userSig{}, err
}
var sig userSig
if err = json.Unmarshal(data, &sig); err != nil {
return userSig{}, nil
}
return sig, nil
}

func (u userSig) verify(sdkappid uint64, key string, userid string, now time.Time, userbuf []byte) error {
if sdkappid != u.SdkAppID {
return ErrSdkAppIDNotMatch
}
if userid != u.Identifier {
return ErrIdentifierNotMatch
}
if now.Unix() > u.Time+u.Expire {
return ErrExpired
}
if userbuf != nil {
if u.UserBuf == nil {
return ErrUserBufTypeNotMatch
}
if !bytes.Equal(userbuf, u.UserBuf) {
return ErrUserBufNotMatch
}
} else if u.UserBuf != nil {
return ErrUserBufTypeNotMatch
}
if u.sign(key) != u.Sig {
return ErrSigNotMatch
}
return nil
}

func (u userSig) sign(key string) string {
var sb bytes.Buffer
sb.WriteString("TLS.identifier:")
sb.WriteString(u.Identifier)
sb.WriteString("\n")
sb.WriteString("TLS.sdkappid:")
sb.WriteString(strconv.FormatUint(u.SdkAppID, 10))
sb.WriteString("\n")
sb.WriteString("TLS.time:")
sb.WriteString(strconv.FormatInt(u.Time, 10))
sb.WriteString("\n")
sb.WriteString("TLS.expire:")
sb.WriteString(strconv.FormatInt(u.Expire, 10))
sb.WriteString("\n")
if u.UserBuf != nil {
sb.WriteString("TLS.userbuf:")
sb.WriteString(base64.StdEncoding.EncodeToString(u.UserBuf))
sb.WriteString("\n")
}

h := hmac.New(sha256.New, []byte(key))
h.Write(sb.Bytes())
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

// 错误类型
var (
ErrSdkAppIDNotMatch = errors.New("sdk appid not match")
ErrIdentifierNotMatch = errors.New("identifier not match")
ErrExpired = errors.New("expired")
ErrUserBufTypeNotMatch = errors.New("userbuf type not match")
ErrUserBufNotMatch = errors.New("userbuf not match")
ErrSigNotMatch = errors.New("sig not match")
)
34 changes: 34 additions & 0 deletions tencentyun/TLSSigAPI_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package tencentyun

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGenAndVerify(t *testing.T) {
// 生成签名
now := time.Now()
sig, err := GenUserSig(1, "2", "3", 4)
require.NoError(t, err)
bufSig, err := GenUserSigWithBuf(1, "2", "3", 4, []byte{5})
require.NoError(t, err)

// 验证签名
assert.NoError(t, VerifyUserSig(1, "2", "3", sig, now))
assert.Equal(t, ErrExpired, VerifyUserSig(1, "2", "3", sig, now.Add(time.Hour)))
assert.Equal(t, ErrSdkAppIDNotMatch, VerifyUserSig(2, "2", "3", sig, now))
assert.Equal(t, ErrIdentifierNotMatch, VerifyUserSig(1, "2", "4", sig, now))
assert.Equal(t, ErrSigNotMatch, VerifyUserSig(1, "3", "3", sig, now))
assert.Equal(t, ErrUserBufTypeNotMatch, VerifyUserSig(1, "3", "3", bufSig, now))

assert.NoError(t, VerifyUserSigWithBuf(1, "2", "3", bufSig, now, []byte{5}))
assert.Equal(t, ErrExpired, VerifyUserSigWithBuf(1, "2", "3", bufSig, now.Add(time.Hour), []byte{5}))
assert.Equal(t, ErrSdkAppIDNotMatch, VerifyUserSigWithBuf(2, "2", "3", bufSig, now, []byte{5}))
assert.Equal(t, ErrIdentifierNotMatch, VerifyUserSigWithBuf(1, "2", "4", bufSig, now, []byte{5}))
assert.Equal(t, ErrSigNotMatch, VerifyUserSigWithBuf(1, "3", "3", bufSig, now, []byte{5}))
assert.Equal(t, ErrUserBufTypeNotMatch, VerifyUserSigWithBuf(1, "3", "3", bufSig, now, nil))
assert.Equal(t, ErrUserBufNotMatch, VerifyUserSigWithBuf(1, "3", "3", bufSig, now, []byte{6}))
}