forked from royalrick/weapp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
weapp.go
191 lines (157 loc) · 4.3 KB
/
weapp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package weapp
import (
"encoding/json"
"errors"
"net/http"
"net/url"
"github.com/medivhzhan/weapp/util"
)
const (
// BaseURL 微信请求基础URL
BaseURL = "https://api.weixin.qq.com"
codeAPI = "/sns/jscode2session"
)
const (
// WeChatServerError 微信服务器错误时返回返回消息
WeChatServerError = "微信服务器发生错误"
)
// Response 请求微信返回基础数据
type Response struct {
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
}
// PhoneNumber 解密后的用户手机号码信息
type PhoneNumber struct {
PhoneNumber string `json:"phoneNumber"`
PurePhoneNumber string `json:"purePhoneNumber"`
CountryCode string `json:"countryCode"`
Watermark watermark `json:"watermark"`
}
// Userinfo 解密后的用户信息
type Userinfo struct {
OpenID string `json:"openId"`
Nickname string `json:"nickName"`
Gender int `json:"gender"`
Province string `json:"province"`
Language string `json:"language"`
Country string `json:"country"`
City string `json:"city"`
Avatar string `json:"avatarUrl"`
UnionID string `json:"unionId"`
Watermark watermark `json:"watermark"`
}
// LoginResponse 返回给用户的数据
type LoginResponse struct {
OpenID string `json:"openid"`
SessionKey string `json:"session_key"`
// 用户在开放平台的唯一标识符
// 只在满足一定条件的情况下返回
UnionID string `json:"unionid"`
}
type loginResponse struct {
Response
LoginResponse
}
// Login 用户登录
// @appID 小程序 appID
// @secret 小程序的 app secret
// @code 小程序登录时获取的 code
func Login(appID, secret, code string) (lres LoginResponse, err error) {
if code == "" {
err = errors.New("code can not be null")
return
}
api, err := code2url(appID, secret, code)
if err != nil {
return
}
res, err := http.Get(api)
if err != nil {
return
}
defer res.Body.Close()
if res.StatusCode != 200 {
err = errors.New(WeChatServerError)
return
}
var data loginResponse
err = json.NewDecoder(res.Body).Decode(&data)
if err != nil {
return
}
if data.Errcode != 0 {
err = errors.New(data.Errmsg)
return
}
lres = data.LoginResponse
return
}
type watermark struct {
AppID string `json:"appid"`
Timestamp int64 `json:"timestamp"`
}
// DecryptPhoneNumber 解密手机号码
//
// @ssk 通过 Login 向微信服务端请求得到的 session_key
// @data 小程序通过 api 得到的加密数据(encryptedData)
// @iv 小程序通过 api 得到的初始向量(iv)
func DecryptPhoneNumber(ssk, data, iv string) (phone PhoneNumber, err error) {
bts, err := util.CBCDecrypt(ssk, data, iv)
if err != nil {
return
}
err = json.Unmarshal(bts, &phone)
return
}
type group struct {
GID string `json:"openGId"`
}
// DecryptShareInfo 解密转发信息的加密数据
//
// @ssk 通过 Login 向微信服务端请求得到的 session_key
// @data 小程序通过 api 得到的加密数据(encryptedData)
// @iv 小程序通过 api 得到的初始向量(iv)
//
// @gid 小程序唯一群号
func DecryptShareInfo(ssk, data, iv string) (string, error) {
bts, err := util.CBCDecrypt(ssk, data, iv)
if err != nil {
return "", err
}
var g group
err = json.Unmarshal(bts, &g)
return g.GID, err
}
// DecryptUserInfo 解密用户信息
//
// @rawData 不包括敏感信息的原始数据字符串,用于计算签名。
// @encryptedData 包括敏感数据在内的完整用户信息的加密数据
// @signature 使用 sha1( rawData + session_key ) 得到字符串,用于校验用户信息
// @iv 加密算法的初始向量
// @ssk 微信 session_key
func DecryptUserInfo(rawData, encryptedData, signature, iv, ssk string) (ui Userinfo, err error) {
if ok := util.Validate(rawData, ssk, signature); !ok {
err = errors.New("数据校验失败")
return
}
bts, err := util.CBCDecrypt(ssk, encryptedData, iv)
if err != nil {
return
}
err = json.Unmarshal(bts, &ui)
return
}
// 拼接 获取 session_key 的 URL
func code2url(appID, secret, code string) (string, error) {
url, err := url.Parse(BaseURL + codeAPI)
if err != nil {
return "", err
}
query := url.Query()
query.Set("appid", appID)
query.Set("secret", secret)
query.Set("js_code", code)
query.Set("grant_type", "authorization_code")
url.RawQuery = query.Encode()
return url.String(), nil
}