├── wechat ├── model │ ├── watermark.go │ ├── share.go │ ├── run.go │ └── profile.go └── decrypt │ └── decrypt.go ├── LICENSE └── README.md /wechat/model/watermark.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //Watermark encrypted watermark 4 | type Watermark struct { 5 | Timestamp int64 `json:"timestamp"` 6 | AppID string `json:"appid"` 7 | } 8 | -------------------------------------------------------------------------------- /wechat/model/share.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //Share represents weixin share ticket 4 | type Share struct { 5 | OpenGId string `json:"openGId"` 6 | Watermark Watermark `json:"watermark"` 7 | } 8 | -------------------------------------------------------------------------------- /wechat/model/run.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //Run represents weixin run data 4 | type Run struct { 5 | Data []RunRecord `json:"stepInfoList"` 6 | } 7 | 8 | //RunRecord represents weixin run data 9 | type RunRecord struct { 10 | Timestamp uint `json:"timestamp"` 11 | Steps uint `json:"step"` 12 | } 13 | -------------------------------------------------------------------------------- /wechat/model/profile.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | //Profile represents weixin user profile 4 | type Profile struct { 5 | OpenID string `json:"openId"` 6 | UnionID string `json:"unionId"` 7 | NickName string `json:"nickName"` 8 | Gender int `json:"gender"` 9 | City string `json:"city"` 10 | Province string `json:"province"` 11 | Country string `json:"country"` 12 | AvatarURL string `json:"avatarUrl"` 13 | Language string `json:"language"` 14 | Watermark Watermark `json:"watermark"` 15 | } 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 chekun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 微信小程序SDK for Go 2 | =============================== 3 | 4 | 第一个可用版本,随心使用,注意安全 😄 5 | 6 | ## 目前功能 7 | 8 | - 数据解密 9 | 10 | - 解密 wx.getUserInfo 11 | - 解密 wx.getShareInfo 12 | - 解密 wx.getWeRunData 13 | 14 | - 接口调用 15 | 16 | - todo 17 | 18 | ## 使用方法 19 | 20 | - 数据解密 21 | 22 | ```golang 23 | 24 | import ( 25 | "fmt" 26 | "github.com/chekun/go-wechat-app/wechat/decrypt" 27 | ) 28 | 29 | func main() { 30 | decryptor, err := New("your-app-id", "your-session-key") 31 | if err != nil { 32 | fmt.Println(err)//sessionKey不正确 33 | } 34 | 35 | if profile := decryptor.Profile( "your-encrypted-data", "your-iv"); decryptor.Err != nil { 36 | fmr.Println("Profile 解密失败 - ", decryptor.Err) 37 | } else { 38 | fmt.Println(profile) 39 | } 40 | 41 | 42 | if share := decryptor.Share( "your-encrypted-data", "your-iv"); decryptor.Err != nil { 43 | fmr.Println("Share Ticket 解密失败 - ", decryptor.Err) 44 | } else { 45 | fmt.Println(share) 46 | } 47 | 48 | if run := decryptor.Run( "your-encrypted-data", "your-iv"); decryptor.Err != nil { 49 | fmr.Println("Run Data 解密失败 - ", decryptor.Err) 50 | } else { 51 | fmt.Println(run) 52 | } 53 | } 54 | 55 | ``` -------------------------------------------------------------------------------- /wechat/decrypt/decrypt.go: -------------------------------------------------------------------------------- 1 | package decrypt 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "encoding/base64" 7 | 8 | "encoding/json" 9 | 10 | "github.com/chekun/go-wechat-app/wechat/model" 11 | ) 12 | 13 | //Decryptor controls all decrypt features 14 | type Decryptor struct { 15 | appID string 16 | sessionKey []byte 17 | Err error 18 | } 19 | 20 | //New creates a decryptor 21 | func New(appID, sessionKey string) (*Decryptor, error) { 22 | 23 | aesKey, err := base64.StdEncoding.DecodeString(sessionKey) 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | return &Decryptor{ 29 | appID: appID, 30 | sessionKey: []byte(aesKey), 31 | }, nil 32 | } 33 | 34 | func (decryptor *Decryptor) base64Decode(encodedStr string) []byte { 35 | if decryptor.Err != nil { 36 | return nil 37 | } 38 | 39 | result, err := base64.StdEncoding.DecodeString(encodedStr) 40 | 41 | if err != nil { 42 | decryptor.Err = err 43 | return nil 44 | } 45 | 46 | return result 47 | } 48 | 49 | func (decryptor *Decryptor) decrypt(encryptedData, iv string) []byte { 50 | decryptor.Err = nil 51 | cipherBytes := decryptor.base64Decode(encryptedData) 52 | ivBytes := decryptor.base64Decode(iv) 53 | 54 | if decryptor.Err != nil { 55 | return nil 56 | } 57 | 58 | block, err := aes.NewCipher(decryptor.sessionKey) 59 | if err != nil { 60 | decryptor.Err = err 61 | return nil 62 | } 63 | mode := cipher.NewCBCDecrypter(block, ivBytes) 64 | mode.CryptBlocks(cipherBytes, cipherBytes) 65 | 66 | return pkcs7Unpad(cipherBytes) 67 | } 68 | 69 | //Profile decrypt the encryped profile 70 | func (decryptor *Decryptor) Profile(encryptedData, iv string) *model.Profile { 71 | result := decryptor.decrypt(encryptedData, iv) 72 | if decryptor.Err != nil { 73 | return nil 74 | } 75 | var profile model.Profile 76 | decryptor.Err = json.Unmarshal(result, &profile) 77 | return &profile 78 | } 79 | 80 | //Share decrypt the encryped share ticket 81 | func (decryptor *Decryptor) Share(encryptedData, iv string) *model.Share { 82 | result := decryptor.decrypt(encryptedData, iv) 83 | if decryptor.Err != nil { 84 | return nil 85 | } 86 | var share model.Share 87 | decryptor.Err = json.Unmarshal(result, &share) 88 | return &share 89 | } 90 | 91 | //Run decrypt the encryped rundata 92 | func (decryptor *Decryptor) Run(encryptedData, iv string) *model.Run { 93 | result := decryptor.decrypt(encryptedData, iv) 94 | if decryptor.Err != nil { 95 | return nil 96 | } 97 | var run model.Run 98 | decryptor.Err = json.Unmarshal(result, &run) 99 | return &run 100 | } 101 | 102 | func pkcs7Unpad(padBytes []byte) []byte { 103 | length := len(padBytes) 104 | padLen := int(padBytes[length-1]) 105 | if padLen < 1 || padLen > 32 { 106 | padLen = 0 107 | } 108 | return padBytes[:(length - padLen)] 109 | } 110 | --------------------------------------------------------------------------------