-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathreceipt.go
104 lines (89 loc) · 2.77 KB
/
receipt.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
package apple
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
)
const (
kVerifyReceiptProduction = "https://buy.itunes.apple.com/verifyReceipt"
kVerifyReceiptSandbox = "https://sandbox.itunes.apple.com/verifyReceipt"
)
var (
ErrBadReceipt = errors.New("bad receipt")
)
// VerifyReceipt 验证苹果内购交易是否有效 https://developer.apple.com/documentation/appstorereceipts/verifyreceipt
// 首先请求苹果的服务器,获取票据(receipt)的详细信息,然后验证交易信息(transactionId)是否属于该票据,
// 如果交易信息在票据中,则返回详细的交易信息。
// 注意:本方法会先调用苹果生产环境接口进行票据查询,如果返回票据信息为测试环境中的信息时,则调用测试环境接口进行查询。
func VerifyReceipt(transactionId, receipt string, opts ...ReceiptOption) (*ReceiptSummary, *InApp, error) {
var summary, err = GetReceipt(receipt, opts...)
if err != nil {
return nil, nil, err
}
// 没有交易信息
if summary == nil {
return nil, nil, ErrBadReceipt
}
// 票据查询失败
if summary.Status != 0 {
return nil, nil, fmt.Errorf("bad receipt: %d", summary.Status)
}
// 验证 transactionId 和 receipt 是否匹配
if summary.Receipt != nil {
for _, info := range summary.Receipt.InApp {
if info.TransactionId == transactionId {
return summary, info, nil
}
}
}
return nil, nil, ErrBadReceipt
}
// GetReceipt 获取票据信息
//
// 注意:本方法会先调用苹果生产环境接口进行票据查询,如果返回票据信息为测试环境中的信息时,则调用测试环境接口进行查询。
func GetReceipt(receipt string, opts ...ReceiptOption) (*ReceiptSummary, error) {
var nOpt = &ReceiptOptions{}
nOpt.Client = http.DefaultClient
nOpt.Receipt = receipt
for _, opt := range opts {
if opt != nil {
opt(nOpt)
}
}
// 从生产环境查询
var summary, err = getReceipt(kVerifyReceiptProduction, nOpt)
if err != nil {
return nil, err
}
// 如果返回票据信息为测试环境中的信息时,则调用测试环境接口进行查询
if summary != nil && summary.Status == 21007 {
summary, err = getReceipt(kVerifyReceiptSandbox, nOpt)
if err != nil {
return nil, err
}
}
return summary, nil
}
func getReceipt(url string, opts *ReceiptOptions) (*ReceiptSummary, error) {
var data, err = json.Marshal(opts)
if err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
if err != nil {
return nil, err
}
rsp, err := opts.Client.Do(req)
if err != nil {
return nil, err
}
defer rsp.Body.Close()
var summary *ReceiptSummary
var decoder = json.NewDecoder(rsp.Body)
if err = decoder.Decode(&summary); err != nil {
return nil, err
}
return summary, nil
}