Skip to content

Commit 16712e4

Browse files
committed
1. The first version.
1 parent d55d076 commit 16712e4

11 files changed

+1076
-0
lines changed

AliyunLogin.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package toolset
2+
3+
import (
4+
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
5+
dypnsapi20170525 "github.com/alibabacloud-go/dypnsapi-20170525/v2/client"
6+
util "github.com/alibabacloud-go/tea-utils/v2/service"
7+
"github.com/alibabacloud-go/tea/tea"
8+
)
9+
10+
func createAliyunLoginClient(accessKeyId *string, accessKeySecret *string) (_result *dypnsapi20170525.Client, _err error) {
11+
config := &openapi.Config{
12+
AccessKeyId: accessKeyId,
13+
AccessKeySecret: accessKeySecret,
14+
}
15+
16+
config.Endpoint = tea.String("dypnsapi.aliyuncs.com")
17+
18+
_result, _err = dypnsapi20170525.NewClient(config)
19+
return _result, _err
20+
}
21+
22+
func AliyunGetMobile(token string, accessKeyId string, accessKeySecret string) (string, error) {
23+
client, err := createAliyunLoginClient(tea.String(accessKeyId), tea.String(accessKeySecret))
24+
25+
if err != nil {
26+
return "", err
27+
}
28+
29+
getMobileRequest := &dypnsapi20170525.GetMobileRequest{
30+
AccessToken: tea.String(token),
31+
}
32+
runtime := &util.RuntimeOptions{}
33+
34+
response, _err := client.GetMobileWithOptions(getMobileRequest, runtime)
35+
36+
if _err == nil {
37+
38+
bok := response.Body.Code
39+
40+
if *bok == "OK" {
41+
strMobile := response.Body.GetMobileResultDTO.Mobile
42+
43+
return *strMobile, nil
44+
45+
} else {
46+
return "", nil
47+
}
48+
49+
} else {
50+
return "", _err
51+
}
52+
53+
}

Apns.go

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package toolset
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
"github.com/sideshow/apns2"
8+
"github.com/sideshow/apns2/token"
9+
)
10+
11+
var (
12+
apnsClient *apns2.Client
13+
isInit bool
14+
appBundleId string
15+
)
16+
17+
func ApnsInit(certificate []byte, keyID string, teamID string, appBundle string) {
18+
appBundleId = appBundle
19+
authKey, err := token.AuthKeyFromBytes(certificate)
20+
if err != nil {
21+
fmt.Println(err)
22+
}
23+
24+
t := &token.Token{AuthKey: authKey, KeyID: keyID, TeamID: teamID}
25+
26+
apnsClient = apns2.NewTokenClient(t).Production().Development()
27+
isInit = true
28+
}
29+
30+
func ApnsPush(token string, msg string) error {
31+
if !isInit {
32+
return fmt.Errorf("apns not init, call ApnsInit() first")
33+
}
34+
payload := make(map[string]interface{})
35+
aps := make(map[string]interface{})
36+
37+
aps["alert"] = msg
38+
aps["sound"] = "defalut"
39+
aps["badge"] = 1
40+
payload["aps"] = aps
41+
42+
notification := &apns2.Notification{}
43+
notification.DeviceToken = token
44+
notification.Topic = appBundleId
45+
46+
jsonPayload, _ := json.Marshal(payload)
47+
48+
notification.Payload = jsonPayload
49+
50+
res, err := apnsClient.Push(notification)
51+
52+
if res.StatusCode != 200 {
53+
return fmt.Errorf("apns push error, status code: %d, %s", res.StatusCode, res.Reason)
54+
}
55+
return err
56+
}

AppleLogin.go

+259
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
package toolset
2+
3+
import (
4+
"crypto/ecdsa"
5+
"crypto/rsa"
6+
"crypto/x509"
7+
"encoding/json"
8+
"encoding/pem"
9+
"errors"
10+
"fmt"
11+
"io"
12+
"math/big"
13+
"net/http"
14+
"net/url"
15+
"strings"
16+
"time"
17+
18+
"github.com/dgrijalva/jwt-go"
19+
)
20+
21+
type AppleLoginToken struct {
22+
AccessToken string `json:"access_token"`
23+
ExpiresIn int `json:"expires_in"`
24+
RefreshToken string `json:"refresh_token"`
25+
IdToken string `json:"id_token"`
26+
TokenType string `json:"token_type"`
27+
}
28+
29+
// create client_secret
30+
func getAppleSecret(secret, keyId, teamId, bundleId string) string {
31+
token := &jwt.Token{
32+
Header: map[string]interface{}{
33+
"alg": "ES256",
34+
"kid": keyId,
35+
},
36+
Claims: jwt.MapClaims{
37+
"iss": teamId,
38+
"iat": time.Now().Unix(),
39+
"exp": time.Now().Add(24 * time.Hour).Unix(),
40+
"aud": "https://appleid.apple.com",
41+
"sub": bundleId,
42+
},
43+
Method: jwt.SigningMethodES256,
44+
}
45+
46+
ecdsaKey, _ := authKeyFromBytes([]byte(secret))
47+
ss, _ := token.SignedString(ecdsaKey)
48+
return ss
49+
}
50+
51+
// create private key for jwt sign
52+
func authKeyFromBytes(key []byte) (*ecdsa.PrivateKey, error) {
53+
var err error
54+
55+
// Parse PEM block
56+
var block *pem.Block
57+
if block, _ = pem.Decode(key); block == nil {
58+
return nil, errors.New("token: AuthKey must be a valid .p8 PEM file")
59+
}
60+
61+
// Parse the key
62+
var parsedKey interface{}
63+
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
64+
return nil, err
65+
}
66+
67+
var pkey *ecdsa.PrivateKey
68+
var ok bool
69+
if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok {
70+
return nil, errors.New("token: AuthKey must be of type ecdsa.PrivateKey")
71+
}
72+
73+
return pkey, nil
74+
}
75+
76+
// do http request
77+
func httpRequest(method, addr string, params map[string]string) ([]byte, int, error) {
78+
form := url.Values{}
79+
for k, v := range params {
80+
form.Set(k, v)
81+
}
82+
83+
var request *http.Request
84+
var err error
85+
if request, err = http.NewRequest(method, addr, strings.NewReader(form.Encode())); err != nil {
86+
return nil, 0, err
87+
}
88+
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
89+
90+
var response *http.Response
91+
if response, err = http.DefaultClient.Do(request); nil != err {
92+
return nil, 0, err
93+
}
94+
defer response.Body.Close()
95+
96+
data, err := io.ReadAll(response.Body)
97+
if err != nil {
98+
return nil, 0, err
99+
}
100+
return data, response.StatusCode, nil
101+
}
102+
103+
func AppleLogin(authorizationCode, certSecret, keyID, teamID, bundleId, redirectUrl string) string {
104+
data, _, err := httpRequest("POST", "https://appleid.apple.com/auth/token", map[string]string{
105+
"client_id": bundleId,
106+
"client_secret": getAppleSecret(certSecret, keyID, teamID, bundleId),
107+
"code": authorizationCode,
108+
"grant_type": "authorization_code",
109+
"redirect_uri": redirectUrl,
110+
})
111+
112+
if err != nil {
113+
return ""
114+
}
115+
116+
var tt AppleLoginToken
117+
err = json.Unmarshal(data, &tt)
118+
if err != nil {
119+
return ""
120+
}
121+
122+
t, err := verifyIDToken(tt.IdToken)
123+
124+
if err != nil {
125+
fmt.Println("Token verification failed:", err)
126+
return ""
127+
}
128+
129+
if claims, ok := t.Claims.(jwt.MapClaims); ok && t.Valid {
130+
131+
fmt.Println("Token verified. Claims:", claims)
132+
return claims["email"].(string)
133+
} else {
134+
fmt.Println("Invalid token")
135+
return ""
136+
}
137+
}
138+
139+
// 定义Apple公钥的结构体
140+
type applePublicKey struct {
141+
Kty string `json:"kty"`
142+
Kid string `json:"kid"`
143+
Use string `json:"use"`
144+
Alg string `json:"alg"`
145+
N string `json:"n"`
146+
E string `json:"e"`
147+
}
148+
149+
type applePublicKeys struct {
150+
Keys []applePublicKey `json:"keys"`
151+
}
152+
153+
// 从Apple的JWKs端点获取公钥
154+
func getApplePublicKeys() (*applePublicKeys, error) {
155+
resp, err := http.Get("https://appleid.apple.com/auth/keys")
156+
if err != nil {
157+
return nil, err
158+
}
159+
defer resp.Body.Close()
160+
161+
body, err := io.ReadAll(resp.Body)
162+
if err != nil {
163+
return nil, err
164+
}
165+
166+
var keys applePublicKeys
167+
err = json.Unmarshal(body, &keys)
168+
if err != nil {
169+
return nil, err
170+
}
171+
172+
return &keys, nil
173+
}
174+
175+
// 根据kid找到匹配的公钥
176+
func findMatchingKey(kid string, keys *applePublicKeys) (*rsa.PublicKey, error) {
177+
for _, key := range keys.Keys {
178+
if key.Kid == kid {
179+
n, err := base64URLDecodeToBigInt(key.N)
180+
if err != nil {
181+
return nil, err
182+
}
183+
e, err := base64URLDecodeToBigInt(key.E)
184+
if err != nil {
185+
return nil, err
186+
}
187+
return &rsa.PublicKey{N: n, E: int(e.Int64())}, nil
188+
}
189+
}
190+
return nil, fmt.Errorf("matching key not found")
191+
}
192+
193+
// Base64 URL 解码到大整数
194+
func base64URLDecodeToBigInt(base64url string) (*big.Int, error) {
195+
// Base64 URL 解码
196+
decoded, err := jwt.DecodeSegment(base64url)
197+
if err != nil {
198+
return nil, err
199+
}
200+
201+
// 转换为大整数
202+
n := big.NewInt(0)
203+
n.SetBytes(decoded)
204+
return n, nil
205+
}
206+
207+
// 验证ID Token
208+
func verifyIDToken(tokenString string) (*jwt.Token, error) {
209+
// 分割JWT,获取Header部分
210+
parts := strings.Split(tokenString, ".")
211+
if len(parts) != 3 {
212+
return nil, fmt.Errorf("expected 3 parts but got %d", len(parts))
213+
}
214+
215+
// Base64 URL 解码Header
216+
headerJSON, err := jwt.DecodeSegment(parts[0])
217+
if err != nil {
218+
return nil, err
219+
}
220+
221+
// 解析Header为map
222+
var header map[string]interface{}
223+
if err := json.Unmarshal(headerJSON, &header); err != nil {
224+
return nil, err
225+
}
226+
227+
// 从Header中获取kid
228+
kid, ok := header["kid"].(string)
229+
if !ok {
230+
return nil, fmt.Errorf("kid not found in token header")
231+
}
232+
233+
// 获取Apple的公钥
234+
keys, err := getApplePublicKeys()
235+
if err != nil {
236+
return nil, err
237+
}
238+
239+
// 根据kid找到匹配的公钥
240+
publicKey, err := findMatchingKey(kid, keys)
241+
if err != nil {
242+
return nil, err
243+
}
244+
245+
// 使用找到的公钥解析并验证JWT
246+
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
247+
// 确保token使用的是RSA签名
248+
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
249+
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
250+
}
251+
return publicKey, nil
252+
})
253+
254+
if err != nil {
255+
return nil, err
256+
}
257+
258+
return token, nil
259+
}

Image2File.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package toolset
2+
3+
import (
4+
"encoding/base64"
5+
"os"
6+
7+
"github.com/gofrs/uuid"
8+
)
9+
10+
func WriteImageFile(path string, base64_image_content string) (bool, string) {
11+
12+
fileType := "png"
13+
id, _ := uuid.NewV4()
14+
ids := id.String()
15+
16+
var fileName string = path + "/" + ids + "." + fileType
17+
byte, _ := base64.StdEncoding.DecodeString(base64_image_content)
18+
19+
err := os.WriteFile(fileName, byte, 0666)
20+
21+
return err == nil, ids + "." + fileType
22+
}

0 commit comments

Comments
 (0)