From a14bd11b0c03e4d9a0a93288da21c79def40d264 Mon Sep 17 00:00:00 2001 From: sanjid133 Date: Tue, 6 Aug 2019 17:22:41 +0600 Subject: [PATCH] Verfiy latest receipt --- appstore/model.go | 10 ++++++++++ appstore/validator.go | 31 ++++++++++++++++--------------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/appstore/model.go b/appstore/model.go index 19182fa..a6f0f4f 100644 --- a/appstore/model.go +++ b/appstore/model.go @@ -151,6 +151,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 dee06bc..077dc7d 100644 --- a/appstore/validator.go +++ b/appstore/validator.go @@ -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 }