GithubHelp home page GithubHelp logo

awa / go-iap Goto Github PK

View Code? Open in Web Editor NEW
863.0 863.0 245.0 438 KB

go-iap verifies the purchase receipt via AppStore, GooglePlayStore, AmazonAppStore and Huawei HMS.

License: MIT License

Makefile 0.24% Go 99.76%
amazonappstrore appstore billing googleplaystore hms iab iap purchase-receipt

go-iap's People

Contributors

ashhadsheikh avatar avivmag avatar bobdu avatar bogdanconstantinescu avatar daydaylw3 avatar dbican-gpsw avatar djworth avatar dominiclvrpl avatar folone avatar jaryf avatar jbgosselin avatar jordancco avatar jun06t avatar kaijietti avatar kitakitabauer avatar mlesar avatar monkey92t avatar msyrus avatar nikonm avatar ojrac avatar omarelgabry avatar richzw avatar riskimidiw avatar sams96 avatar sanae10001 avatar swordkee avatar takecy avatar timothylock avatar tockn avatar zeevallin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-iap's Issues

How to send receipt-data?

I send from my app like this:

{"receipt-data":"MIISZAYJKoZIhvcNAQcCoIISVTCCElECAQExCzAJBgUrDgMCGgUAMIICBQYJ etc..."}

Is it right?

My code:

var IAPTest = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
err := r.ParseForm()
if err != nil {
	panic(err)
}

v := r.Form
var re string
for i := range v {
	re = i
}

fmt.Println("This is re: ", re)

client := appstore.New()
req := appstore.IAPRequest{
	ReceiptData: re,
}

resp := &appstore.IAPResponse{}
ctx := context.Background()
err2 := client.Verify(ctx, req, resp)

fmt.Println("client", client)
fmt.Println("req", req)
fmt.Println("resp", resp)
fmt.Println("ctx", ctx)
fmt.Println("err", err2)

And my response:

client &{https://buy.itunes.apple.com/verifyReceipt https://sandbox.itunes.apple.com/verifyReceipt 0x1a12f680}
req {{"receipt-data":"MIIWdgYJKoZIhvcNAQcCoIIWZzCCFmMCAQExCzAJBgUrDgMCGgUAMIIGFwYJK
resp &{21002  { 0    0   [] {  } {  } {  }} []  [] false}

Post "https://buy.itunes.apple.com/verifyReceipt": EOF

Hey,

Thank you for this awesome package, we are using go-iap to verify apple receipts, and we have some failing requests with EOF errors in production, after checking the failed receipts I can verify that they are valid, and after a retry the verify request is passing with no issue, I think it might be related to empty response from apple side, any idea how to handle it?

We are using v1.3.8 here is a code snippet -

         iapReq := appstore.IAPRequest{
		ReceiptData: receiptData,
		Password:   password,
	}
	iapResp := &appstore.IAPResponse{}
	err := s.asc.Verify(ctx, iapReq, iapResp)

Thanks!

Failed to go get github.com/awa/go-iap/playstore

I got the following error message

go/src/github.com/awa/go-iap/playstore/validator.go:26:68: undefined: androidpublisher.SubscriptionPurchasesAcknowledgeRequest go/src/github.com/awa/go-iap/playstore/validator.go:67:7: undefined: androidpublisher.SubscriptionPurchasesAcknowledgeRequest go/src/github.com/awa/go-iap/playstore/validator.go:75:10: ps.Acknowledge undefined (type *androidpublisher.PurchasesSubscriptionsService has no field or method Acknowledge)

Needs new field of IAPResponse "unifined_reciept"

As per the official documentation, since 2021 3/10 the "latest_receipt" field is now an old field and requires "unified_reciept" as well NotificationUnifiedReciept.

ref:
https://developer.apple.com/documentation/appstoreservernotifications/responsebody

latest_receipt
byte
Removed. As of March 10, 2021 this object is no longer provided in production and sandbox environments. Use the latest_receipt field found in the unified_receipt object instead.

`is_in_intro_offer_period` is missing at InApp model in appstore package

From apple developer reference there is a is_in_intro_offer_period and below is a sample response struct from my project

		"in_app": [
			{
				"quantity": "1",
				"product_id": "com.ghostcall.testsubscription.1monthpass",
				"transaction_id": "1000000463911073",
				"original_transaction_id": "1000000463911073",
				"purchase_date": "2018-10-27 18:02:50 Etc/GMT",
				"purchase_date_ms": "1540663370000",
				"purchase_date_pst": "2018-10-27 11:02:50 America/Los_Angeles",
				"original_purchase_date": "2018-10-27 18:02:50 Etc/GMT",
				"original_purchase_date_ms": "1540663370000",
				"original_purchase_date_pst": "2018-10-27 11:02:50 America/Los_Angeles",
				"expires_date": "2018-10-27 18:07:50 Etc/GMT",
				"expires_date_ms": "1540663670000",
				"expires_date_pst": "2018-10-27 11:07:50 America/Los_Angeles",
				"web_order_line_item_id": "1000000041021420",
				"is_trial_period": "false",
				"is_in_intro_offer_period": "false"
			}
		]

But the is_in_intro_offer_period is missing at InApp model in appstore package

Missing `latest_receipt` and `latest_receipt_info` definition in IAPResponseForIOS6?

Per this doc

`latest_receipt

Only returned for receipts containing auto-renewable subscriptions. For iOS 6 style transaction receipts, this is the base-64 encoded receipt for the most recent renewal. For iOS 7 style app receipts, this is the latest base-64 encoded app receipt.

latest_receipt_info

Only returned for receipts containing auto-renewable subscriptions. For iOS 6 style transaction receipts, this is the JSON representation of the receipt for the most recent renewal. For iOS 7 style app receipts, the value of this key is an array containing all in-app purchase transactions. This excludes transactions for a consumable product that have been marked as finished by your app.`

However, I cannot find those two fields defined in IAPResponseForIOS6?

Docker Image

Is there any plans to provide library as docker image ?

transacionID not exist in subscription

When I purchased the first item, the validation that the appstore returned to me did not include the transactionID that the client sent me.
environment:SandBox

GoogleAPI error messages has been changed

So some tests fail now.

--- FAIL: TestCancelSubscription (0.09s)
    validator_test.go:166: got googleapi: Error 400: Invalid Value, invalid
        want googleapi: Error 404: No application was found for the given package name., applicationNotFound
--- FAIL: TestVerifyProduct (0.09s)
    validator_test.go:131: got googleapi: Error 400: Invalid Value, invalid
--- FAIL: TestVerifySubscription (0.09s)
    validator_test.go:103: got googleapi: Error 400: Invalid Value, invalid
        want googleapi: Error 404: No application was found for the given package name., applicationNotFound
--- FAIL: TestAcknowledgeSubscription (0.10s)
    validator_test.go:87: got googleapi: Error 400: Invalid Value, invalid
        want googleapi: Error 404: No application was found for the given package name., applicationNotFound
FAIL

Appstore returning error as HTML

The appstore appears to be returning HTML from an API call resulting in the following error propagating from the client.Verify call (I believe its actually coming from the parseResponse method when attempting to decode JSON that is actually in HTML format. I have logged the same error from other API's that have returned HTML when JSON is expected in code I have written.

invalid character '<' looking for beginning of value

library version: 1.2.0/1.3.0
go version: 1.13.12

Getting empty response body from Verify

Calling appstore.Verify is giving me EOF errors. On closer inspection, these are being thrown by https://github.com/dogenzaka/go-iap/blob/e9d5da1f8f6bff09e3f0ff777a44fe617e45ae52/appstore/validator.go#L112 as the body from the previous request is empty.

Inspecting the gorequest with AsCurlCommand() and running that as a curl command, the request succeeds with a valid (albeit large) response body every time.

Ultimately, what appears to be happening is when the receipt response is large (this can happen very quickly with iOS especially with autorenewing subscriptions) something isn't reading it properly. I don't know if this is in the std lib or gorequest, all I know is the string being passed to the json decoder is empty, and it's never empty when the same request is ran with curl.

invalid character '<' looking for beginning of value

When validating ios receipt data, some of the receipts are failing the client.Verify call with the following error

invalid character '<' looking for beginning of value

The data is the raw base64 encoded string that the app receives. Having passed the data through base64 decode using the following site https://www.base64decode.org/ it would appear that changing the charset from UTF-8 to ASCII means the receipt then decodes as expected, but given this is only happening for some receipts and not others I believe the issue is better fixed in this library.

Any thoughts on what might be causing this?

The letter case of appstore.NotificationEnv constants

The appstore.NotificationEnv constants are currently "SANDBOX" and "PROD". I just noticed that Apple sends "Sandbox" - i.e. different letter case.

Apple's documentation contradicts itself on the same page: https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Subscriptions.html

First, Table 6-3 says the values are "Sandbox" and "PROD".

Later it says "To determine if a status update notifications for a subscription event is in the test environment, check if the value of the environment key in the statusUpdateNotification JSON object equals SANDBOX."

Based on observation, I'm guessing the second paragraph has a bug and got the case wrong.

I think the appstore.NotificationEnvSandbox constant needs to be changed to "Sandbox"

playstore: is oauth compulsory

Thanks for open sourcing the library!

I have a problem that if the oauth compulsory when I only want to call client.VerifyProduct.

Google App Engine compatibility

Introduction

Google App Engine is a sandboxed environment. We can't make calls to the outside world without using the net/http's Request to create a http.Client by:

import (
        "net/http"

        "google.golang.org/appengine"
        "google.golang.org/appengine/urlfetch"
)
ctx := appengine.NewContext(r)
client := urlfetch.Client(ctx)

Without doing that, the library doesn't work.

The way Stripe-Go-Library handles it is like this: https://github.com/stripe/stripe-go#google-appengine

Basically Stripe allows Google App Engine users the ability to feed in their own http Client and the library will then use that.

    ctx := appengine.NewContext(r)
    httpClient := urlfetch.Client(ctx)

    sc := client.New(key, stripe.NewBackends(httpClient))

The way I handle it is like this:

https://github.com/pjebs/optimus-go/blob/master/gae.go
https://github.com/pjebs/optimus-go/blob/master/standalone.go

My way may be a lot easier to implement.

In your code, everytime you refer to a http Client, you instead call: client() from the files above.

There will be no affect to the rest of your code.

More information

https://cloud.google.com/appengine/docs/go/issue-requests
https://cloud.google.com/appengine/docs/go/urlfetch/reference

Playstore VerifyProduct error

Hi.
I'm trying to validate product purchase but it returns "Error 400: Invalid Value, invalid".
Could you explain what I'm doing in wrong way?

apple store response is diffent

My response struct is :

IAPResponse struct {
Receipt struct {
AppItemID string json:"app_item_id"
Bid string json:"bid"
Bvrs string json:"bvrs"
ItemID string json:"item_id"
OriginalPurchaseDate string json:"original_purchase_date"
OriginalPurchaseDateMs string json:"original_purchase_date_ms"
OriginalPurchaseDatePst string json:"original_purchase_date_pst"
OriginalTransactionID string json:"original_transaction_id"
ProductID string json:"product_id"
PurchaseDate string json:"purchase_date"
PurchaseDateMs string json:"purchase_date_ms"
PurchaseDatePst string json:"purchase_date_pst"
Quantity string json:"quantity"
TransactionID string json:"transaction_id"
UniqueIdentifier string json:"unique_identifier"
UniqueVendorIdentifier string json:"unique_vendor_identifier"
VersionExternalIdentifier string json:"version_external_identifier"
} json:"receipt"
Status int json:"status"
}

Thank you for this nice & compact library.

Thank you for this nice & compact library.

We're considering using this in our company.

I wanted to check if you have considered adding Roku support and if so, will you be willing to accept a PR if I send you one?

Don't add undocumented fields to appstore.Receipt struct

Some fields of appstore.Receipt are not mentioned in the Apple IAP Doc, such as ReceiptType, AdamID and AppItemID. Although they are appear in the response, using them can be a risk. Because they are not promised by Apple, things would be changed in the future.

So that I suggest that they should be removed to avoid misuse.

How to encode ios receipt through base64?

Per doc, the ios receipt should be encoded by base64

req := appstore.IAPRequest{
	ReceiptData: "your receipt data encoded by base64",
}

Then I try it through

 base64.StdEncoding.EncodeToString([]byte(receipt))

and the value of receipt like

 "{\n\t\"signature\" = \"ZwXG56AezlHRTBhL8cTqA==\";\n\t\"purchase-info\" = \"RXRjL0dNVCI7Cn0=\";\n\t\"environment\" = \"Sandbox\";\n\t\"pod\" = \"100\";\n\t\"signing-status\" = \"0\";\n}"

However, I got the status of response is 21002, which is The data in the receipt-data property was malformed or missing

How to encode ios receipt by base64 or is there anything I am missing?

How to pass receipt in ios?

I want to do method in API to purchase products. How to do it? How to pass receipt from API? What does the recipe consist of?

package main

import (
  "github.com/awa/go-iap/appstore"
)

func main() {
  r := mux.NewRouter()
  r.Handle("/iaptest", IAPTest).Methods("GET")
  fmt.Println("Server is runned on port 3000")
  if err := http.ListenAndServe(":3000", handlers.LoggingHandler(os.Stdout, r)); err != nil {
	  log.Fatal(err)
  }
}
var IAPTest = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  client := appstore.New()
  req := appstore.IAPRequest{
	  ReceiptData: "your receipt data encoded by base64",
  }
  resp := &appstore.IAPResponse{}
  ctx := context.Background()
  err := client.Verify(ctx, req, resp)
})

Missing notification type const DID_CHANGE_RENEWAL_STATUS

There is new notification status that Apple started sending, which is not in their official documentation (https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Subscriptions.html), but is mentioned in this article: https://developer.apple.com/documentation/storekit/in-app_purchase/enabling_status_update_notifications

I also started receiving this notification type recently so it's legit.

Apple Api verifyReceipt return last_receipt_info as object instead of array, some time

I run the test for a lot of receipts in prod env and see that the field last_receipt_info is is both array and map. Some receipt apple return array, some else return object. I tested with the receipt the same app and the same subscription. I check on the documentation here https://developer.apple.com/documentation/appstorereceipts/responsebody and see they said that last_receipt_info is an array, but it is not sometimes.

How to cover this case.

Failed to parse iOS subscription test receipt?

When I try to verify subscription test receipt on iOS, I got the following error,

cannot unmarshal object into Go struct field IAPResponse.latest_receipt_info of type []appstore.InApp

Then I define another testResponse

IAPTestResponse struct {
	Status             int                  `json:"status"`
	Environment        Environment          `json:"environment"`
	Receipt            Receipt              `json:"receipt"`
	LatestReceiptInfo  InApp                `json:"latest_receipt_info"`
	LatestReceipt      string               `json:"latest_receipt"`
	PendingRenewalInfo []PendingRenewalInfo `json:"pending_renewal_info"`
	IsRetryable        bool                 `json:"is-retryable"`
}

which is used to json.Unmarshal, it seems work well now.

Anything I am missing?

Failed to go get ./... on TravisCI

go get ./...
# golang.org/x/net/context/ctxhttp
../../../golang.org/x/net/context/ctxhttp/ctxhttp.go:35: req.Cancel undefined (type *http.Request has no field or method Cancel)
make: *** [setup] Error 2

Error 401, permissiondenied

This works:

        key, err := ioutil.ReadFile("key.json")
	c(err, true) // check error
	conf, err := google.JWTConfigFromJSON(key, androidpublisher.AndroidpublisherScope)
	c(err, true) // check error...
	cli := conf.Client(context.Background())
	service, err := androidpublisher.New(cli)
	c(err, true)
	inapps := androidpublisher.NewInappproductsService(service)
	iplc := inapps.List(packageName)
	resp, err := iplc.Context(context.Background()).Do()
	c(err, true)
	return resp.Inappproduct

The same API library (publisher v2 or v3), checking purchase status not works:

        key, err := ioutil.ReadFile("key.json")
	c(err, true) //check error

	ctx := context.WithValue(context.Background(), oauth2.HTTPClient, &http.Client{Timeout: 10 * time.Second})
	conf, err := google.JWTConfigFromJSON(key, androidpublisher.AndroidpublisherScope)
	c(err, true)
	client := conf.Client(ctx)
	sr, err := androidpublisher.New(client)
	c(err, true)
	pr := androidpublisher.NewPurchasesProductsService(sr)
	pe, err := pr.Get(packageName, "sku", "purchase token (android sended to my server)").Context(ctx).Do()
	if err != nil {
		fmt.Println("Error:", err)
	}

Output:
Error: googleapi: Error 401: The current user has insufficient permissions to perform the requested operation., permissionDenied

Apple receipt field app_item_id type mismatch

As stated here Apple Receipt Fields "app_item_id" field should be a string but in the library it is mapped to int64. This causes an error during json decoding.

EDIT:
Apparently Apple is giving out different responses some has app_item_id as string and some has it as a number. In this case a custom type that implements Unmarshaler interface would be better suited for this. Something like the following:

	Receipt struct {
		ReceiptType                string        `json:"receipt_type"`
		AdamID                     int64         `json:"adam_id"`
		AppItemID                  NumericString `json:"app_item_id"`
		BundleID                   string        `json:"bundle_id"`
		ApplicationVersion         string        `json:"application_version"`
		DownloadID                 int64         `json:"download_id"`
		OriginalApplicationVersion string        `json:"original_application_version"`
		InApp                      []InApp       `json:"in_app"`
		RequestDate
		OriginalPurchaseDate
	}

        func (n NumericString) UnmarshalJSON(data []byte) error {
	        n = NumericString(string(data))
	        return nil
        }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.