-
Notifications
You must be signed in to change notification settings - Fork 782
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
31 changed files
with
755 additions
and
233 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package apple | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
"crypto/x509" | ||
"encoding/pem" | ||
"errors" | ||
) | ||
|
||
// ParseECPrivateKeyFromPEM parses a PEM encoded Elliptic Curve Private Key Structure | ||
func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) { | ||
var err error | ||
// Parse PEM block | ||
var block *pem.Block | ||
if block, _ = pem.Decode(key); block == nil { | ||
return nil, errors.New("ErrKeyMustBePEMEncoded") | ||
} | ||
// Parse the key | ||
var parsedKey interface{} | ||
if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil { | ||
if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { | ||
return nil, err | ||
} | ||
} | ||
pkey, ok := parsedKey.(*ecdsa.PrivateKey) | ||
if !ok { | ||
return nil, errors.New("ErrNotECPrivateKey") | ||
} | ||
return pkey, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package apple | ||
|
||
import ( | ||
"context" | ||
"crypto/ecdsa" | ||
"net/http" | ||
|
||
"github.com/go-pay/gopay" | ||
"github.com/go-pay/gopay/pkg/util" | ||
"github.com/go-pay/gopay/pkg/xhttp" | ||
) | ||
|
||
// Client AppleClient | ||
type Client struct { | ||
iss string // Your issuer ID from the Keys page in App Store Connect (Ex: "57246542-96fe-1a63-e053-0824d011072a") | ||
bid string // Your app’s bundle ID (Ex: “com.example.testbundleid2021”) | ||
kid string // Your private key ID from App Store Connect (Ex: 2X9R4HXF34) | ||
isProd bool // 是否是正式环境 | ||
privateKey *ecdsa.PrivateKey | ||
} | ||
|
||
// NewClient 初始化Apple客户端 | ||
// iss:issuer ID | ||
// bid:bundle ID | ||
// kid:private key ID | ||
// privateKey:私钥文件读取后的字符串内容 | ||
// isProd:是否是正式环境 | ||
func NewClient(iss, bid, kid, privateKey string, isProd bool) (client *Client, err error) { | ||
if iss == util.NULL || bid == util.NULL || kid == util.NULL || privateKey == util.NULL { | ||
return nil, gopay.MissAppleInitParamErr | ||
} | ||
ecPrivateKey, err := ParseECPrivateKeyFromPEM([]byte(privateKey)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
//ecPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||
//if err != nil { | ||
// panic(err) | ||
//} | ||
client = &Client{ | ||
iss: iss, | ||
bid: bid, | ||
kid: kid, | ||
privateKey: ecPrivateKey, | ||
} | ||
return client, nil | ||
} | ||
|
||
func (c *Client) doRequestGet(ctx context.Context, path string) (res *http.Response, bs []byte, err error) { | ||
uri := hostUrl + path | ||
if !c.isProd { | ||
uri = sandBoxHostUrl + path | ||
} | ||
token, err := c.generatingToken() | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
cli := xhttp.NewClient() | ||
cli.Header.Set("Authorization", "Bearer "+token) | ||
res, bs, err = cli.Type(xhttp.TypeJSON).Get(uri).EndBytes(ctx) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
return res, bs, nil | ||
} | ||
|
||
func (c *Client) doRequestPost(ctx context.Context, path string, bm gopay.BodyMap) (res *http.Response, bs []byte, err error) { | ||
uri := hostUrl + path | ||
if !c.isProd { | ||
uri = sandBoxHostUrl + path | ||
} | ||
token, err := c.generatingToken() | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
cli := xhttp.NewClient() | ||
cli.Header.Set("Authorization", "Bearer "+token) | ||
res, bs, err = cli.Type(xhttp.TypeJSON).Post(uri).SendBodyMap(bm).EndBytes(ctx) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
return res, bs, nil | ||
} | ||
|
||
func (c *Client) doRequestPut(ctx context.Context, path string, bm gopay.BodyMap) (res *http.Response, bs []byte, err error) { | ||
uri := hostUrl + path | ||
if !c.isProd { | ||
uri = sandBoxHostUrl + path | ||
} | ||
token, err := c.generatingToken() | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
cli := xhttp.NewClient() | ||
cli.Header.Set("Authorization", "Bearer "+token) | ||
res, bs, err = cli.Type(xhttp.TypeJSON).Put(uri).SendBodyMap(bm).EndBytes(ctx) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
return res, bs, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package apple | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"testing" | ||
|
||
"github.com/go-pay/gopay/pkg/xlog" | ||
) | ||
|
||
var ( | ||
ctx = context.Background() | ||
client *Client | ||
err error | ||
|
||
iss = "57246542-96fe-1a63-e053-0824d011072a" | ||
bid = "com.example.testbundleid2021" | ||
kid = "2X9R4HXF34" | ||
) | ||
|
||
func TestMain(m *testing.M) { | ||
xlog.Level = xlog.DebugLevel | ||
// 初始化客户端 | ||
// iss:issuer ID | ||
// bid:bundle ID | ||
// kid:private key ID | ||
// privateKey:私钥文件读取后的字符串内容 | ||
// isProd:是否是正式环境 | ||
client, err = NewClient(iss, bid, kid, "privateKey", false) | ||
if err != nil { | ||
xlog.Error(err) | ||
return | ||
} | ||
|
||
os.Exit(m.Run()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package apple | ||
|
||
const ( | ||
hostUrl = "https://api.storekit.itunes.apple.com" | ||
sandBoxHostUrl = "https://api.storekit-sandbox.itunes.apple.com" | ||
|
||
// Get Transaction History | ||
getTransactionHistory = "/inApps/v1/history/%s" // transactionId | ||
|
||
// Get Transaction Info | ||
getTransactionInfo = "/inApps/v1/transactions/%s" // transactionId | ||
|
||
// Get All Subscription Statuses | ||
getAllSubscriptionStatuses = "/inApps/v1/subscriptions/%s" // transactionId | ||
|
||
// Send Consumption Information | ||
sendConsumptionInformation = "/inApps/v1/transactions/consumption/%s" // transactionId | ||
|
||
// Look Up Order ID | ||
lookUpOrderID = "/inApps/v1/lookup/%s" // orderId | ||
|
||
// Get Subscription Status | ||
getRefundHistory = "/inApps/v2/refund/lookup/%s" // transactionId | ||
|
||
// Get Notification History | ||
getNotificationHistory = "/inApps/v1/notifications/history" | ||
) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package apple | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/go-pay/gopay" | ||
) | ||
|
||
// SendConsumptionInformation Send Consumption Information | ||
// Doc: https://developer.apple.com/documentation/appstoreserverapi/send_consumption_information | ||
func (c *Client) SendConsumptionInformation(ctx context.Context, transactionId string, bm gopay.BodyMap) (err error) { | ||
path := fmt.Sprintf(sendConsumptionInformation, transactionId) | ||
res, _, err := c.doRequestPut(ctx, path, bm) | ||
if err != nil { | ||
return err | ||
} | ||
if res.StatusCode != http.StatusOK { | ||
return fmt.Errorf("http.stauts_code = %d", res.StatusCode) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package apple | ||
|
||
import "fmt" | ||
|
||
// StatusCodeErr 用于判断Apple的status_code错误 | ||
type StatusCodeErr struct { | ||
ErrorCode int `json:"errorCode,omitempty"` | ||
ErrorMessage string `json:"errorMessage,omitempty"` | ||
} | ||
|
||
// statusCodeErrCheck 检查状态码是否为非200错误 | ||
func statusCodeErrCheck(errRsp StatusCodeErr) error { | ||
if errRsp.ErrorCode != 0 { | ||
return &StatusCodeErr{ | ||
ErrorCode: errRsp.ErrorCode, | ||
ErrorMessage: errRsp.ErrorMessage, | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (e *StatusCodeErr) Error() string { | ||
return fmt.Sprintf(`{"errorCode":"%d","errorMessage":"%s"}`, e.ErrorCode, e.ErrorMessage) | ||
} | ||
|
||
func IsStatusCodeError(err error) (*StatusCodeErr, bool) { | ||
if bizErr, ok := err.(*StatusCodeErr); ok { | ||
return bizErr, true | ||
} | ||
return nil, false | ||
} |
Oops, something went wrong.