package svc import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/base64" "encoding/json" "fmt" "image/png" "io" "net/url" "time" "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" "github.com/boombuler/barcode" "github.com/boombuler/barcode/qr" ) // Wechat defined type Wechat struct { RdCli Cache 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 || token == "" { 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) { ube, err := json.Marshal(params) hashCode := utils.HashCode(string(ube)) if err != nil { return "", err } err = wc.RdCli.SetWithExpire(fmt.Sprintf(prefix, hashCode), string(ube), time.Duration(1)*time.Hour) return fmt.Sprintf("%v", hashCode), err } // GenUserQrId defined TODO func (wc *Wechat) GenUserQrId(prefix string, userId int64, params interface{}) (string, error) { ube, err := json.Marshal(params) hashCode := utils.HashCode(string(ube)) if err != nil { return "", err } qrId := fmt.Sprintf("u%v-%v", userId, hashCode) err = wc.RdCli.SetWithExpire(fmt.Sprintf(prefix, qrId), string(ube), time.Duration(1)*time.Hour) return qrId, err } // GetQrParams defined TODO func (wc *Wechat) GetQrParams(prefix string, id string, params interface{}) error { ube := "" err := wc.RdCli.GetCache(fmt.Sprintf(prefix, id), &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 } func (wc *Wechat) GenQrCode(scene, page string) (*model.I2billSysAttachment, error) { var r io.Reader var err error if wc.c.Debug { r, err = wc.GenTestQrCode(scene, page) if err != nil { return nil, err } } else { r1, err := wc.GenGaQrCode(scene, page) if err != nil { return nil, err } defer func() { _ = r1.Close() }() r = r1 } oss, err := GetAliYunOssInstance() if err != nil { return nil, err } return oss.UploadRead(r, ".png") } func (wc *Wechat) GenGaQrCode(scene, page string) (r io.ReadCloser, err error) { token, err := wc.GetAccessToken() if err != nil { return nil, err } req := utils.Post("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + token) _, err = req.JSONBody(map[string]interface{}{"scene": scene, "page": page, "is_hyaline": true}) if err != nil { return nil, err } resp, err := req.Response() if err != nil { return nil, err } r = resp.Body return } func (wc *Wechat) GenTestQrCode(scene, page string) (r io.Reader, err error) { ret := "https://open.weixin.qq.com/sns/getexpappinfo" + "?appid=" + wc.c.Weixin.Appid + "&path=" + url.QueryEscape(url.QueryEscape(page+".html?scene="+scene+"&is_hyaline=true")) + "#wechat-redirect" code, err := qr.Encode(ret, qr.L, qr.Unicode) if err != nil { return nil, err } code, err = barcode.Scale(code, 256, 256) if err != nil { return nil, err } buff := &bytes.Buffer{} err = png.Encode(buff, code) if err != nil { return nil, err } r = buff return }