package svc import ( "crypto/aes" "crypto/cipher" "encoding/base64" "encoding/json" "fmt" "net/http" "path" "time" "git.i2edu.net/i2/go-zero/core/stores/sqlx" "git.i2edu.net/i2/go-zero/rest/token" "git.i2edu.net/i2/go-zero/zrpc" "git.i2edu.net/i2/i2-bill-api/internal/config" "git.i2edu.net/i2/i2-bill-api/internal/utils" "git.i2edu.net/i2/i2-bill-api/model" "git.i2edu.net/i2/i2-bill-erp/transformclient" "github.com/dgrijalva/jwt-go" ) const cacheWechatTokenPrefix = "cache:wechat:token:" // RdCli defined type RdCli interface { SetCache(key string, v interface{}) error GetCache(key string, v interface{}) error SetWithExpire(key string, v interface{}, expire time.Duration) error } // Wechat defined type Wechat struct { RdCli RdCli c config.Config } // WechatPhonedecrypt defined TODO type WechatPhonedecrypt struct { PhoneNumber string `json:"phoneNumber"` PurePhoneNumber string `json:"purePhoneNumber"` CountryCode string `json:"countryCode"` Watermark struct { Appid string `json:"appid"` Timestamp int32 `json:"timestamp"` } `json:"watermark"` } // GetAccessToken defined TODO func (wc *Wechat) GetAccessToken() (string, error) { token := "" err := wc.RdCli.GetCache(cacheWechatTokenPrefix, &token) if err == model.ErrRdsNotFound { req := utils.Get("https://api.weixin.qq.com/cgi-bin/token") req.Param("grant_type", "client_credential") req.Param("secret", wc.c.Weixin.Secret) req.Param("appid", wc.c.Weixin.Appid) var res = struct { AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` }{} err = req.ToJSON(&res) if err != nil { return "", err } token = res.AccessToken err := wc.RdCli.SetWithExpire(cacheWechatTokenPrefix, res.AccessToken, time.Duration((res.ExpiresIn-60*2))*time.Second) if err != nil { return "", err } } return token, nil } // GenQrId defined TODO func (wc *Wechat) GenQrId(prefix string, params interface{}) (string, error) { uuid := utils.GetUUID() ube, err := json.Marshal(params) if err != nil { return "", err } err = wc.RdCli.SetWithExpire(fmt.Sprintf(prefix, uuid), string(ube), time.Duration(1)*time.Hour) return uuid, err } // GetQrParams defined TODO func (wc *Wechat) GetQrParams(prefix string, uuid string, params interface{}) error { ube := "" err := wc.RdCli.GetCache(fmt.Sprintf(prefix, uuid), &ube) if err != nil { return err } err = json.Unmarshal([]byte(ube), params) if err != nil { return err } return err } // GetQrParams defined TODO func (wc *Wechat) DecryptMobile(sessionKey, encryptedData, iv string) (string, error) { key, err := base64.StdEncoding.DecodeString(sessionKey) if err != nil { return "", err } bIv, err := base64.StdEncoding.DecodeString(iv) if err != nil { return "", err } bEncryptedData, err := base64.StdEncoding.DecodeString(encryptedData) if err != nil { return "", err } block, err := aes.NewCipher(key) if err != nil { return "", err } var decrypt = bEncryptedData blockMode := cipher.NewCBCDecrypter(block, bIv) blockMode.CryptBlocks(decrypt, bEncryptedData) length := len(decrypt) unpadding := int(decrypt[length-1]) decData := decrypt[:(length - unpadding)] decryptData := WechatPhonedecrypt{} err = json.Unmarshal(decData, &decryptData) if err != nil { return "", err } return decryptData.PhoneNumber, err } // GenQrCode defined TODO func (wc *Wechat) GenQrCode(scene, page string) (string, error) { token, err := wc.GetAccessToken() if err != nil { return "", err } req := utils.Post("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + token) req.JSONBody(map[string]interface{}{"scene": scene}) ph := path.Join("asserts", "qrcode", scene+".png") err = req.ToFile(ph) if err != nil { return "", err } return ph, err } type ServiceContext struct { Config config.Config SqlConn sqlx.SqlConn UserModel model.UserModel RdCli RdCli Wechat *Wechat Transformer transformclient.Transform } // GetUserId defined TODO func (sc *ServiceContext) GetUserId(r *http.Request) (int64, error) { parser := token.NewTokenParser(token.WithResetDuration(time.Minute)) tok, err := parser.ParseToken(r, sc.Config.JwtAuth.AccessSecret, "") if err != nil { return 0, err } return tok.Claims.(jwt.MapClaims)["userId"].(int64), err } // GetSessionKey defined TODO func (sc *ServiceContext) GetSessionKey(r *http.Request) (string, error) { parser := token.NewTokenParser(token.WithResetDuration(time.Minute)) tok, err := parser.ParseToken(r, sc.Config.JwtAuth.AccessSecret, "") if err != nil { return "", err } return tok.Claims.(jwt.MapClaims)["sessionKey"].(string), err } func NewServiceContext(c config.Config) *ServiceContext { svc := &ServiceContext{ Config: c, SqlConn: sqlx.NewMysql(c.DataSource), Transformer: transformclient.NewTransform(zrpc.MustNewClient(c.Transform)), } svc.UserModel = model.NewUserModel(svc.SqlConn, c.Cache) svc.RdCli = svc.UserModel.CacheStorage() svc.Wechat = &Wechat{ RdCli: svc.RdCli, c: c, } return svc }