From 4ed348bb1b6a058e940cc3d2475ecd59eee10ebd Mon Sep 17 00:00:00 2001 From: Minhaz Ahmed Syrus Date: Tue, 6 Nov 2018 14:25:38 +0600 Subject: [PATCH 1/9] 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 94f276769f691dfe59ba368fe06c1cb34c65e021 Mon Sep 17 00:00:00 2001 From: Minhaz Ahmed Syrus Date: Tue, 6 Nov 2018 16:58:05 +0600 Subject: [PATCH 2/9] 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 bac6b5676bc848bcebf95f239ab26a5619661a4b Mon Sep 17 00:00:00 2001 From: Minhaz Ahmed Syrus Date: Tue, 6 Nov 2018 14:25:38 +0600 Subject: [PATCH 3/9] Add missing notification verification fields --- appstore/notification.go | 1 + 1 file changed, 1 insertion(+) diff --git a/appstore/notification.go b/appstore/notification.go index 4c2b680..c01194f 100644 --- a/appstore/notification.go +++ b/appstore/notification.go @@ -79,6 +79,7 @@ type SubscriptionNotification struct { 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. From fbfe02b5f63f501f1eddb19706d1b6e384152a5c Mon Sep 17 00:00:00 2001 From: Minhaz Ahmed Syrus Date: Tue, 6 Nov 2018 16:58:05 +0600 Subject: [PATCH 4/9] Add missing subscription billing retry flag --- appstore/notification.go | 1 - 1 file changed, 1 deletion(-) diff --git a/appstore/notification.go b/appstore/notification.go index c01194f..4c2b680 100644 --- a/appstore/notification.go +++ b/appstore/notification.go @@ -79,7 +79,6 @@ type SubscriptionNotification struct { 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. From c92634081e443de354f269286e8ba728f86bdabb Mon Sep 17 00:00:00 2001 From: sanjid133 Date: Thu, 1 Aug 2019 17:46:48 +0600 Subject: [PATCH 5/9] 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 b60c954624cad811ccc14cb93293c4a3f43ce8a3 Mon Sep 17 00:00:00 2001 From: sanjid133 Date: Tue, 6 Aug 2019 17:22:41 +0600 Subject: [PATCH 6/9] 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 11e072e211d00f2398781b2a6a888fdff7f399eb Mon Sep 17 00:00:00 2001 From: sanjid133 Date: Wed, 7 Aug 2019 15:16:30 +0600 Subject: [PATCH 7/9] 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 From e0f6e608e77b5ebfcfcbf78da63fcc69798a6b4e Mon Sep 17 00:00:00 2001 From: sanjid133 Date: Thu, 8 Aug 2019 14:48:47 +0600 Subject: [PATCH 8/9] auto renew status string --- appstore/notification.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appstore/notification.go b/appstore/notification.go index 4c2b680..1e18848 100644 --- a/appstore/notification.go +++ b/appstore/notification.go @@ -71,7 +71,7 @@ type SubscriptionNotification struct { ExpirationIntent string `json:"expiration_intent"` // Auto renew info - AutoRenewStatus int `json:"auto_renew_status"` // false or true + 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 From 8414aff3448deae430006c8635568d53a0db1930 Mon Sep 17 00:00:00 2001 From: sanjid133 Date: Sun, 18 Aug 2019 13:33:20 +0600 Subject: [PATCH 9/9] status field not present in initial_buy --- appstore/model.go | 2 +- appstore/notification.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appstore/model.go b/appstore/model.go index a3d4a97..bac4e61 100644 --- a/appstore/model.go +++ b/appstore/model.go @@ -141,7 +141,7 @@ 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"` + Status int `json:"status,omitempty"` Receipt InApp `json:"receipt"` LatestReceiptInfo InApp `json:"latest_receipt_info,omitempty"` LatestExpiredReceiptInfo InApp `json:"latest_expired_receipt_info,omitempty"` diff --git a/appstore/notification.go b/appstore/notification.go index 1e18848..4a38b82 100644 --- a/appstore/notification.go +++ b/appstore/notification.go @@ -75,7 +75,7 @@ type SubscriptionNotification struct { AutoRenewProductID string `json:"auto_renew_product_id"` // HACK (msyrus): Separate Subscriptiton Notification from Notification verification response - Status int `json:"status"` + Status int `json:"status,omitempty"` Receipt NotificationReceipt `json:"recipt"` SubscriptionRetryFlag string `json:"is_in_billing_retry_period"`