|
- package mob
-
- import (
- "applet/app/db"
- "applet/app/lib/sms"
- "applet/app/lib/zhimeng"
- "applet/app/utils"
- "applet/app/utils/logx"
- "bytes"
- "crypto/cipher"
- "crypto/des"
- "crypto/md5"
- "encoding/base64"
- "encoding/hex"
- "encoding/json"
- "errors"
- "fmt"
- "io/ioutil"
- "net/http"
- "sort"
- "time"
-
- "github.com/gin-gonic/gin"
- "github.com/tidwall/gjson"
- )
-
- const base string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
-
- // Mob is mob sdk
- var Mob *SDK
-
- // MobMap is 每个站长都要有自己的mob 对象
- var MobMap map[string]*SDK
-
- //Init 初始化
- func Init() {
- // 后续可能要传请求的上下文来获取对应的配置
- // mob 目前都是我们来管理每个站长的app 所以使用template 库
- //fmt.Println("Mob SDK init ....")
- ch := make(chan struct{}) // 只是做信号标志的话 空struct 更省点资源
- MobMap = make(map[string]*SDK)
- // 初始化
- for k, e := range db.DBs {
- m, err := db.SysCfgGetOne(e, "third_app_push_set")
- if err != nil {
- logx.Warn(err)
- fmt.Println(k + ":init mob err")
- continue
- }
- key := gjson.Get(m.Val, "mobAppKey").String()
- secret := gjson.Get(m.Val, "mobAppSecret").String()
- if key == "" || secret == "" {
- fmt.Println(k + ":mob no config")
- continue
- }
- // fmt.Println(k, key, secret)
- mob := new(SDK)
- mob.AppKey = key
- mob.AppSecret = secret
- MobMap[k] = mob
- fmt.Println(k + ":mob config success")
- }
- go func() {
- ch <- struct{}{}
- }()
-
- // 定时任务
- go func(MobMap map[string]*SDK, ch chan struct{}) {
- <-ch
- ticker := time.NewTicker(time.Duration(time.Second * 15))
- //每 15s 一次更新一次mob 配置
- for range ticker.C {
- for k, e := range db.DBs {
- if err := e.Ping(); err != nil {
- logx.Info(err)
- continue
- }
- m, err := db.SysCfgGetOne(e, "third_app_push_set")
- if err != nil {
- logx.Warn(err)
- fmt.Println(k + ":init mob err")
- continue
- }
- key := gjson.Get(m.Val, "mobAppKey").String()
- secret := gjson.Get(m.Val, "mobAppSecret").String()
- if key == "" || secret == "" {
- fmt.Println(k + ":mob no config")
- continue
- }
- // fmt.Println(k, key, secret)
- mob := new(SDK)
- mob.AppKey = key
- mob.AppSecret = secret
- MobMap[k] = mob
- // fmt.Println(k + ":mob config success")
- }
- }
- }(MobMap, ch)
- }
-
- // GetMobSDK is 获取mob 的sdk
- func GetMobSDK(mid string) (*SDK, error) {
- selectDB := db.DBs[mid]
- m, err := db.SysCfgGetOne(selectDB, "third_app_push_set")
- if err != nil {
- return nil, err
- }
- key := gjson.Get(m.Val, "mobAppKey").String()
- secret := gjson.Get(m.Val, "mobAppSecret").String()
- if key == "" || secret == "" {
- return nil, fmt.Errorf("%s mob not config", mid)
- }
-
- return &SDK{AppKey: key, AppSecret: secret}, nil
- }
-
- // SDK is mob_push 的sdk
- type SDK struct {
- AppKey string
- AppSecret string
- }
-
- //MobFreeLogin is 秒验
- func (s *SDK) MobFreeLogin(args map[string]interface{}) (string, error) {
- var url string = "http://identify.verify.mob.com/auth/auth/sdkClientFreeLogin"
- // https://www.mob.com/wiki/detailed/?wiki=miaoyan_for_fuwuduan_mianmifuwuduanjieru&id=78
- //加appkey
- args["appkey"] = s.AppKey
- //加签名
- args["sign"] = generateSign(args, s.AppSecret)
- b, err := json.Marshal(args)
- if err != nil {
- return "", logx.Warn(err)
- }
- // 发送请求
- respBody, err := httpPostBody(url, b)
- if err != nil {
- return "", logx.Warn(err)
- }
- // 反序列化
- ret := struct {
- Status int `json:"status"`
- Error string `json:"error"`
- Res interface{} `json:"res"`
- }{}
- // 要拿 ret 里面 Res 再解密
- if err := json.Unmarshal(respBody, &ret); err != nil {
- return "", logx.Warn(err)
- }
- //fmt.Println(ret)
- // ret里面的Res 反序列化为结构体
- res := struct {
- IsValid int `json:"isValid"`
- Phone string `json:"phone"`
- }{}
- // 判断是否返回正确 状态码
- if ret.Status == 200 {
- decode, _ := base64Decode([]byte(ret.Res.(string)))
- decr, _ := desDecrypt(decode, []byte(s.AppSecret)[0:8])
- if err := json.Unmarshal(decr, &res); err != nil {
- return "", logx.Warn(err)
- }
- }
- // 有效则拿出res 里的电话号码
- if res.IsValid == 1 {
- return res.Phone, nil
- }
- // Status 不等于200 则返回空
- return "", fmt.Errorf("Mob error , status code %v ", ret.Status)
- }
-
- // MobSMS is mob 的短信验证
- func (s *SDK) MobSMS(c *gin.Context, args map[string]interface{}) (bool, error) {
- // mob 的短信验证
- // https://www.mob.com/wiki/detailed/?wiki=SMSSDK_for_yanzhengmafuwuduanxiaoyanjiekou&id=23
- url := "https://webapi.sms.mob.com/sms/verify"
- //加appkey
- args["appkey"] = s.AppKey
- //fmt.Println(args)
- // 发送请求
- respBody, err := utils.CurlPost(url, args, nil)
- if err != nil {
- return false, logx.Warn(err)
- }
- //fmt.Println(string(respBody))
- code := gjson.GetBytes(respBody, "status").Int()
- if code != 200 {
- return false, nil
- }
- if code == 468 {
- return false, errors.New("验证码错误")
- }
- // TODO 成功后扣费暂时先接旧智盟
- sdk, err := sms.NewZhimengSMS(c).SelectFunction("deduction_doing").WithSMSArgs(map[string]interface{}{
- "mobile": args["phone"],
- "getmsg": "1",
- }).Result()
- if err != nil {
- return false, logx.Warn(err)
- }
- zr := sdk.ToInterface().(string)
- if zr == "1" {
- logx.Infof("旧智盟扣费成功 appkey %s", zhimeng.SMS_APP_KEY)
- }
- return true, nil
- }
-
- func pkcs5UnPadding(origData []byte) []byte {
- length := len(origData)
- // 去掉最后一个字节 unpadding 次
- unpadding := int(origData[length-1])
- return origData[:(length - unpadding)]
- }
-
- func desDecrypt(crypted, key []byte) ([]byte, error) {
- block, err := des.NewCipher(key)
- if err != nil {
- return nil, err
- }
- blockMode := cipher.NewCBCDecrypter(block, []byte("00000000"))
- origData := make([]byte, len(crypted))
- // origData := crypted
- blockMode.CryptBlocks(origData, crypted)
- origData = pkcs5UnPadding(origData)
- // origData = ZeroUnPadding(origData)
- return origData, nil
- }
-
- func base64Decode(src []byte) ([]byte, error) {
- var coder *base64.Encoding
- coder = base64.NewEncoding(base)
- return coder.DecodeString(string(src))
- }
-
- func httpPostBody(url string, msg []byte) ([]byte, error) {
- resp, err := http.Post(url, "application/json;charset=utf-8", bytes.NewBuffer(msg))
- if err != nil {
- return []byte(""), err
- }
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
- return body, err
- }
-
- func generateSign(request map[string]interface{}, secret string) string {
- ret := ""
- var keys []string
- for k := range request {
- keys = append(keys, k)
- }
- sort.Strings(keys)
- for _, k := range keys {
- ret = ret + fmt.Sprintf("%v=%v&", k, request[k])
- }
- ret = ret[:len(ret)-1] + secret
-
- md5Ctx := md5.New()
- md5Ctx.Write([]byte(ret))
- cipherStr := md5Ctx.Sum(nil)
- return hex.EncodeToString(cipherStr)
- }
|