-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
226 lines (215 loc) · 6.51 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/solywsh/qqBot-revue/background"
"github.com/solywsh/qqBot-revue/conf"
"github.com/solywsh/qqBot-revue/cq"
"github.com/solywsh/qqBot-revue/db"
"github.com/thedevsaddam/gojsonq"
"io/ioutil"
"log"
"net/http"
"strconv"
"time"
)
// 定义全局变量
var (
yamlConf *conf.Config
gdb *db.GormDb
)
// 初始化配置
func init() {
yamlConf = conf.NewConf() // 得到配置文件
gdb = db.NewDB() // 初始化操作数据库
}
// revue发送消息api,用于接收
type revueApiPost struct {
Token string `json:"token"` // 加密后的密钥
UserId string `json:"user_id"` // qq号
Message string `json:"message"` // 消息内容
}
// 监听go-cqhttp动作并以此做出反应
func listenFromCqhttp(c *gin.Context) {
var cpf cq.PostForm
if c.ShouldBindBodyWith(&cpf, binding.JSON) == nil {
// 存储记录
gdb.InsertCqPostFrom(cq2db(cpf))
// 对message事件进行响应
if cpf.PostType == "message" {
go cpf.MsgEvent()
}
}
}
func cq2db(form cq.PostForm) db.PostForm {
return db.PostForm{
GroupId: form.GroupId,
Interval: form.Interval,
MetaEventType: form.MetaEventType,
Font: form.Font,
Message: form.Message,
MessageId: form.MessageId,
MessageSeq: form.MessageSeq,
MessageType: form.MessageType,
PostType: form.PostType,
RawMessage: form.RawMessage,
SelfId: form.SelfId,
SubType: form.SubType,
TargetId: form.TargetId,
Time: form.Time,
UserId: form.UserId,
SenderAge: form.Sender.Age,
SenderArea: form.Sender.Area,
SenderCard: form.Sender.Card,
SenderLevel: form.Sender.Level,
SenderNickname: form.Sender.Nickname,
SenderRole: form.Sender.Role,
SenderSex: form.Sender.Sex,
SenderTitle: form.Sender.Title,
SenderUserId: form.Sender.UserId,
StatusAppEnabled: form.Status.AppEnabled,
StatusAppGood: form.Status.Good,
StatusAppInitialized: form.Status.AppInitialized,
StatusGood: form.Status.Good,
StatusOnline: form.Status.Online,
StatusStatPacketReceived: form.Status.Stat.PacketReceived,
StatusStatPacketSent: form.Status.Stat.PacketSent,
StatusStatPacketLost: form.Status.Stat.PacketLost,
StatusStatMessageReceived: form.Status.Stat.MessageReceived,
StatusStatMessageSent: form.Status.Stat.MessageSent,
StatusStatLastMessageTime: form.Status.Stat.LastMessageTime,
StatusStatDisconnectTimes: form.Status.Stat.DisconnectTimes,
StatusStatLostTimes: form.Status.Stat.LostTimes,
DataTime: time.Now().Format("2006-01-02 15:04:05"),
}
}
// SHA1 加密进行鉴权
func hmacSHA1Encrypt(encryptKey string, encryptText []byte) string {
key := []byte(encryptKey)
mac := hmac.New(sha1.New, key)
mac.Write(encryptText)
var str = hex.EncodeToString(mac.Sum(nil))
return str
}
// gin中间件,如果开启反向鉴权(reverseAuthentication)时,对数据进行验证
func ginReverseAuthentication() gin.HandlerFunc {
return func(c *gin.Context) {
if yamlConf.ReverseAuthentication.Enable {
body, _ := ioutil.ReadAll(c.Request.Body)
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body)) // 重设body
headerXSignature := c.Request.Header.Get("X-Signature") // sha1签名
//headerXSelfId := c.Request.Header.Get("X-Self-Id") // 发送消息的qq
if headerXSignature[len("sha1="):] != hmacSHA1Encrypt(yamlConf.ReverseAuthentication.Secret, body) {
c.JSON(
http.StatusForbidden,
gin.H{
"code": http.StatusForbidden,
"msg": "密钥错误",
},
)
c.Abort()
}
}
}
}
// 监听revue发送私聊消息的接口
func listenFromSendPrivateMsg(c *gin.Context) {
// 如果revue没开启直接结束
if !yamlConf.Revue.Enable {
c.Abort()
}
// 如果revue开启了,则进行验证
var rap revueApiPost
if c.ShouldBindBodyWith(&rap, binding.JSON) == nil {
many, i, err := gdb.FindRevueApiTokenMany(db.RevueApiToken{Token: rap.Token})
if err != nil && i != 0 {
c.JSON(
http.StatusInternalServerError,
gin.H{
"code": http.StatusInternalServerError,
"msg": "token查询错误", // 返回错误信息
},
)
} else {
var cpf cq.PostForm
cpf.UserId, _ = strconv.Atoi(many[0].UserId)
msg, err := cpf.SendPrivateMsg(rap.Message)
if err != nil {
c.JSON(
http.StatusInternalServerError,
gin.H{
"code": http.StatusInternalServerError,
"msg": msg, // 返回错误信息
},
)
} else {
c.JSON(
http.StatusOK,
gin.H{
"code": http.StatusOK,
"msg": msg, // 正确返回msg id
},
)
}
}
} else {
c.JSON(
http.StatusBadRequest,
gin.H{
"code": http.StatusBadRequest,
"msg": "请求参数不能识别",
},
)
}
}
// revue接口中间件,对发送的token进行验证
func ginRevueAuthentication() gin.HandlerFunc {
return func(c *gin.Context) {
if yamlConf.ReverseAuthentication.Enable {
if c.Query("message") != "" {
c.JSON(
http.StatusForbidden,
gin.H{
"code": http.StatusForbidden,
"msg": "请数据放入body",
},
)
c.Abort()
return
}
body, _ := ioutil.ReadAll(c.Request.Body)
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body)) // 重设body
pJson := gojsonq.New().JSONString(string(body))
pToken := pJson.Reset().Find("token").(string)
_, i, err := gdb.FindRevueApiTokenMany(db.RevueApiToken{Token: pToken})
if err != nil && i != 1 {
c.JSON(
http.StatusForbidden,
gin.H{
"code": http.StatusForbidden,
"msg": "查询token错误",
},
)
c.Abort() // 结束会话
}
}
}
}
func main() {
background.Services() // 启动后台服务
gin.DisableConsoleColor() // 不显示彩色日志
gin.SetMode(gin.ReleaseMode) // 生产模式,log精简化
router := gin.Default()
// 监听动作并做出反应
router.POST("/", ginReverseAuthentication(), listenFromCqhttp)
// 监听revue提供发送消息的接口
router.POST("/send_private_msg", ginRevueAuthentication(), listenFromSendPrivateMsg)
err := router.Run("0.0.0.0:" + yamlConf.ListenPort)
if err != nil {
log.Println(err)
}
}