123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- 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(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
- }
|