Skip to content

Commit

Permalink
feat: 补充说明签名算法
Browse files Browse the repository at this point in the history
  • Loading branch information
rianli committed Sep 10, 2024
1 parent 43d91ca commit 1c98a8d
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 11 deletions.
59 changes: 54 additions & 5 deletions docs/develop/api-v2/dev-prepare/interface-framework/event-emit.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ QQ机器人开放平台支持通过使用HTTP接口接收事件。开发者可
| **CODE** | **名称** | **客户端行为** | **描述** |
| --- | --- | --- | --- |
| 0 | Dispatch | Receive | 服务端进行消息推送 |
| 12 | HTTP Callback ACK | Reply | 仅用于 http 回调模式的回包,代表机器人收到了平台推送的数据 |
| 13 | 回调地址验证 | Receive | 开放平台对机器人服务端进行验证 |
| 14 | 回调地址验证 ACK | Reply | 机器人服务端响应开放平台的验证请求 |


### 签名校验
机器人服务端需要对回调请求进行签名验证以保证数据没有被篡改过。
Expand All @@ -50,8 +47,8 @@ QQ机器人开放平台支持通过使用HTTP接口接收事件。开发者可
开发者需要提供一个HTTPS回调地址。并选定监听的事件类型。开放平台会将事件通过回调的方式推送给机器人。
<img :src="$withBotBase('/images/api-231017/event_subscription.png')" alt="event_subscription">

开发者配置回调地址时,开放平台会对回调地址进行验证。机器人服务端需要按格式返回签名信息。签名算法同上。 机器人服务端需要在 3 秒内响应200或204,表示接受到事件。
* 请求结构
配置回调地址后,开放平台会对回调地址进行验证
* 请求结构(Payload.d)

| **字段** | **描述** |
| --- |------|
Expand All @@ -65,6 +62,58 @@ QQ机器人开放平台支持通过使用HTTP接口接收事件。开发者可
| plain_token | 要计算hash的字符串 |
| signature | 签名 |

计算过程如下(golang):
```go
func handleValidation(rw http.ResponseWriter, r *http.Request, botSecret string) {
httpBody, err := io.ReadAll(r.Body)
if err != nil {
log.Println("read http body err", err)
return
}
payload := &Payload{}
if err = json.Unmarshal(httpBody, payload); err != nil {
log.Println("parse http payload err", err)
return
}
validationPayload := &ValidationRequest{}
if err = json.Unmarshal(payload.Data, validationPayload);err != nil {
log.Println("parse http payload failed:", err)
return
}
seed := botSecret
for len(seed) < ed25519.SeedSize {
seed = strings.Repeat(seed, 2)
}
seed = seed[:ed25519.SeedSize]
reader := strings.NewReader(seed)
// GenerateKey 方法会返回公钥、私钥,这里只需要私钥进行签名生成不需要返回公钥
_, privateKey, err := ed25519.GenerateKey(reader)
if err != nil {
log.Println("ed25519 generate key failed:", err)
return
}
var msg bytes.Buffer
msg.WriteString(validationPayload.EventTs)
msg.WriteString(validationPayload.PlainToken)
signature := hex.EncodeToString(ed25519.Sign(privateKey, msg.Bytes()))
if err != nil {
log.Println("generate signature failed:", err)
return
}
rspBytes, err := json.Marshal(
&ValidationResponse{
PlainToken: validationPayload.PlainToken,
Signature: signature,
})
if err != nil {
log.Println("handle validation failed:", err)
return
}
rw.Write(rspBytes)
}

```

例如机器人账号
```
appid: 11111111
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
| 9 | Invalid Session | Receive | 当identify或resume的时候,如果参数有错,服务端会返回该消息 |
| 10 | Hello | Receive | 当客户端与网关建立ws连接之后,网关下发的第一条消息 |
| 11 | Heartbeat ACK | Receive/Reply | 当发送心跳成功之后,就会收到该消息 |
| 12 | HTTP Callback ACK | Reply | 仅用于 http 回调模式的回包,代表机器人收到了平台推送的数据 |
| 12 | HTTP Callback ACK | Reply | 仅用于 http 回调模式的回包,代表机器人收到了平台推送的数据() |
| 13 | 回调地址验证 | Receive | 开放平台对机器人服务端进行验证 |


客户端操作含义如下:

Expand Down
12 changes: 7 additions & 5 deletions docs/develop/api-v2/dev-prepare/interface-framework/sign.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,14 @@ privateKey: [110 97 79 67 48 111 99 81 69 51 115 104 87 76 65 102 102 102 86 76
if timestamp == "" {
return false
}
// 按照timstamp+Body顺序组成签名体
httpBody, err := io.ReadAll(req.Body)
if err != nil {
return false
}
// 按照timestamp+Body顺序组成签名体
var msg bytes.Buffer
msg.WriteString(timestamp)
var body bytes.Buffer
// copy body into buffers
_, err = io.Copy(&msg, io.TeeReader(r.Body, &body))
msg.Write(httpBody)
if err != nil {
return false
}
Expand All @@ -81,7 +83,7 @@ privateKey: [110 97 79 67 48 111 99 81 69 51 115 104 87 76 65 102 102 102 86 76
- 根据公钥、Signature、签名体调用 Ed25519 算法进行验证

```go
ed25519.Verify(publicKey, msg.Bytes(), sig)
ed25519.Verify(publicKey, msg.Bytes(), sig)
```

DEMO
Expand Down

0 comments on commit 1c98a8d

Please sign in to comment.