diff --git a/gin_server_admin/api/v1/enter.go b/gin_server_admin/api/v1/enter.go index 83486b4..4443115 100644 --- a/gin_server_admin/api/v1/enter.go +++ b/gin_server_admin/api/v1/enter.go @@ -6,6 +6,7 @@ import ( "github.com/flipped-aurora/gin-vue-admin/server/api/v1/examtestpage" "github.com/flipped-aurora/gin-vue-admin/server/api/v1/shiyan" "github.com/flipped-aurora/gin-vue-admin/server/api/v1/system" + "github.com/flipped-aurora/gin-vue-admin/server/api/v1/wechatcallback" ) type ApiGroup struct { @@ -14,6 +15,7 @@ type ApiGroup struct { AutoCodeApiGroup autocode.ApiGroup ShiyanApiGroup shiyan.ApiGroup GroupHandleApiGroup examtestpage.ApiGroup + WeCahtCallBackGroup wechatcallback.ApiGroup } var ApiGroupApp = new(ApiGroup) diff --git a/gin_server_admin/api/v1/examtestpage/healthreportstat.go b/gin_server_admin/api/v1/examtestpage/healthreportstat.go index 962f965..cc0c6b4 100644 --- a/gin_server_admin/api/v1/examtestpage/healthreportstat.go +++ b/gin_server_admin/api/v1/examtestpage/healthreportstat.go @@ -249,7 +249,7 @@ func (h *HealthReportStat) PostReportAnswerListAll(c *gin.Context) { returData["baojinglist"] = readBaoJinf //计算未上报人员 - CalculationNotReport(tadayTime, calCulTime, readDataMap) + // CalculationNotReport(tadayTime, calCulTime, readDataMap) //判断报警人是不是超员 if len(readBaoJinf) > 0 { //给相关人员发送信息 @@ -341,7 +341,7 @@ func (d *dataLockStatistics) getUserAnswerList(jobid, tadayTime string, page int d.mutext.Lock() defer d.mutext.Unlock() calCulTime := tadayTime + " 12:00:00" - fmt.Printf("page ------------> %v\n", page) + // fmt.Printf("page ------------> %v\n", page) // timeStamp := commonus.DateToTimeStamp(calCulTime) // var judgeWriteInfoUser locationing.ReportAddress // getReportAddressErr := global.GVA_DB_HealthReport.Where("calcultime = ?", timeStamp).Take(&judgeWriteInfoUser).Error @@ -358,13 +358,16 @@ func (d *dataLockStatistics) getUserAnswerList(jobid, tadayTime string, page int AdmDivMap := commonus.MapOut() // writeInfoUser.Address = string(msgBtye) countSplit := strings.Split(v_sun.Text, "省") - + xieRuBaoJong := false + var groupIdCont int64 + groupIdCont = 0 if len(countSplit) >= 2 { writeInfoUser.WechatId = v.Userid writeInfoUser.Userid = v.Userid writeInfoUser.AddTime = time.Now().Unix() writeInfoUser.Address = v_sun.Text AdmDivMap["riskLevel"] = 0 + writeInfoUser.RiskLevel = 0 writeInfoUser.CalCulTime = commonus.DateToTimeStamp(calCulTime) @@ -393,6 +396,9 @@ func (d *dataLockStatistics) getUserAnswerList(jobid, tadayTime string, page int if riskAre.CityName == countSplitSun[0] { writeInfoUser.RiskLevel = riskAre.RiskLevel AdmDivMap["riskLevel"] = riskAre.RiskLevel + // commonus.WriteInMan(v.Userid) + xieRuBaoJong = true + } } } @@ -409,6 +415,8 @@ func (d *dataLockStatistics) getUserAnswerList(jobid, tadayTime string, page int writeInfoUser.RiskLevel = riskAre.RiskLevel writeInfoUser.RiskLevel = riskAre.RiskLevel AdmDivMap["riskLevel"] = riskAre.RiskLevel + // commonus.WriteInMan(v.Userid) + xieRuBaoJong = true } } } @@ -470,12 +478,14 @@ func (d *dataLockStatistics) getUserAnswerList(jobid, tadayTime string, page int if len(arrAy) >= 2 { if arrAy[0] == 1 { writeInfoUser.GroupId = arrAy[1] + groupIdCont = arrAy[1] isTrues, myDepartments := commonus.GetGroupInfo(arrAy[1]) if isTrues == true { writeInfoUser.GroupName = fmt.Sprintf("%s", myDepartments.Name) } } else { writeInfoUser.GroupId = arrAy[0] + groupIdCont = arrAy[0] isTrues, myDepartments := commonus.GetGroupInfo(arrAy[0]) if isTrues == true { writeInfoUser.GroupName = fmt.Sprintf("%s", myDepartments.Name) @@ -484,6 +494,9 @@ func (d *dataLockStatistics) getUserAnswerList(jobid, tadayTime string, page int } } } + if xieRuBaoJong == true { + commonus.WriteInMan(v.Userid, calCulTime, groupIdCont) + } // writeInfoUser.MainDepartment = AdmDivStruct = append(AdmDivStruct, AdmDiv) d.dataMap = append(d.dataMap, AdmDivMap) diff --git a/gin_server_admin/api/v1/examtestpage/healthreportstathand.go b/gin_server_admin/api/v1/examtestpage/healthreportstathand.go index ef227b1..7b693c4 100644 --- a/gin_server_admin/api/v1/examtestpage/healthreportstathand.go +++ b/gin_server_admin/api/v1/examtestpage/healthreportstathand.go @@ -10,6 +10,7 @@ import ( "github.com/flipped-aurora/gin-vue-admin/server/commonus" "github.com/flipped-aurora/gin-vue-admin/server/global" "github.com/flipped-aurora/gin-vue-admin/server/model/common/response" + "github.com/flipped-aurora/gin-vue-admin/server/model/location" "github.com/flipped-aurora/gin-vue-admin/server/model/locationing" "github.com/flipped-aurora/gin-vue-admin/server/model/wechat" "github.com/gin-gonic/gin" @@ -438,82 +439,8 @@ func (h *HealthReportStat) NotReportedPeople(c *gin.Context) { //获取全国风险地区列表(企鹅接口 https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5) func (h *HealthReportStat) NationalRiskArea(c *gin.Context) { - // nationalRiskArea := commonus.NationalRiskArea() - // var tencentJsonData commonus.TencentJsonData - // jsonErr := json.Unmarshal(nationalRiskArea, &tencentJsonData) - // if jsonErr != nil { - // response.Result(101, jsonErr, "未能全国风险地区数据!", c) - // return - // } - // var DataJSonTencent commonus.DataJSonTencent - // zhuanyi := json.RawMessage(tencentJsonData.Data) - // jsonErrs := json.Unmarshal(zhuanyi, &DataJSonTencent) - // if jsonErrs != nil { - // response.Result(102, zhuanyi, "未能全国风险地区数据!", c) - // return - // } - // var regionalRiskAry []commonus.RegionalRiskLevel - // for _, chinaAry := range DataJSonTencent.AreaTree { //国家级 - // for _, provinceAry := range chinaAry.Children { //省级 - // for _, cityAry := range provinceAry.Children { //市级 - - // var regionalRisk commonus.RegionalRiskLevel - // regionalRisk.ProvinceName = provinceAry.Name - // regionalRisk.CityName = cityAry.Name - // regionalRisk.RiskText = cityAry.Total.Grade - - // countSplit := strings.Split(cityAry.Total.Grade, "中高") - // regionalRisk.Province = int64(len(countSplit)) - // //0:无;1:低风险;2:中低风险;3:中风险;4:中高风险;5:高风险 - - // if len(countSplit) >= 2 { - // regionalRisk.RiskLevel = 4 - // } else { - // countSplits := strings.Split(cityAry.Total.Grade, "中低") - // regionalRisk.City = int64(len(countSplits)) - // if len(countSplits) >= 2 { - // regionalRisk.RiskLevel = 2 - // } else { - // countSplitcont := strings.Split(cityAry.Total.Grade, "中") - // regionalRisk.County = int64(len(countSplitcont)) - // if len(countSplitcont) >= 2 { - // regionalRisk.RiskLevel = 3 - // } else { - // countSpliHigh := strings.Split(cityAry.Total.Grade, "高") - // regionalRisk.County = int64(len(countSpliHigh)) - // if len(countSpliHigh) >= 2 { - // regionalRisk.RiskLevel = 5 - // } - // countSpliLown := strings.Split(cityAry.Total.Grade, "低") - // regionalRisk.County = int64(len(countSpliLown)) - // if len(countSpliLown) >= 2 { - // regionalRisk.RiskLevel = 1 - // } - // } - // } - // } - - // regionalRiskAry = append(regionalRiskAry, regionalRisk) - // // fmt.Printf("%v\n", cityAry.Name) - // } - // } - // } - // regionalRiskJson, regionalRiskjsonErr := json.Marshal(regionalRiskAry) - // if regionalRiskjsonErr == nil { - - // } jsondata, isyes := commonus.GetNationalRiskArea() returnData := commonus.MapOut() - // var chianMap commonus.DataJSonTencent - // for i, v := range zhuanyi { - // fmt.Printf("%v---------------->%v\n", i, string(v)) - // } - // returnData["jsonStr"] = string(tencentJsonData.Data) - // returnData["DataJSonTencent"] = DataJSonTencent - // returnData["china"] = DataJSonTencent.AreaTree - // returnData["regionalRiskAry"] = regionalRiskAry - // returnData["regionalRiskJson"] = string(regionalRiskJson) - // returnData["zhuanyi"] = zhuanyi returnData["isyes"] = isyes returnData["jsondata"] = jsondata @@ -521,3 +448,13 @@ func (h *HealthReportStat) NationalRiskArea(c *gin.Context) { response.Result(0, returnData, "全国风险地区列表!", c) } + +//测试写入异常人员 +func (h *HealthReportStat) TestMan(c *gin.Context) { + var reportAnswer location.AbnormalPeople + c.ShouldBindJSON(&reportAnswer) + commonus.WriteInMan(reportAnswer.WechatId, "2021-12-04", 1) + returnData := commonus.MapOut() + returnData["isyes"] = reportAnswer + response.Result(0, returnData, "全国风险地区列表!", c) +} diff --git a/gin_server_admin/api/v1/wechatcallback/enter.go b/gin_server_admin/api/v1/wechatcallback/enter.go new file mode 100644 index 0000000..a9dd4c1 --- /dev/null +++ b/gin_server_admin/api/v1/wechatcallback/enter.go @@ -0,0 +1,5 @@ +package wechatcallback + +type ApiGroup struct { + WeChatCallBackApi +} diff --git a/gin_server_admin/api/v1/wechatcallback/wechatcallbackmain.go b/gin_server_admin/api/v1/wechatcallback/wechatcallbackmain.go new file mode 100644 index 0000000..b70539b --- /dev/null +++ b/gin_server_admin/api/v1/wechatcallback/wechatcallbackmain.go @@ -0,0 +1,31 @@ +package wechatcallback + +import ( + "github.com/flipped-aurora/gin-vue-admin/server/model/common/response" + "github.com/flipped-aurora/gin-vue-admin/server/wechatjiexi/wxbizmsgcrypt" + "github.com/gin-gonic/gin" +) + +type WeChatCallBackApi struct{} + +type MsgContent struct { + ToUsername string `xml:"ToUserName"` + FromUsername string `xml:"FromUserName"` + CreateTime uint32 `xml:"CreateTime"` + MsgType string `xml:"MsgType"` + Content string `xml:"Content"` + Msgid string `xml:"MsgId"` + Agentid uint32 `xml:"AgentId"` +} + +//回调首页 +func (w *WeChatCallBackApi) Index(c *gin.Context) { + + token := "QDG6eK" + receiverId := "wx5823bf96d3bd56c7" + encodingAeskey := "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C" + + wxcpt := wxbizmsgcrypt.NewWXBizMsgCrypt(token, encodingAeskey, receiverId, wxbizmsgcrypt.XmlType) + + response.Result(0, wxcpt, "获取成功", c) +} diff --git a/gin_server_admin/commonus/publichaneld.go b/gin_server_admin/commonus/publichaneld.go index c7e65c1..4aa7863 100644 --- a/gin_server_admin/commonus/publichaneld.go +++ b/gin_server_admin/commonus/publichaneld.go @@ -8,6 +8,7 @@ import ( "time" "github.com/flipped-aurora/gin-vue-admin/server/global" + "github.com/flipped-aurora/gin-vue-admin/server/model/location" "github.com/flipped-aurora/gin-vue-admin/server/model/testpage" "github.com/flipped-aurora/gin-vue-admin/server/model/wechat" "github.com/flipped-aurora/gin-vue-admin/server/utils/redishandel" @@ -54,13 +55,30 @@ func BubbleSort(slice []int64) []int64 { //获取公司,分厂,工段 func GetGroupInfo(id int64) (isTrue bool, groupStruct wechat.GroupForm) { isTrue = false - var groupStructs wechat.GroupForm //集团表结构 - err := global.GVA_DB_WatchDate.Where("g_id = ?", id).First(&groupStruct).Error //获取集团信息 - if err != nil { - groupStruct, isTrue = AddWechatGroup(id, groupStructs) - return + redisClient := redishandel.RunRedis() + isTrues, tokenInfo := redisClient.Get("organStructure:group_" + global.GVA_CONFIG.RedisPrefix.Alias + "_" + strconv.FormatInt(id, 10)) + if isTrues == true { + jsonUserList := json.Unmarshal([]byte(tokenInfo), &groupStruct) + if jsonUserList != nil { + return + } + isTrue = true + } else { + var groupStructs wechat.GroupForm //集团表结构 + err := global.GVA_DB_WatchDate.Where("g_id = ?", id).First(&groupStruct).Error //获取集团信息 + if err != nil { + groupStruct, isTrue = AddWechatGroup(id, groupStructs) + return + } + jsonUserList, jsonErr := json.Marshal(groupStruct) + if jsonErr != nil { + return + } + redisClient.SetRedisTime(604800) + redisClient.Set("organStructure:group_"+global.GVA_CONFIG.RedisPrefix.Alias+"_"+strconv.FormatInt(id, 10), string(jsonUserList)) + isTrue = true } - isTrue = true + // groupInfo["name"] = groupStruct.Name return } @@ -431,6 +449,7 @@ func GetNationalRiskArea() (riskAreaCityList []RegionalRiskLevel, isTrue bool) { regionalRisk.ProvinceName = provinceAry.Name regionalRisk.CityName = cityAry.Name regionalRisk.RiskText = cityAry.Total.Grade + regionalRisk.RiskLevel = 0 //切分数据结果,判断风险等级 countSplit := strings.Split(cityAry.Total.Grade, "中高") regionalRisk.Province = int64(len(countSplit)) @@ -484,3 +503,32 @@ func GetNationalRiskArea() (riskAreaCityList []RegionalRiskLevel, isTrue bool) { } return } + +//写入异常人员列表 +func WriteInMan(wechat, calCulTime string, groupId int64) { + if wechat == "" { + return + } + timeVal := time.Now().Unix() - 86400 + if calCulTime != "" { + timeVals, errTime := DateToTimeStampEs(calCulTime) + if errTime == true { + timeVal = timeVals + } + } + + var abn location.AbnormalPeople + abnErr := global.GVA_DB_HealthReport.Where("abn_wechat_id = ?", wechat).First(&abn).Error + if abnErr != nil { + abn.WechatId = wechat + abn.GroupId = groupId + abn.Time = timeVal + global.GVA_DB_HealthReport.Create(&abn) + // fmt.Printf("Add -----> %v ------>%v\n", abnErr, abn) + } else { + abn.GroupId = groupId + abn.Time = timeVal + global.GVA_DB_HealthReport.Save(&abn) + // fmt.Printf("Eite -----> %v ------>%v\n", abnErr, abn) + } +} diff --git a/gin_server_admin/commonus/timeSub.go b/gin_server_admin/commonus/timeSub.go index 1d62c3c..5fbe38d 100644 --- a/gin_server_admin/commonus/timeSub.go +++ b/gin_server_admin/commonus/timeSub.go @@ -115,6 +115,17 @@ func DateToTimeStamp(dataStr string) (timeStamp int64) { return } +func DateToTimeStampEs(dataStr string) (timeStamp int64, isTrue bool) { + isTrue = false + tmp := "2006-01-02 15:04:05" + res, err := time.ParseInLocation(tmp, dataStr, time.Local) + timeStamp = res.Unix() + if err == nil { + isTrue = true + } + return +} + /* 时间戳转日期 */ diff --git a/gin_server_admin/commonus/wechatapp.go b/gin_server_admin/commonus/wechatapp.go index 12667dc..1e80a44 100644 --- a/gin_server_admin/commonus/wechatapp.go +++ b/gin_server_admin/commonus/wechatapp.go @@ -579,7 +579,7 @@ func GetUserWriteAnswer(jobid, date string, page int, pageSize int64) (btyDate [ } addDePartMent := CurlPostJosn(getWechatApiUrl, sendJsonData) btyDate = addDePartMent - + fmt.Printf("结果---->%v\n", string(addDePartMent)) var reportAnswerJson ReportAnswerResult err = json.Unmarshal(addDePartMent, &reportAnswerJson) r = &reportAnswerJson diff --git a/gin_server_admin/config.yaml b/gin_server_admin/config.yaml index 8b610c4..e901932 100644 --- a/gin_server_admin/config.yaml +++ b/gin_server_admin/config.yaml @@ -273,6 +273,8 @@ workwechatschool: #知行学院 workwechatappmaillist: #通讯录 secretstr: 'yjcQXkh6_116QKjfZfbRSyzdrFFZ9jbVlKJtL2tn3OU' + token: '' + encodingaeskey: '' healthreport: #健康上报 secretstr: 'smjpGmFo5wp18BZGiLaECFr84Blv429v_GFdKp4_0YQ' @@ -287,6 +289,13 @@ workwechatschools: #测试 workwechatappmaillists: #通讯录 secretstr: 'TSSsJXiqh3RKl0NYIoB-sPc43MUIRJ1ppALWtzyLY94' + token: '' + encodingaeskey: '' healthreports: #健康上报 - secretstr: 'smjpGmFo5wp18BZGiLaECFr84Blv429v_GFdKp4_0YQ' \ No newline at end of file + secretstr: 'smjpGmFo5wp18BZGiLaECFr84Blv429v_GFdKp4_0YQ' + + + + + \ No newline at end of file diff --git a/gin_server_admin/config/wechat.go b/gin_server_admin/config/wechat.go index 9a7f60f..ab4c448 100644 --- a/gin_server_admin/config/wechat.go +++ b/gin_server_admin/config/wechat.go @@ -15,5 +15,7 @@ type workWechatApplication struct { //企业微信内置应用 type workWechatSecret struct { - SecretStr string `json:secretstr` //应用Secret + SecretStr string `json:secretstr` //应用Secret + Token string `json:Token` //应用Secret + EncodingAESKey string `json:EncodingAESKey` //应用Secret } diff --git a/gin_server_admin/initialize/router.go b/gin_server_admin/initialize/router.go index e8a1e05..3201df4 100644 --- a/gin_server_admin/initialize/router.go +++ b/gin_server_admin/initialize/router.go @@ -44,8 +44,13 @@ func Routers() *gin.Engine { groupHandleRouter := router.RouterGroupApp.GroupHandle + weChatCallBaclRouter := router.RouterGroupApp.WeChatCallBacl + PublicGroup := Router.Group("") { + PublicGroup.GET("/", func(c *gin.Context) { + c.JSON(0, "is ok") + }) // 健康监测 PublicGroup.GET("/health", func(c *gin.Context) { c.JSON(200, "ok") @@ -60,6 +65,8 @@ func Routers() *gin.Engine { groupHandleRouter.InitGroupRouter(PublicGroup) //集团架构 shiyanRouter.InitShiyanRouter(PublicGroup) // 实验路由 + + weChatCallBaclRouter.InitGroupRouter(PublicGroup) // 微信回调 } PrivateGroup := Router.Group("") PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler()) diff --git a/gin_server_admin/model/location/abnormal_people.go b/gin_server_admin/model/location/abnormal_people.go new file mode 100644 index 0000000..603f103 --- /dev/null +++ b/gin_server_admin/model/location/abnormal_people.go @@ -0,0 +1,12 @@ +package location + +type AbnormalPeople struct { + Id int64 `json:"id" gorm:"column:abn_id;type:bigint(20);;primaryKey;unique;not null;autoIncrement;index"` + WechatId string `json:"wechatid" gorm:"column:abn_wechat_id;type:varchar(50);not null;comment:微信id"` + Time int64 `json:"time" gorm:"column:abn_time;type:bigint(20) unsigned;default:0;not null;comment:异常开始时间"` //'异常开始时间', + GroupId int64 `json:"groupId" gorm:"column:abn_group;type:bigint(20) unsigned;default:1;not null;comment:组织"` //'组织', +} + +func (AbnormalPeople *AbnormalPeople) TableName() string { + return "abnormal_people" +} diff --git a/gin_server_admin/model/locationing/reportAddress.go b/gin_server_admin/model/locationing/reportAddress.go index dbf45db..4b4d1db 100644 --- a/gin_server_admin/model/locationing/reportAddress.go +++ b/gin_server_admin/model/locationing/reportAddress.go @@ -17,7 +17,7 @@ type ReportAddress struct { MainDepartment int64 `json:"main_department" gorm:"column:main_department;type:bigint(20) unsigned;default:0;not null;comment:主部门"` //'主部门', GroupName string `json:"groupName" gorm:"column:group_name;type:varchar(255);comment:集团名称"` //'集团名称', GroupId int64 `json:"groupId" gorm:"column:group_id;type:bigint(20) unsigned;default:1;not null;comment:集团id"` //'集团id', - RiskLevel int `json:"riskLevel" gorm:"column:risk_level;type:int(3) unsigned;default:1;not null;comment:风险等级"` //'风险等级', + RiskLevel int `json:"riskLevel" gorm:"column:risk_level;type:int(3) unsigned;default:0;not null;comment:风险等级"` //'风险等级', } func (ReportAddress *ReportAddress) TableName() string { diff --git a/gin_server_admin/router/enter.go b/gin_server_admin/router/enter.go index aaf71f1..f53dd92 100644 --- a/gin_server_admin/router/enter.go +++ b/gin_server_admin/router/enter.go @@ -6,14 +6,16 @@ import ( "github.com/flipped-aurora/gin-vue-admin/server/router/examtestpage" "github.com/flipped-aurora/gin-vue-admin/server/router/shiyan" "github.com/flipped-aurora/gin-vue-admin/server/router/system" + "github.com/flipped-aurora/gin-vue-admin/server/router/wechatcallbackrouter" ) type RouterGroup struct { - System system.RouterGroup - Example example.RouterGroup - Autocode autocode.RouterGroup - Shiyan shiyan.RouterGroup - GroupHandle examtestpage.RouterGroup + System system.RouterGroup + Example example.RouterGroup + Autocode autocode.RouterGroup + Shiyan shiyan.RouterGroup + GroupHandle examtestpage.RouterGroup + WeChatCallBacl wechatcallbackrouter.RouterGroup } var RouterGroupApp = new(RouterGroup) diff --git a/gin_server_admin/router/examtestpage/healthreporthandle.go b/gin_server_admin/router/examtestpage/healthreporthandle.go index fe54953..f563c2a 100644 --- a/gin_server_admin/router/examtestpage/healthreporthandle.go +++ b/gin_server_admin/router/examtestpage/healthreporthandle.go @@ -34,6 +34,8 @@ func (g *GroupHandleRouter) InitHealthReporRouter(Router *gin.RouterGroup) (R gi groupCodeRouter.POST("/nationalriskarea", authorityApi.NationalRiskArea) //全国异常地区 + groupCodeRouter.POST("/testman", authorityApi.TestMan) //测试 + } return groupCodeRouter } diff --git a/gin_server_admin/router/wechatcallbackrouter/enter.go b/gin_server_admin/router/wechatcallbackrouter/enter.go new file mode 100644 index 0000000..8535659 --- /dev/null +++ b/gin_server_admin/router/wechatcallbackrouter/enter.go @@ -0,0 +1,5 @@ +package wechatcallbackrouter + +type RouterGroup struct { + WeChatCallBackRoute +} diff --git a/gin_server_admin/router/wechatcallbackrouter/wechatcallbackhandle.go b/gin_server_admin/router/wechatcallbackrouter/wechatcallbackhandle.go new file mode 100644 index 0000000..09f9cc2 --- /dev/null +++ b/gin_server_admin/router/wechatcallbackrouter/wechatcallbackhandle.go @@ -0,0 +1,19 @@ +package wechatcallbackrouter + +import ( + v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1" + "github.com/gin-gonic/gin" +) + +type WeChatCallBackRoute struct{} + +func (g *WeChatCallBackRoute) InitGroupRouter(Router *gin.RouterGroup) { + groupCodeRouter := Router.Group("wechatcallback") + var authorityApi = v1.ApiGroupApp.WeCahtCallBackGroup.WeChatCallBackApi + { + groupCodeRouter.POST("", authorityApi.Index) + groupCodeRouter.POST("/", authorityApi.Index) + groupCodeRouter.GET("/", authorityApi.Index) + + } +} diff --git a/gin_server_admin/wechatjiexi/wxbizjsonmsgcrypt/wxbizjsonmsgcrypt.go b/gin_server_admin/wechatjiexi/wxbizjsonmsgcrypt/wxbizjsonmsgcrypt.go new file mode 100644 index 0000000..689cc84 --- /dev/null +++ b/gin_server_admin/wechatjiexi/wxbizjsonmsgcrypt/wxbizjsonmsgcrypt.go @@ -0,0 +1,313 @@ +package wxbizjsonmsgcrypt + +import( + "crypto/sha1" + "crypto/aes" + "crypto/cipher" + "bytes" + "strings" + "fmt" + "sort" + "encoding/base64" + "math/rand" + "encoding/binary" + "encoding/json" +) + +const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +const ( + ValidateSignatureError int = -40001 + ParseJsonError int = -40002 + ComputeSignatureError int = -40003 + IllegalAesKey int = -40004 + ValidateCorpidError int = -40005 + EncryptAESError int = -40006 + DecryptAESError int = -40007 + IllegalBuffer int = -40008 + EncodeBase64Error int = -40009 + DecodeBase64Error int = -40010 + GenJsonError int = -40011 + IllegalProtocolType int = -40012 +) + +type ProtocolType int +const ( + JsonType ProtocolType = 1 +) + +type CryptError struct{ + ErrCode int + ErrMsg string +} + +func NewCryptError(err_code int, err_msg string) * CryptError{ + return &CryptError{ErrCode:err_code, ErrMsg: err_msg} +} + +type WXBizJsonMsg4Recv struct { + Tousername string `json:"tousername"` + Encrypt string `json:"encrypt"` + Agentid string `json:"agentid"` +} + + +type WXBizJsonMsg4Send struct { + Encrypt string `json:"encrypt"` + Signature string `json:"msgsignature"` + Timestamp string `json:"timestamp"` + Nonce string `json:"nonce"` +} + +func NewWXBizJsonMsg4Send(encrypt, signature, timestamp, nonce string) * WXBizJsonMsg4Send { + return &WXBizJsonMsg4Send{Encrypt:encrypt, Signature:signature, Timestamp:timestamp, Nonce:nonce} +} + +type ProtocolProcessor interface { + parse(src_data []byte) (* WXBizJsonMsg4Recv, * CryptError) + serialize(msg_send * WXBizJsonMsg4Send) ([]byte, * CryptError) +} + +type WXBizMsgCrypt struct{ + token string + encoding_aeskey string + receiver_id string + protocol_processor ProtocolProcessor +} + +type JsonProcessor struct{ +} + +func (self * JsonProcessor) parse(src_data []byte) (* WXBizJsonMsg4Recv, * CryptError) { + var msg4_recv WXBizJsonMsg4Recv + err := json.Unmarshal(src_data, &msg4_recv) + if nil != err { + fmt.Println("Unmarshal fail", err) + return nil, NewCryptError(ParseJsonError, "json to msg fail") + } + return &msg4_recv, nil +} + +func (self * JsonProcessor) serialize(msg4_send * WXBizJsonMsg4Send) ([]byte, * CryptError){ + json_msg, err := json.Marshal(msg4_send) + if nil != err { + return nil, NewCryptError(GenJsonError, err.Error()) + } + + return json_msg, nil +} + +func NewWXBizMsgCrypt(token, encoding_aeskey, receiver_id string, protocol_type ProtocolType) * WXBizMsgCrypt{ + var protocol_processor ProtocolProcessor + if protocol_type != JsonType { + panic("unsupport protocal") + } else { + protocol_processor = new(JsonProcessor) + } + + return &WXBizMsgCrypt{token:token, encoding_aeskey:(encoding_aeskey+"="), receiver_id:receiver_id, protocol_processor:protocol_processor} +} + +func (self * WXBizMsgCrypt) randString(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letterBytes[rand.Int63() % int64(len(letterBytes))] + } + return string(b) +} + +func (self * WXBizMsgCrypt) pKCS7Padding(plaintext string, block_size int) []byte { + padding := block_size- (len(plaintext) % block_size) + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + var buffer bytes.Buffer + buffer.WriteString(plaintext) + buffer.Write(padtext) + return buffer.Bytes() +} + +func (self * WXBizMsgCrypt) pKCS7Unpadding(plaintext []byte, block_size int) ([]byte, * CryptError) { + plaintext_len := len(plaintext) + if nil == plaintext || plaintext_len == 0 { + return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding error nil or zero") + } + if plaintext_len % block_size != 0 { + return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding text not a multiple of the block size") + } + padding_len := int(plaintext[plaintext_len - 1]) + return plaintext[:plaintext_len - padding_len], nil +} + +func (self * WXBizMsgCrypt) cbcEncrypter(plaintext string) ([]byte, * CryptError) { + aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey) + if nil != err { + return nil, NewCryptError(DecodeBase64Error, err.Error()) + } + const block_size = 32 + pad_msg := self.pKCS7Padding(plaintext, block_size) + + block, err := aes.NewCipher(aeskey) + if err != nil { + return nil, NewCryptError(EncryptAESError, err.Error()) + } + + ciphertext := make([]byte, len(pad_msg)) + iv := aeskey[:aes.BlockSize] + + mode := cipher.NewCBCEncrypter(block, iv) + + mode.CryptBlocks(ciphertext, pad_msg) + base64_msg := make([]byte, base64.StdEncoding.EncodedLen(len(ciphertext))) + base64.StdEncoding.Encode(base64_msg, ciphertext) + + return base64_msg, nil +} + +func (self * WXBizMsgCrypt) cbcDecrypter(base64_encrypt_msg string) ([]byte, * CryptError){ + aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey) + if nil != err { + return nil, NewCryptError(DecodeBase64Error, err.Error()) + } + + encrypt_msg, err := base64.StdEncoding.DecodeString(base64_encrypt_msg) + if nil != err { + return nil, NewCryptError(DecodeBase64Error, err.Error()) + } + + block, err := aes.NewCipher(aeskey) + if err != nil { + return nil, NewCryptError(DecryptAESError, err.Error()) + } + + if len(encrypt_msg) < aes.BlockSize { + return nil, NewCryptError(DecryptAESError, "encrypt_msg size is not valid") + } + + iv := aeskey[:aes.BlockSize] + + if len(encrypt_msg) % aes.BlockSize != 0 { + return nil, NewCryptError(DecryptAESError, "encrypt_msg not a multiple of the block size") + } + + mode := cipher.NewCBCDecrypter(block, iv) + + mode.CryptBlocks(encrypt_msg, encrypt_msg) + + return encrypt_msg, nil +} + +func (self * WXBizMsgCrypt) calSignature(timestamp, nonce, data string) string{ + sort_arr := []string{self.token, timestamp, nonce, data} + sort.Strings(sort_arr); + var buffer bytes.Buffer + for _, value := range sort_arr { + buffer.WriteString(value) + } + + sha := sha1.New() + sha.Write(buffer.Bytes()) + signature := fmt.Sprintf("%x", sha.Sum(nil)) + return string(signature) +} + +func (self * WXBizMsgCrypt) ParsePlainText(plaintext[]byte)([]byte, uint32, []byte, []byte, * CryptError){ + const block_size = 32 + plaintext, err := self.pKCS7Unpadding(plaintext, block_size) + if nil != err { + return nil, 0, nil, nil, err + } + + text_len := uint32(len(plaintext)) + if text_len < 20 { + return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 1") + } + random := plaintext[:16] + msg_len := binary.BigEndian.Uint32(plaintext[16:20]) + if text_len < (20 + msg_len) { + return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 2") + } + + msg := plaintext[20: 20 + msg_len] + receiver_id := plaintext[20+msg_len:] + + return random, msg_len, msg, receiver_id, nil +} + +func (self * WXBizMsgCrypt) VerifyURL(msg_signature, timestamp, nonce, echostr string) ([]byte, * CryptError){ + signature := self.calSignature(timestamp, nonce, echostr) + + if strings.Compare(signature, msg_signature) != 0{ + return nil, NewCryptError(ValidateSignatureError, "signature not equal") + } + + plaintext, err := self.cbcDecrypter(echostr) + if nil != err { + return nil, err + } + + _, _, msg, receiver_id, err := self.ParsePlainText(plaintext) + if nil != err { + return nil, err + } + + if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 { + fmt.Println(string(receiver_id), self.receiver_id, len(receiver_id), len(self.receiver_id)) + return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil") + } + + return msg, nil +} + + +func (self * WXBizMsgCrypt) EncryptMsg(reply_msg, timestamp, nonce string) ([]byte, * CryptError){ + rand_str := self.randString(16) + var buffer bytes.Buffer + buffer.WriteString(rand_str) + + msg_len_buf := make([]byte, 4) + binary.BigEndian.PutUint32(msg_len_buf, uint32(len(reply_msg))) + buffer.Write(msg_len_buf) + buffer.WriteString(reply_msg); + buffer.WriteString(self.receiver_id); + + tmp_ciphertext, err := self.cbcEncrypter(buffer.String()); + if nil != err { + return nil, err + } + ciphertext := string(tmp_ciphertext) + + signature := self.calSignature(timestamp, nonce, ciphertext) + + msg4_send := NewWXBizJsonMsg4Send(ciphertext, signature, timestamp, nonce) + return self.protocol_processor.serialize(msg4_send) +} + +func (self * WXBizMsgCrypt) DecryptMsg(msg_signature, timestamp, nonce string, post_data []byte) ([]byte, * CryptError){ + msg4_recv, crypt_err := self.protocol_processor.parse(post_data) + if nil != crypt_err { + return nil, crypt_err + } + + signature := self.calSignature(timestamp, nonce, msg4_recv.Encrypt) + + if strings.Compare(signature, msg_signature) != 0{ + return nil, NewCryptError(ValidateSignatureError, "signature not equal") + } + + + plaintext, crypt_err := self.cbcDecrypter(msg4_recv.Encrypt) + if nil != crypt_err { + return nil, crypt_err + } + + _, _, msg, receiver_id, crypt_err := self.ParsePlainText(plaintext) + if nil != crypt_err { + return nil, crypt_err + } + + if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 { + return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil") + } + + return msg, nil +} + diff --git a/gin_server_admin/wechatjiexi/wxbizmsgcrypt/wxbizmsgcrypt.go b/gin_server_admin/wechatjiexi/wxbizmsgcrypt/wxbizmsgcrypt.go new file mode 100644 index 0000000..9f30dca --- /dev/null +++ b/gin_server_admin/wechatjiexi/wxbizmsgcrypt/wxbizmsgcrypt.go @@ -0,0 +1,315 @@ +package wxbizmsgcrypt + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/sha1" + "encoding/base64" + "encoding/binary" + "encoding/xml" + "fmt" + "math/rand" + "sort" + "strings" +) + +const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +const ( + ValidateSignatureError int = -40001 + ParseXmlError int = -40002 + ComputeSignatureError int = -40003 + IllegalAesKey int = -40004 + ValidateCorpidError int = -40005 + EncryptAESError int = -40006 + DecryptAESError int = -40007 + IllegalBuffer int = -40008 + EncodeBase64Error int = -40009 + DecodeBase64Error int = -40010 + GenXmlError int = -40010 + ParseJsonError int = -40012 + GenJsonError int = -40013 + IllegalProtocolType int = -40014 +) + +type ProtocolType int + +const ( + XmlType ProtocolType = 1 +) + +type CryptError struct { + ErrCode int + ErrMsg string +} + +func NewCryptError(err_code int, err_msg string) *CryptError { + return &CryptError{ErrCode: err_code, ErrMsg: err_msg} +} + +type WXBizMsg4Recv struct { + Tousername string `xml:"ToUserName"` + Encrypt string `xml:"Encrypt"` + Agentid string `xml:"AgentID"` +} + +type CDATA struct { + Value string `xml:",cdata"` +} + +type WXBizMsg4Send struct { + XMLName xml.Name `xml:"xml"` + Encrypt CDATA `xml:"Encrypt"` + Signature CDATA `xml:"MsgSignature"` + Timestamp string `xml:"TimeStamp"` + Nonce CDATA `xml:"Nonce"` +} + +func NewWXBizMsg4Send(encrypt, signature, timestamp, nonce string) *WXBizMsg4Send { + return &WXBizMsg4Send{Encrypt: CDATA{Value: encrypt}, Signature: CDATA{Value: signature}, Timestamp: timestamp, Nonce: CDATA{Value: nonce}} +} + +type ProtocolProcessor interface { + parse(src_data []byte) (*WXBizMsg4Recv, *CryptError) + serialize(msg_send *WXBizMsg4Send) ([]byte, *CryptError) +} + +type WXBizMsgCrypt struct { + token string + encoding_aeskey string + receiver_id string + protocol_processor ProtocolProcessor +} + +type XmlProcessor struct { +} + +func (self *XmlProcessor) parse(src_data []byte) (*WXBizMsg4Recv, *CryptError) { + var msg4_recv WXBizMsg4Recv + err := xml.Unmarshal(src_data, &msg4_recv) + if nil != err { + return nil, NewCryptError(ParseXmlError, "xml to msg fail") + } + return &msg4_recv, nil +} + +func (self *XmlProcessor) serialize(msg4_send *WXBizMsg4Send) ([]byte, *CryptError) { + xml_msg, err := xml.Marshal(msg4_send) + if nil != err { + return nil, NewCryptError(GenXmlError, err.Error()) + } + return xml_msg, nil +} + +func NewWXBizMsgCrypt(token, encoding_aeskey, receiver_id string, protocol_type ProtocolType) *WXBizMsgCrypt { + var protocol_processor ProtocolProcessor + if protocol_type != XmlType { + panic("unsupport protocal") + } else { + protocol_processor = new(XmlProcessor) + } + + return &WXBizMsgCrypt{token: token, encoding_aeskey: (encoding_aeskey + "="), receiver_id: receiver_id, protocol_processor: protocol_processor} +} + +func (self *WXBizMsgCrypt) randString(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letterBytes[rand.Int63()%int64(len(letterBytes))] + } + return string(b) +} + +func (self *WXBizMsgCrypt) pKCS7Padding(plaintext string, block_size int) []byte { + padding := block_size - (len(plaintext) % block_size) + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + var buffer bytes.Buffer + buffer.WriteString(plaintext) + buffer.Write(padtext) + return buffer.Bytes() +} + +func (self *WXBizMsgCrypt) pKCS7Unpadding(plaintext []byte, block_size int) ([]byte, *CryptError) { + plaintext_len := len(plaintext) + if nil == plaintext || plaintext_len == 0 { + return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding error nil or zero") + } + if plaintext_len%block_size != 0 { + return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding text not a multiple of the block size") + } + padding_len := int(plaintext[plaintext_len-1]) + return plaintext[:plaintext_len-padding_len], nil +} + +func (self *WXBizMsgCrypt) cbcEncrypter(plaintext string) ([]byte, *CryptError) { + aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey) + if nil != err { + return nil, NewCryptError(DecodeBase64Error, err.Error()) + } + const block_size = 32 + pad_msg := self.pKCS7Padding(plaintext, block_size) + + block, err := aes.NewCipher(aeskey) + if err != nil { + return nil, NewCryptError(EncryptAESError, err.Error()) + } + + ciphertext := make([]byte, len(pad_msg)) + iv := aeskey[:aes.BlockSize] + + mode := cipher.NewCBCEncrypter(block, iv) + + mode.CryptBlocks(ciphertext, pad_msg) + base64_msg := make([]byte, base64.StdEncoding.EncodedLen(len(ciphertext))) + base64.StdEncoding.Encode(base64_msg, ciphertext) + + return base64_msg, nil +} + +func (self *WXBizMsgCrypt) cbcDecrypter(base64_encrypt_msg string) ([]byte, *CryptError) { + aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey) + if nil != err { + return nil, NewCryptError(DecodeBase64Error, err.Error()) + } + + encrypt_msg, err := base64.StdEncoding.DecodeString(base64_encrypt_msg) + if nil != err { + return nil, NewCryptError(DecodeBase64Error, err.Error()) + } + + block, err := aes.NewCipher(aeskey) + if err != nil { + return nil, NewCryptError(DecryptAESError, err.Error()) + } + + if len(encrypt_msg) < aes.BlockSize { + return nil, NewCryptError(DecryptAESError, "encrypt_msg size is not valid") + } + + iv := aeskey[:aes.BlockSize] + + if len(encrypt_msg)%aes.BlockSize != 0 { + return nil, NewCryptError(DecryptAESError, "encrypt_msg not a multiple of the block size") + } + + mode := cipher.NewCBCDecrypter(block, iv) + + mode.CryptBlocks(encrypt_msg, encrypt_msg) + + return encrypt_msg, nil +} + +func (self *WXBizMsgCrypt) calSignature(timestamp, nonce, data string) string { + sort_arr := []string{self.token, timestamp, nonce, data} + sort.Strings(sort_arr) + var buffer bytes.Buffer + for _, value := range sort_arr { + buffer.WriteString(value) + } + + sha := sha1.New() + sha.Write(buffer.Bytes()) + signature := fmt.Sprintf("%x", sha.Sum(nil)) + return string(signature) +} + +func (self *WXBizMsgCrypt) ParsePlainText(plaintext []byte) ([]byte, uint32, []byte, []byte, *CryptError) { + const block_size = 32 + plaintext, err := self.pKCS7Unpadding(plaintext, block_size) + if nil != err { + return nil, 0, nil, nil, err + } + + text_len := uint32(len(plaintext)) + if text_len < 20 { + return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 1") + } + random := plaintext[:16] + msg_len := binary.BigEndian.Uint32(plaintext[16:20]) + if text_len < (20 + msg_len) { + return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 2") + } + + msg := plaintext[20 : 20+msg_len] + receiver_id := plaintext[20+msg_len:] + + return random, msg_len, msg, receiver_id, nil +} + +func (self *WXBizMsgCrypt) VerifyURL(msg_signature, timestamp, nonce, echostr string) ([]byte, *CryptError) { + signature := self.calSignature(timestamp, nonce, echostr) + + if strings.Compare(signature, msg_signature) != 0 { + return nil, NewCryptError(ValidateSignatureError, "signature not equal") + } + + plaintext, err := self.cbcDecrypter(echostr) + if nil != err { + return nil, err + } + + _, _, msg, receiver_id, err := self.ParsePlainText(plaintext) + if nil != err { + return nil, err + } + + if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 { + fmt.Println(string(receiver_id), self.receiver_id, len(receiver_id), len(self.receiver_id)) + return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil") + } + + return msg, nil +} + +func (self *WXBizMsgCrypt) EncryptMsg(reply_msg, timestamp, nonce string) ([]byte, *CryptError) { + rand_str := self.randString(16) + var buffer bytes.Buffer + buffer.WriteString(rand_str) + + msg_len_buf := make([]byte, 4) + binary.BigEndian.PutUint32(msg_len_buf, uint32(len(reply_msg))) + buffer.Write(msg_len_buf) + buffer.WriteString(reply_msg) + buffer.WriteString(self.receiver_id) + + tmp_ciphertext, err := self.cbcEncrypter(buffer.String()) + if nil != err { + return nil, err + } + ciphertext := string(tmp_ciphertext) + + signature := self.calSignature(timestamp, nonce, ciphertext) + + msg4_send := NewWXBizMsg4Send(ciphertext, signature, timestamp, nonce) + return self.protocol_processor.serialize(msg4_send) +} + +func (self *WXBizMsgCrypt) DecryptMsg(msg_signature, timestamp, nonce string, post_data []byte) ([]byte, *CryptError) { + msg4_recv, crypt_err := self.protocol_processor.parse(post_data) + if nil != crypt_err { + return nil, crypt_err + } + + signature := self.calSignature(timestamp, nonce, msg4_recv.Encrypt) + + if strings.Compare(signature, msg_signature) != 0 { + return nil, NewCryptError(ValidateSignatureError, "signature not equal") + } + + plaintext, crypt_err := self.cbcDecrypter(msg4_recv.Encrypt) + if nil != crypt_err { + return nil, crypt_err + } + + _, _, msg, receiver_id, crypt_err := self.ParsePlainText(plaintext) + if nil != crypt_err { + return nil, crypt_err + } + + if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 { + return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil") + } + + return msg, nil +}