15 Commits

Author SHA1 Message Date
sanjid133
4f7b16717e fix auto renew status 2020-03-05 17:35:21 +06:00
sanjid133
a564d013c9 status field not present in initial_buy 2020-03-05 17:35:21 +06:00
sanjid133
134bcb9b89 auto renew status string 2020-03-05 17:35:21 +06:00
sanjid133
5cc0a53c63 Verfiy latest receipt 2020-03-05 17:35:21 +06:00
Minhaz Ahmed Syrus
22c0b76a09 Add missing subscription billing retry flag 2020-03-05 17:33:20 +06:00
Minhaz Ahmed Syrus
0ae05687d4 Add missing notification verification fields 2020-03-05 17:33:20 +06:00
Minhaz Ahmed Syrus
b04c08d22b Add missing subscription billing retry flag 2020-03-05 17:32:57 +06:00
Minhaz Ahmed Syrus
9b772f3398 Add missing notification verification fields 2020-03-05 17:32:19 +06:00
sanjid133
073874b26d Add renewal field 2020-03-05 17:31:39 +06:00
sanjid133
a14bd11b0c Verfiy latest receipt 2020-03-05 17:31:39 +06:00
sanjid133
7f77f5e33e Add missing is_upgrade field 2020-03-05 17:00:02 +06:00
Minhaz Ahmed Syrus
eacfb2d096 Add missing subscription billing retry flag 2020-03-05 17:00:02 +06:00
Minhaz Ahmed Syrus
91cd5b791c Add missing notification verification fields 2020-03-05 16:59:30 +06:00
Minhaz Ahmed Syrus
2700fc2ec0 Add missing subscription billing retry flag 2020-03-05 16:57:47 +06:00
Minhaz Ahmed Syrus
e4338cd607 Add missing notification verification fields 2020-03-05 16:57:47 +06:00
3 changed files with 35 additions and 16 deletions

View File

@@ -150,6 +150,19 @@ 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,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 interface{} `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
StatusResponse struct {

View File

@@ -87,6 +87,11 @@ 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.

View File

@@ -105,70 +105,71 @@ 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()
if resp.StatusCode >= 500 {
return fmt.Errorf("Received http status code %d from the App Store: %w", resp.StatusCode, ErrAppStoreServer)
return "", fmt.Errorf("Received http status code %d from the App Store: %w", resp.StatusCode, ErrAppStoreServer)
}
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()
if resp.StatusCode >= 500 {
return fmt.Errorf("Received http status code %d from the App Store Sandbox: %w", resp.StatusCode, ErrAppStoreServer)
return Sandbox, fmt.Errorf("Received http status code %d from the App Store Sandbox: %w", resp.StatusCode, ErrAppStoreServer)
}
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
}