From 6d5e856650d7733c1940c325acdea930011ba870 Mon Sep 17 00:00:00 2001 From: Minhaz Ahmed Syrus Date: Tue, 6 Nov 2018 14:25:38 +0600 Subject: [PATCH 1/7] Add missing notification verification fields --- appstore/notification.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appstore/notification.go b/appstore/notification.go index 9637a5d..64e76af 100644 --- a/appstore/notification.go +++ b/appstore/notification.go @@ -69,9 +69,13 @@ type SubscriptionNotification struct { ExpirationIntent string `json:"expiration_intent"` // Auto renew info - AutoRenewStatus string `json:"auto_renew_status"` // false or true + AutoRenewStatus int `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"` + Receipt NotificationReceipt `json:"recipt"` + // 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. From c371d6eb7882fe48222077a927e59524fe60539f Mon Sep 17 00:00:00 2001 From: Minhaz Ahmed Syrus Date: Tue, 6 Nov 2018 16:58:05 +0600 Subject: [PATCH 2/7] Add missing subscription billing retry flag --- appstore/notification.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/appstore/notification.go b/appstore/notification.go index 64e76af..3e61b63 100644 --- a/appstore/notification.go +++ b/appstore/notification.go @@ -73,8 +73,9 @@ type SubscriptionNotification struct { AutoRenewProductID string `json:"auto_renew_product_id"` // HACK (msyrus): Separate Subscriptiton Notification from Notification verification response - Status int `json:"status"` - Receipt NotificationReceipt `json:"recipt"` + Status int `json:"status"` + 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. From 7ef252fde0e2f8e22b693356a0d4445c97aa0a7f Mon Sep 17 00:00:00 2001 From: Minhaz Ahmed Syrus Date: Tue, 6 Nov 2018 14:25:38 +0600 Subject: [PATCH 3/7] Add missing notification verification fields --- appstore/notification.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appstore/notification.go b/appstore/notification.go index 4c3df6f..19af79e 100644 --- a/appstore/notification.go +++ b/appstore/notification.go @@ -71,9 +71,13 @@ type SubscriptionNotification struct { ExpirationIntent string `json:"expiration_intent"` // Auto renew info - AutoRenewStatus string `json:"auto_renew_status"` // false or true + AutoRenewStatus int `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"` + Receipt NotificationReceipt `json:"recipt"` + // 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. From 1877c0ae24bca4f7440c9a7ee928b76b399b8934 Mon Sep 17 00:00:00 2001 From: Minhaz Ahmed Syrus Date: Tue, 6 Nov 2018 16:58:05 +0600 Subject: [PATCH 4/7] Add missing subscription billing retry flag --- appstore/notification.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/appstore/notification.go b/appstore/notification.go index 19af79e..4c2b680 100644 --- a/appstore/notification.go +++ b/appstore/notification.go @@ -75,8 +75,9 @@ type SubscriptionNotification struct { AutoRenewProductID string `json:"auto_renew_product_id"` // HACK (msyrus): Separate Subscriptiton Notification from Notification verification response - Status int `json:"status"` - Receipt NotificationReceipt `json:"recipt"` + Status int `json:"status"` + 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. From ff9fd778a3d2e57e68840c3722aaa7632e6b7a1d Mon Sep 17 00:00:00 2001 From: sanjid133 Date: Thu, 1 Aug 2019 17:46:48 +0600 Subject: [PATCH 5/7] Add missing is_upgrade field --- appstore/model.go | 1 + 1 file changed, 1 insertion(+) diff --git a/appstore/model.go b/appstore/model.go index 58c8eb1..0561631 100644 --- a/appstore/model.go +++ b/appstore/model.go @@ -93,6 +93,7 @@ type ( CancellationDate CancellationReason string `json:"cancellation_reason,omitempty"` + IsUpgraded string `json:"is_upgraded,omitempty"` } // The Receipt type has whole data of receipt From ee59170931549ec5a323e77e4a6d3c96ec303645 Mon Sep 17 00:00:00 2001 From: sanjid133 Date: Tue, 6 Aug 2019 17:22:41 +0600 Subject: [PATCH 6/7] Verfiy latest receipt --- appstore/model.go | 10 ++++++++++ appstore/validator.go | 28 ++++++++++++++-------------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/appstore/model.go b/appstore/model.go index 0561631..789bc14 100644 --- a/appstore/model.go +++ b/appstore/model.go @@ -138,6 +138,16 @@ type ( 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"` + 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"` + } + // 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 StatusResponse struct { diff --git a/appstore/validator.go b/appstore/validator.go index 4786f01..9b8698f 100644 --- a/appstore/validator.go +++ b/appstore/validator.go @@ -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 } From 5354251ea54cccf7727eb089118feece28085064 Mon Sep 17 00:00:00 2001 From: sanjid133 Date: Wed, 7 Aug 2019 15:16:30 +0600 Subject: [PATCH 7/7] Add renewal field --- appstore/model.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/appstore/model.go b/appstore/model.go index 789bc14..a3d4a97 100644 --- a/appstore/model.go +++ b/appstore/model.go @@ -141,11 +141,14 @@ type ( // 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"` - 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"` + Status int `json:"status"` + 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