diff --git a/api/core/app_server.go b/api/core/app_server.go index 15450b89..6a09ce99 100644 --- a/api/core/app_server.go +++ b/api/core/app_server.go @@ -186,6 +186,7 @@ func authorizeMiddleware(s *AppServer) gin.HandlerFunc { if c.Request.URL.Path == "/api/user/login" || c.Request.URL.Path == "/api/admin/login" || c.Request.URL.Path == "/api/user/register" || + c.Request.URL.Path == "/api/reward/push" || strings.HasPrefix(c.Request.URL.Path, "/api/sms/") || strings.HasPrefix(c.Request.URL.Path, "/api/captcha/") || strings.HasPrefix(c.Request.URL.Path, "/static/") || diff --git a/api/core/config.go b/api/core/config.go index 2c8a51d2..7308c185 100644 --- a/api/core/config.go +++ b/api/core/config.go @@ -33,8 +33,8 @@ func NewDefaultConfig() *types.AppConfig { HttpOnly: false, SameSite: http.SameSiteLaxMode, }, - ApiConfig: types.ChatPlusApiConfig{}, - StartWechatBot: false, + ApiConfig: types.ChatPlusApiConfig{}, + ChatPlusExtApiToken: utils.RandString(32), } } diff --git a/api/core/types/config.go b/api/core/types/config.go index 1bbec2c1..9a919528 100644 --- a/api/core/types/config.go +++ b/api/core/types/config.go @@ -6,19 +6,19 @@ import ( ) type AppConfig struct { - Path string `toml:"-"` - Listen string - Session Session - ProxyURL string - MysqlDns string // mysql 连接地址 - Manager Manager // 后台管理员账户信息 - StaticDir string // 静态资源目录 - StaticUrl string // 静态资源 URL - Redis RedisConfig // redis 连接信息 - ApiConfig ChatPlusApiConfig // ChatPlus API authorization configs - AesEncryptKey string - SmsConfig AliYunSmsConfig // AliYun send message service config - StartWechatBot bool // 是否启动微信机器人 + Path string `toml:"-"` + Listen string + Session Session + ProxyURL string + MysqlDns string // mysql 连接地址 + Manager Manager // 后台管理员账户信息 + StaticDir string // 静态资源目录 + StaticUrl string // 静态资源 URL + Redis RedisConfig // redis 连接信息 + ApiConfig ChatPlusApiConfig // ChatPlus API authorization configs + AesEncryptKey string + SmsConfig AliYunSmsConfig // AliYun send message service config + ChatPlusExtApiToken string // chatgpt-plus-exts callback api token } type ChatPlusApiConfig struct { diff --git a/api/go.mod b/api/go.mod index f1e0e6ea..9ed4c372 100644 --- a/api/go.mod +++ b/api/go.mod @@ -5,14 +5,12 @@ go 1.19 require ( github.com/BurntSushi/toml v1.1.0 github.com/aliyun/alibaba-cloud-sdk-go v1.62.405 - github.com/eatmoreapple/openwechat v1.2.1 github.com/gin-contrib/sessions v0.0.5 github.com/gin-gonic/gin v1.9.1 github.com/gorilla/websocket v1.5.0 github.com/imroc/req/v3 v3.37.2 github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20230415042440-a5e3d8259ae0 github.com/pkoukk/tiktoken-go v0.1.1-0.20230418101013-cae809389480 - github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/syndtr/goleveldb v1.0.0 go.uber.org/zap v1.23.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 diff --git a/api/go.sum b/api/go.sum index 46b525d8..94cd6f58 100644 --- a/api/go.sum +++ b/api/go.sum @@ -18,8 +18,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0= github.com/dlclark/regexp2 v1.8.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/eatmoreapple/openwechat v1.2.1 h1:ez4oqF/Y2NSEX/DbPV8lvj7JlfkYqvieeo4awx5lzfU= -github.com/eatmoreapple/openwechat v1.2.1/go.mod h1:61HOzTyvLobGdgWhL68jfGNwTJEv0mhQ1miCXQrvWU8= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= @@ -140,8 +138,6 @@ github.com/quic-go/quic-go v0.35.1 h1:b0kzj6b/cQAf05cT0CkQubHM31wiA+xH3IBkxP62po github.com/quic-go/quic-go v0.35.1/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g= github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8= github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvjQpqP7L2vcm/9KUfm/E= -github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= -github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/api/handler/reward_handler.go b/api/handler/reward_handler.go index 53d049ad..0825d7ae 100644 --- a/api/handler/reward_handler.go +++ b/api/handler/reward_handler.go @@ -21,6 +21,50 @@ func NewRewardHandler(server *core.AppServer, db *gorm.DB) *RewardHandler { return &h } +func (h *RewardHandler) Push(c *gin.Context) { + token := c.GetHeader("X-TOKEN") + if token != h.App.Config.ChatPlusExtApiToken { + resp.NotAuth(c) + return + } + + var data struct { + TransId string `json:"trans_id"` // 微信转账交易 ID + Amount float64 `json:"amount"` // 微信转账交易金额 + Remark string `json:"remark"` // 转账备注 + } + if err := c.ShouldBindJSON(&data); err != nil { + resp.ERROR(c, types.InvalidArgs) + return + } + + if data.Amount <= 0 { + resp.ERROR(c, "Amount should not be 0") + return + } + + logger.Infof("收到众筹收款信息: %+v", data) + var item model.Reward + res := h.db.Where("tx_id = ?", data.TransId).First(&item) + if res.Error == nil { + resp.ERROR(c, "当前交易 ID 己经存在!") + return + } + + res = h.db.Create(&model.Reward{ + TxId: data.TransId, + Amount: data.Amount, + Remark: data.Remark, + Status: false, + }) + if res.Error != nil { + logger.Errorf("交易保存失败: %v", res.Error) + resp.ERROR(c, "交易保存失败") + return + } + resp.SUCCESS(c) +} + // Verify 打赏码核销 func (h *RewardHandler) Verify(c *gin.Context) { var data struct { diff --git a/api/main.go b/api/main.go index c713a480..f5140a6e 100644 --- a/api/main.go +++ b/api/main.go @@ -6,7 +6,6 @@ import ( "chatplus/handler" "chatplus/handler/admin" logger2 "chatplus/logger" - "chatplus/modules/wexin" "chatplus/service" "chatplus/service/function" "chatplus/store" @@ -104,17 +103,6 @@ func main() { return xdb.NewWithBuffer(cBuff) }), - // 创建微信机器人 - fx.Provide(wexin.NewWeChatBot), - fx.Invoke(func(bot *wexin.WeChatBot) { - go func() { - err := bot.Login() - if err != nil { - log.Fatal(err) - } - }() - }), - // 创建函数 fx.Provide(func(config *types.AppConfig) (function.FuncZaoBao, error) { return function.NewZaoBao(config.ApiConfig), nil @@ -192,6 +180,7 @@ func main() { }), fx.Invoke(func(s *core.AppServer, h *handler.RewardHandler) { group := s.Engine.Group("/api/reward/") + group.POST("push", h.Push) group.POST("verify", h.Verify) }), diff --git a/api/modules/wexin/handler.go b/api/modules/wexin/handler.go deleted file mode 100644 index 85d24609..00000000 --- a/api/modules/wexin/handler.go +++ /dev/null @@ -1,54 +0,0 @@ -package wexin - -import ( - "chatplus/store/model" - "github.com/eatmoreapple/openwechat" - "github.com/skip2/go-qrcode" - "gorm.io/gorm" -) - -// MessageHandler 消息处理 -func MessageHandler(msg *openwechat.Message, db *gorm.DB) { - sender, err := msg.Sender() - if err != nil { - return - } - - // 只处理微信支付的推送消息 - if sender.NickName == "微信支付" || - msg.MsgType == openwechat.MsgTypeApp || - msg.AppMsgType == openwechat.AppMsgTypeUrl { - // 解析支付金额 - message, err := parseTransactionMessage(msg.Content) - if err == nil { - transaction := extractTransaction(message) - logger.Infof("解析到收款信息:%+v", transaction) - if transaction.Amount <= 0 { - return - } - var item model.Reward - res := db.Where("tx_id = ?", transaction.TransId).First(&item) - if res.Error == nil { - logger.Infof("当前交易 ID %s 己经存在!", transaction.TransId) - return - } - - res = db.Create(&model.Reward{ - TxId: transaction.TransId, - Amount: transaction.Amount, - Remark: transaction.Remark, - Status: false, - }) - if res.Error != nil { - logger.Errorf("交易保存失败,ID: %s", transaction.TransId) - } - } - } -} - -// QrCodeCallBack 登录扫码回调, -func QrCodeCallBack(uuid string) { - logger.Info("请使用微信扫描下面二维码登录") - q, _ := qrcode.New("https://login.weixin.qq.com/l/"+uuid, qrcode.Medium) - logger.Info(q.ToString(true)) -} diff --git a/api/modules/wexin/tranaction.go b/api/modules/wexin/tranaction.go deleted file mode 100644 index 1f7daad7..00000000 --- a/api/modules/wexin/tranaction.go +++ /dev/null @@ -1,68 +0,0 @@ -package wexin - -import ( - "encoding/xml" - "strconv" - "strings" -) - -// Message 转账消息 -type Message struct { - XMLName xml.Name `xml:"msg"` - AppMsg struct { - Des string `xml:"des"` - Url string `xml:"url"` - } `xml:"appmsg"` -} - -// Transaction 解析后的交易信息 -type Transaction struct { - TransId string `json:"trans_id"` // 微信转账交易 ID - Amount float64 `json:"amount"` // 微信转账交易金额 - Remark string `json:"remark"` // 转账备注 -} - -// 解析微信转账消息 -func parseTransactionMessage(xmlData string) (*Message, error) { - var msg Message - if err := xml.Unmarshal([]byte(xmlData), &msg); err != nil { - return nil, err - } - - return &msg, nil -} - -// 导出交易信息 -func extractTransaction(message *Message) Transaction { - var tx = Transaction{} - // 导出交易金额和备注 - lines := strings.Split(message.AppMsg.Des, "\n") - for _, line := range lines { - line = strings.TrimSpace(line) - if len(line) == 0 { - continue - } - // 解析收款金额 - prefix := "收款金额¥" - if strings.HasPrefix(line, prefix) { - if value, err := strconv.ParseFloat(line[len(prefix):], 64); err == nil { - tx.Amount = value - continue - } - } - // 解析收款备注 - prefix = "付款方备注" - if strings.HasPrefix(line, prefix) { - tx.Remark = line[len(prefix):] - break - } - } - - // 解析交易 ID - index := strings.Index(message.AppMsg.Url, "trans_id=") - if index != -1 { - end := strings.LastIndex(message.AppMsg.Url, "&") - tx.TransId = strings.TrimSpace(message.AppMsg.Url[index+9 : end]) - } - return tx -} diff --git a/api/modules/wexin/wechat_bot.go b/api/modules/wexin/wechat_bot.go deleted file mode 100644 index 8ac5f5ec..00000000 --- a/api/modules/wexin/wechat_bot.go +++ /dev/null @@ -1,49 +0,0 @@ -package wexin - -import ( - "chatplus/core/types" - logger2 "chatplus/logger" - "github.com/eatmoreapple/openwechat" - "gorm.io/gorm" -) - -// 微信收款机器人服务 -var logger = logger2.GetLogger() - -type WeChatBot struct { - bot *openwechat.Bot - db *gorm.DB - appConfig *types.AppConfig -} - -func NewWeChatBot(db *gorm.DB, config *types.AppConfig) *WeChatBot { - bot := openwechat.DefaultBot(openwechat.Desktop) - // 注册消息处理函数 - bot.MessageHandler = func(msg *openwechat.Message) { - MessageHandler(msg, db) - } - // 注册登陆二维码回调 - bot.UUIDCallback = QrCodeCallBack - return &WeChatBot{ - bot: bot, - db: db, - appConfig: config, - } -} - -func (b *WeChatBot) Login() error { - if !b.appConfig.StartWechatBot { - return nil - } - - // 创建热存储容器对象 - reloadStorage := openwechat.NewJsonFileHotReloadStorage("storage.json") - // 执行热登录 - err := b.bot.HotLogin(reloadStorage) - if err != nil { - logger.Error("login error: %v", err) - return b.bot.Login() - } - logger.Info("微信登录成功!") - return nil -} diff --git a/api/test/test.go b/api/test/test.go index c6ec4b0a..d7b2dcb2 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -20,6 +20,7 @@ import ( ) func main() { + fmt.Println(utils.RandString(32)) } // Http client 取消操作 diff --git a/api/utils/crypto.go b/api/utils/crypto.go index fbebbf07..dbca8ce8 100644 --- a/api/utils/crypto.go +++ b/api/utils/crypto.go @@ -4,8 +4,11 @@ import ( "bytes" "crypto/aes" "crypto/cipher" + "crypto/sha256" "encoding/base64" "errors" + "fmt" + "io" ) // AesEncrypt 加密 @@ -68,3 +71,14 @@ func pkcs7UnPadding(data []byte) ([]byte, error) { unPadding := int(data[length-1]) return data[:(length - unPadding)], nil } + +func Sha256(data string) string { + hash := sha256.New() + _, err := io.WriteString(hash, data) + if err != nil { + return "" + } + + hashValue := hash.Sum(nil) + return fmt.Sprintf("%x", hashValue) +}