119 lines
3.6 KiB
Go
119 lines
3.6 KiB
Go
package playstore
|
||
|
||
import (
|
||
"context"
|
||
"crypto"
|
||
"crypto/rsa"
|
||
"crypto/sha1"
|
||
"crypto/x509"
|
||
"encoding/base64"
|
||
"fmt"
|
||
"net/http"
|
||
"time"
|
||
|
||
"golang.org/x/oauth2"
|
||
"golang.org/x/oauth2/google"
|
||
"google.golang.org/api/androidpublisher/v3"
|
||
"google.golang.org/api/option"
|
||
)
|
||
|
||
// New 创建并返回一个包含访问androidpublisher API所需凭证的http客户端。
|
||
//
|
||
// @Description: 通过提供的JSON密钥创建一个配置好的Client实例,可用于与Google Play Store API交互。
|
||
// @param jsonKey 用于构建JWT配置的JSON密钥字节切片。
|
||
// @return *Client 返回初始化好的Client实例。
|
||
// @return error 如果在创建过程中遇到任何错误,则返回非nil的error。
|
||
func New(jsonKey []byte) (*Client, error) {
|
||
// 设置http客户端超时时间为10秒
|
||
c := &http.Client{Timeout: 10 * time.Second}
|
||
// 为context设置HTTP客户端,以便在OAuth2流程中使用
|
||
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, c)
|
||
|
||
// 使用JSON密钥和所需范围配置JWT
|
||
conf, err := google.JWTConfigFromJSON(jsonKey, androidpublisher.AndroidpublisherScope)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 验证JWT配置是否正确,并获取访问令牌
|
||
val := conf.Client(ctx).Transport.(*oauth2.Transport)
|
||
_, err = val.Source.Token()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 使用配置的HTTP客户端初始化androidpublisher服务
|
||
service, err := androidpublisher.NewService(ctx, option.WithHTTPClient(conf.Client(ctx)))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 返回初始化好的Client实例
|
||
return &Client{service}, err
|
||
}
|
||
|
||
// NewWithClient returns http client which includes the custom http client.
|
||
// 使用自定义的http客户端创建并返回一个包含访问androidpublisher API所需凭证的http客户端。
|
||
func NewWithClient(jsonKey []byte, cli *http.Client) (*Client, error) {
|
||
if cli == nil {
|
||
return nil, fmt.Errorf("client is nil")
|
||
}
|
||
|
||
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, cli)
|
||
|
||
conf, err := google.JWTConfigFromJSON(jsonKey, androidpublisher.AndroidpublisherScope)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
service, err := androidpublisher.NewService(ctx, option.WithHTTPClient(conf.Client(ctx)))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &Client{service}, err
|
||
}
|
||
|
||
// VerifySignature 验证应用内购买的签名。
|
||
// 您需要为您的 Android 应用的内购准备公钥,可在 https://play.google.com/apps/publish/ 上完成。
|
||
// 参数:
|
||
//
|
||
// base64EncodedPublicKey string - 经过 Base64 编码的公钥字符串。
|
||
// receipt []byte - 购买收据的字节数据。
|
||
// signature string - 购买收据的签名字符串。
|
||
//
|
||
// 返回值:
|
||
//
|
||
// isValid bool - 标识签名是否验证成功。
|
||
// err error - 验证过程中遇到的错误。
|
||
func VerifySignature(base64EncodedPublicKey string, receipt []byte, signature string) (isValid bool, err error) {
|
||
// 准备公钥
|
||
decodedPublicKey, err := base64.StdEncoding.DecodeString(base64EncodedPublicKey)
|
||
if err != nil {
|
||
return false, fmt.Errorf("failed to decode public key")
|
||
}
|
||
publicKeyInterface, err := x509.ParsePKIXPublicKey(decodedPublicKey)
|
||
if err != nil {
|
||
return false, fmt.Errorf("failed to parse public key")
|
||
}
|
||
publicKey, _ := publicKeyInterface.(*rsa.PublicKey)
|
||
|
||
// 从收据生成哈希值
|
||
hasher := sha1.New()
|
||
hasher.Write(receipt)
|
||
hashedReceipt := hasher.Sum(nil)
|
||
|
||
// 解码签名
|
||
decodedSignature, err := base64.StdEncoding.DecodeString(signature)
|
||
if err != nil {
|
||
return false, fmt.Errorf("failed to decode signature")
|
||
}
|
||
|
||
// 验证签名
|
||
if err := rsa.VerifyPKCS1v15(publicKey, crypto.SHA1, hashedReceipt, decodedSignature); err != nil {
|
||
return false, nil
|
||
}
|
||
|
||
return true, nil
|
||
}
|