40 Commits

Author SHA1 Message Date
sanjid133
5d167ac1a5 Merge branch 'master' of https://github.com/awa/go-iap 2019-12-05 10:53:06 +06:00
Junpei Tsuji
b31646baf4 Merge pull request #101 from mlesar/unified_receipt
Adding unified receipt to the Apple S2S notification
2019-11-26 00:20:18 +09:00
Matija Lesar
1bd99243d7 Changed environment property type 2019-11-25 12:42:41 +01:00
Matija Lesar
7d624ad068 Updated order of properties 2019-11-25 11:26:42 +01:00
Matija Lesar
31a625b71e CR changes 2019-11-25 11:25:31 +01:00
Matija Lesar
4209b06a64 Added unified receipt 2019-11-25 10:00:13 +01:00
Junpei Tsuji
3d3bd2b6cf Merge pull request #99 from jun06t/error-message
Fixed test error messages
2019-10-10 11:56:32 +09:00
Junpei Tsuji
934d4ffbbd Fixed test error messages 2019-10-10 10:58:16 +09:00
Junpei Tsuji
9c0e16f820 Merge pull request #96 from jun06t/appstore-grace-period
Added grace period fields
2019-09-17 13:47:52 +09:00
Junpei Tsuji
e895c80eb0 Added grace period fields 2019-09-17 13:23:05 +09:00
Hasan
4b88aefda5 Merge pull request #4 from Tapfury/noti
updated notificaiton
2019-08-18 17:07:26 +06:00
sanjid133
62fa34fffb Merge branch 'master' of github.com:Tapfury/go-iap into noti
# Conflicts:
#	appstore/model.go
#	appstore/notification.go
2019-08-18 17:06:30 +06:00
sanjid133
8414aff344 status field not present in initial_buy 2019-08-18 16:56:32 +06:00
sanjid133
e0f6e608e7 auto renew status string 2019-08-18 16:56:32 +06:00
sanjid133
11e072e211 Add renewal field 2019-08-18 16:56:32 +06:00
sanjid133
b60c954624 Verfiy latest receipt 2019-08-18 16:56:32 +06:00
sanjid133
c92634081e Add missing is_upgrade field 2019-08-18 16:56:32 +06:00
Minhaz Ahmed Syrus
fbfe02b5f6 Add missing subscription billing retry flag 2019-08-18 16:56:32 +06:00
Minhaz Ahmed Syrus
bac6b5676b Add missing notification verification fields 2019-08-18 16:56:09 +06:00
Minhaz Ahmed Syrus
94f276769f Add missing subscription billing retry flag 2019-08-18 16:54:57 +06:00
Minhaz Ahmed Syrus
4ed348bb1b Add missing notification verification fields 2019-08-18 16:54:57 +06:00
Hasan
712b3f7da2 Merge pull request #3 from Tapfury/renew
Add renewal field
2019-08-07 15:37:04 +06:00
sanjid133
5354251ea5 Add renewal field 2019-08-07 15:16:30 +06:00
Hasan
ec53640acb Merge pull request #2 from Tapfury/latestReceipt
Verfiy latest receipt
2019-08-06 18:51:28 +06:00
sanjid133
ee59170931 Verfiy latest receipt 2019-08-06 17:22:41 +06:00
Hasan
c992b9705b Merge pull request #1 from Tapfury/isupgrade
Add missing is_upgrade field
2019-08-01 17:55:11 +06:00
sanjid133
ff9fd778a3 Add missing is_upgrade field 2019-08-01 17:53:26 +06:00
Minhaz Ahmed Syrus
1877c0ae24 Add missing subscription billing retry flag 2019-08-01 17:34:39 +06:00
Minhaz Ahmed Syrus
7ef252fde0 Add missing notification verification fields 2019-08-01 17:34:39 +06:00
kitakitabauer
062102b0f3 Merge pull request #93 from awa/androidpublisher-v3
Update androidpublisher api v3
2019-06-19 16:36:38 +09:00
Junpei Tsuji
f0014d5a79 Merge pull request #92 from jun06t/ack
Added acknowledge method for subscription
2019-05-31 11:06:24 +09:00
Junpei Tsuji
c446edf3c4 Added acknowledge method for subscription 2019-05-31 11:03:51 +09:00
Junpei Tsuji
c6347f9585 Merge pull request #91 from jun06t/v3
Update androidpublisher api v3
2019-05-23 17:53:24 +09:00
Junpei Tsuji
c8899d8d2d Update androidpublisher api v3 2019-05-23 17:47:36 +09:00
Junpei Tsuji
ebccfd0170 Merge pull request #90 from jun06t/gomod
Use go modules
2019-05-23 17:36:00 +09:00
Junpei Tsuji
b4e4bec42f Use go modules 2019-05-23 17:27:20 +09:00
Minhaz Syrus
12a8101bb0 Merge branch 'master' of github.com:awa/go-iap 2019-03-23 19:28:46 +06:00
Minhaz Syrus
f94fdb06d8 Merge branch 'master' of github.com:awa/go-iap 2019-02-02 12:17:08 +06:00
Minhaz Ahmed Syrus
c371d6eb78 Add missing subscription billing retry flag 2018-11-06 16:58:05 +06:00
Minhaz Ahmed Syrus
6d5e856650 Add missing notification verification fields 2018-11-06 14:25:38 +06:00
10 changed files with 279 additions and 37 deletions

View File

@@ -1,6 +1,9 @@
language: go
go:
- 1.11.2
- 1.12.5
env:
global:
- GO111MODULE=on
before_install:
- sudo pip install codecov
install:

View File

@@ -1,7 +1,7 @@
go-iap
======
![](https://img.shields.io/badge/golang-1.11-blue.svg?style=flat)
![](https://img.shields.io/badge/golang-1.12-blue.svg?style=flat)
[![Build Status](https://travis-ci.org/awa/go-iap.svg?branch=master)](https://travis-ci.org/awa/go-iap)
[![codecov.io](https://codecov.io/github/awa/go-iap/coverage.svg?branch=master)](https://codecov.io/github/awa/go-iap?branch=master)
@@ -14,13 +14,6 @@ Current API Documents:
* Amazon AppStore: [![GoDoc](https://godoc.org/github.com/awa/go-iap/amazon?status.svg)](https://godoc.org/github.com/awa/go-iap/amazon)
# Dependencies
```
go get golang.org/x/oauth2
go get golang.org/x/oauth2/google
go get google.golang.org/api/androidpublisher/v2
```
# Installation
```
go get github.com/awa/go-iap/appstore

View File

@@ -76,6 +76,13 @@ type (
CancellationDatePST string `json:"cancellation_date_pst,omitempty"`
}
// The GracePeriodDate type indicates the grace period date for the subscription
GracePeriodDate struct {
GracePeriodDate string `json:"grace_period_expires_date,omitempty"`
GracePeriodDateMS string `json:"grace_period_expires_date_ms,omitempty"`
GracePeriodDatePST string `json:"grace_period_expires_date_pst,omitempty"`
}
// The InApp type has the receipt attributes
InApp struct {
Quantity string `json:"quantity"`
@@ -83,9 +90,13 @@ type (
TransactionID string `json:"transaction_id"`
OriginalTransactionID string `json:"original_transaction_id"`
WebOrderLineItemID string `json:"web_order_line_item_id,omitempty"`
PromotionalOfferID string `json:"promotional_offer_id"`
SubscriptionGroupIdentifier string `json:"subscription_group_identifier"`
IsTrialPeriod string `json:"is_trial_period"`
IsInIntroOfferPeriod string `json:"is_in_intro_offer_period,omitempty"`
IsUpgraded string `json:"is_upgraded"`
ExpiresDate
PurchaseDate
@@ -93,6 +104,7 @@ type (
CancellationDate
CancellationReason string `json:"cancellation_reason,omitempty"`
IsUpgraded string `json:"is_upgraded,omitempty"`
}
// The Receipt type has whole data of receipt
@@ -120,6 +132,8 @@ type (
SubscriptionPriceConsentStatus string `json:"price_consent_status"`
ProductID string `json:"product_id"`
OriginalTransactionID string `json:"original_transaction_id"`
GracePeriodDate
}
// The IAPResponse type has the response properties
@@ -136,6 +150,18 @@ type (
PendingRenewalInfo []PendingRenewalInfo `json:"pending_renewal_info,omitempty"`
IsRetryable bool `json:"is-retryable,omitempty"`
}
// The IAPLatestResponse type has the response properties
// If you use latest_receipt as token to verify, response should be like following struct
IAPLatestResponse struct {
Status int `json:"status,omitempty"`
Receipt InApp `json:"receipt"`
LatestReceiptInfo InApp `json:"latest_receipt_info,omitempty"`
LatestExpiredReceiptInfo InApp `json:"latest_expired_receipt_info,omitempty"`
LatestReceipt string `json:"latest_receipt,omitempty"`
SubscriptionAutoRenewStatus string `json:"auto_renew_status,omitempty"`
SubscriptionAutoRenewProductID string `json:"auto_renew_product_id,omitempty"`
SubscriptionRetryFlag string `json:"is_in_billing_retry_period,omitempty"`
}
// The HttpStatusResponse struct contains the status code returned by the store
// Used as a workaround to detect when to hit the production appstore or sandbox appstore regardless of receipt type

View File

@@ -33,7 +33,7 @@ func TestNumericString_UnmarshalJSON(t *testing.T) {
{
name: "object case",
in: []byte("{\"ID\":{\"Num\": 8080}}"),
err: errors.New("json: cannot unmarshal object into Go value of type json.Number"),
err: errors.New("json: cannot unmarshal object into Go struct field foo.ID of type json.Number"),
out: foo{},
},
}

View File

@@ -9,7 +9,10 @@ const (
// Subscription was canceled by Apple customer support.
NotificationTypeCancel NotificationType = "CANCEL"
// Automatic renewal was successful for an expired subscription.
// Deprecated: DID_RECOVER should be used instead of RENEWAL
NotificationTypeRenewal NotificationType = "RENEWAL"
// Expired subscription recovered through a billing retry.
NotificationTypeDidRecover NotificationType = "DID_RECOVER"
// Customer renewed a subscription interactively after it lapsed.
NotificationTypeInteractiveRenewal NotificationType = "INTERACTIVE_RENEWAL"
// Customer changed the plan that takes affect at the next subscription renewal. Current active plan is not affected.
@@ -53,6 +56,14 @@ type NotificationReceipt struct {
CancellationDate
}
type NotificationUnifiedReceipt struct {
Status string `json:"status"`
Environment Environment `json:"environment"`
LatestReceipt string `json:"latest_receipt"`
LatestReceiptInfo []InApp `json:"latest_receipt_info"`
PendingRenewalInfo []PendingRenewalInfo `json:"pending_renewal_info,omitempty"`
}
type SubscriptionNotification struct {
Environment NotificationEnvironment `json:"environment"`
NotificationType NotificationType `json:"notification_type"`
@@ -74,12 +85,20 @@ type SubscriptionNotification struct {
AutoRenewStatus string `json:"auto_renew_status"` // false or true
AutoRenewProductID string `json:"auto_renew_product_id"`
// HACK (msyrus): Separate Subscriptiton Notification from Notification verification response
Status int `json:"status,omitempty"`
Receipt NotificationReceipt `json:"recipt"`
SubscriptionRetryFlag string `json:"is_in_billing_retry_period"`
// Posted if the notification_type is RENEWAL or INTERACTIVE_RENEWAL, and only if the renewal is successful.
// Posted also if the notification_type is INITIAL_BUY.
// Not posted for notification_type CANCEL.
LatestReceipt string `json:"latest_receipt"`
LatestReceiptInfo NotificationReceipt `json:"latest_receipt_info"`
// In the new notifications above properties latest_receipt, latest_receipt_info are moved under this one
UnifiedReceipt NotificationUnifiedReceipt `json:"unified_receipt"`
// Posted only if the notification_type is RENEWAL or CANCEL or if renewal failed and subscription expired.
LatestExpiredReceipt string `json:"latest_expired_receipt"`
LatestExpiredReceiptInfo NotificationReceipt `json:"latest_expired_receipt_info"`

View File

@@ -96,64 +96,64 @@ func NewWithClient(client *http.Client) *Client {
}
// Verify sends receipts and gets validation result
func (c *Client) Verify(ctx context.Context, reqBody IAPRequest, result interface{}) error {
func (c *Client) Verify(ctx context.Context, reqBody IAPRequest, result interface{}) (Environment, error) {
b := new(bytes.Buffer)
if err := json.NewEncoder(b).Encode(reqBody); err != nil {
return err
return "", err
}
req, err := http.NewRequest("POST", c.ProductionURL, b)
if err != nil {
return err
return "", err
}
req.Header.Set("Content-Type", ContentType)
req = req.WithContext(ctx)
resp, err := c.httpCli.Do(req)
if err != nil {
return err
return "", err
}
defer resp.Body.Close()
return c.parseResponse(resp, result, ctx, reqBody)
}
func (c *Client) parseResponse(resp *http.Response, result interface{}, ctx context.Context, reqBody IAPRequest) error {
func (c *Client) parseResponse(resp *http.Response, result interface{}, ctx context.Context, reqBody IAPRequest) (Environment, error) {
// Read the body now so that we can unmarshal it twice
buf, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
return "", err
}
err = json.Unmarshal(buf, &result)
if err != nil {
return err
return "", err
}
// https://developer.apple.com/library/content/technotes/tn2413/_index.html#//apple_ref/doc/uid/DTS40016228-CH1-RECEIPTURL
var r StatusResponse
err = json.Unmarshal(buf, &r)
if err != nil {
return err
return "", err
}
if r.Status == 21007 {
b := new(bytes.Buffer)
if err := json.NewEncoder(b).Encode(reqBody); err != nil {
return err
return "", err
}
req, err := http.NewRequest("POST", c.SandboxURL, b)
if err != nil {
return err
return "", err
}
req.Header.Set("Content-Type", ContentType)
req = req.WithContext(ctx)
resp, err := c.httpCli.Do(req)
if err != nil {
return err
return "", err
}
defer resp.Body.Close()
return json.NewDecoder(resp.Body).Decode(result)
// 21007 is found when the receipt is from the test environment
return Sandbox, json.NewDecoder(resp.Body).Decode(result)
}
return nil
return Production, nil
}

27
go.mod Normal file
View File

@@ -0,0 +1,27 @@
module github.com/awa/go-iap
go 1.12
require (
cloud.google.com/go v0.39.0 // indirect
github.com/golang/mock v1.3.1 // indirect
github.com/google/btree v1.0.0 // indirect
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f // indirect
github.com/kr/pty v1.1.4 // indirect
go.opencensus.io v0.22.0 // indirect
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 // indirect
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522 // indirect
golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff // indirect
golang.org/x/lint v0.0.0-20190409202823-959b441ac422 // indirect
golang.org/x/mobile v0.0.0-20190509164839-32b2708ab171 // indirect
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 // indirect
golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0
golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1 // indirect
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
golang.org/x/tools v0.0.0-20190530215528-75312fb06703 // indirect
google.golang.org/api v0.5.1-0.20190526001144-9f3a303b451f
google.golang.org/appengine v1.6.0
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101 // indirect
google.golang.org/grpc v1.21.0 // indirect
honnef.co/go/tools v0.0.0-20190530170028-a1efa522b896 // indirect
)

130
go.sum Normal file
View File

@@ -0,0 +1,130 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.39.0 h1:UgQP9na6OTfp4dsAiz/eFpFA1C6tPdH5wiRdi19tuMw=
cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190509164839-32b2708ab171/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07 h1:XC1K3wNjuz44KaI+cj85C9TW85w/46RH7J+DTXNH5Wk=
golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0 h1:xFEXbcD0oa/xhqQmMXztdZ0bWvexAWds+8c1gRN8nu0=
golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190530215528-75312fb06703/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
google.golang.org/api v0.5.0 h1:lj9SyhMzyoa38fgFF0oO2T6pjs5IzkLPKfVtxpyCRMM=
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.5.1-0.20190526001144-9f3a303b451f h1:tAgkkP6ovjCY8HraRtpXwh0CVqHwGqEAVLHwXyfFjIM=
google.golang.org/api v0.5.1-0.20190526001144-9f3a303b451f/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw=
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 h1:Lj2SnHtxkRGJDqnGaSjo+CCdIieEnwVazbOXILwQemk=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69 h1:4rNOqY4ULrKzS6twXa619uQgI7h9PaVd4ZhjFQ7C5zs=
google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101 h1:wuGevabY6r+ivPNagjUXGGxF+GqgMd+dBhjsxW4q9u4=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190530170028-a1efa522b896/go.mod h1:wtc9q0E9zm8PjdRMh29DPlTlCCHVzKDwnkT4GskQVzg=

View File

@@ -13,13 +13,18 @@ import (
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
androidpublisher "google.golang.org/api/androidpublisher/v2"
androidpublisher "google.golang.org/api/androidpublisher/v3"
)
// The IABClient type is an interface to verify purchase token
type IABClient interface {
VerifySubscription(context.Context, string, string, string) (*androidpublisher.SubscriptionPurchase, error)
// The IABProduct type is an interface for product service
type IABProduct interface {
VerifyProduct(context.Context, string, string, string) (*androidpublisher.ProductPurchase, error)
}
// The IABSubscription type is an interface for subscription service
type IABSubscription interface {
AcknowledgeSubscription(context.Context, string, string, string, *androidpublisher.SubscriptionPurchasesAcknowledgeRequest) error
VerifySubscription(context.Context, string, string, string) (*androidpublisher.SubscriptionPurchase, error)
CancelSubscription(context.Context, string, string, string) error
RefundSubscription(context.Context, string, string, string) error
RevokeSubscription(context.Context, string, string, string) error
@@ -53,6 +58,25 @@ func NewWithClient(jsonKey []byte, cli *http.Client) (*Client, error) {
return &Client{conf.Client(ctx)}, err
}
// AcknowledgeSubscription acknowledges a subscription purchase.
func (c *Client) AcknowledgeSubscription(
ctx context.Context,
packageName string,
subscriptionID string,
token string,
req *androidpublisher.SubscriptionPurchasesAcknowledgeRequest,
) error {
service, err := androidpublisher.New(c.httpCli)
if err != nil {
return err
}
ps := androidpublisher.NewPurchasesSubscriptionsService(service)
err = ps.Acknowledge(packageName, subscriptionID, token, req).Context(ctx).Do()
return err
}
// VerifySubscription verifies subscription status
func (c *Client) VerifySubscription(
ctx context.Context,

View File

@@ -8,6 +8,7 @@ import (
"testing"
"golang.org/x/oauth2"
androidpublisher "google.golang.org/api/androidpublisher/v3"
"google.golang.org/appengine/urlfetch"
)
@@ -70,10 +71,29 @@ func TestNewWithClient(t *testing.T) {
}
}
func TestAcknowledgeSubscription(t *testing.T) {
t.Parallel()
// Exception scenario
expected := "googleapi: Error 400: Invalid Value, invalid"
client, _ := New(jsonKey)
ctx := context.Background()
req := &androidpublisher.SubscriptionPurchasesAcknowledgeRequest{
DeveloperPayload: "user001",
}
err := client.AcknowledgeSubscription(ctx, "package", "subscriptionID", "purchaseToken", req)
if err.Error() != expected {
t.Errorf("got %v\nwant %v", err, expected)
}
// TODO Normal scenario
}
func TestVerifySubscription(t *testing.T) {
t.Parallel()
// Exception scenario
expected := "googleapi: Error 404: No application was found for the given package name., applicationNotFound"
expected := "googleapi: Error 400: Invalid Value, invalid"
client, _ := New(jsonKey)
ctx := context.Background()
@@ -101,7 +121,7 @@ func TestVerifySubscriptionAndroidPublisherError(t *testing.T) {
func TestVerifyProduct(t *testing.T) {
t.Parallel()
// Exception scenario
expected := "googleapi: Error 404: No application was found for the given package name., applicationNotFound"
expected := "googleapi: Error 400: Invalid Value, invalid"
client, _ := New(jsonKey)
ctx := context.Background()
@@ -139,7 +159,7 @@ func TestCancelSubscription(t *testing.T) {
}
client, _ = New(jsonKey)
expectedStr := "googleapi: Error 404: No application was found for the given package name., applicationNotFound"
expectedStr := "googleapi: Error 400: Invalid Value, invalid"
actual = client.CancelSubscription(ctx, "package", "productID", "purchaseToken")
if actual.Error() != expectedStr {