Documentation
¶
Overview ¶
Package iap holds the Apple and Google in-app-purchase verifiers. They live outside the cashier package so their heavier crypto and HTTP dependencies do not weigh on callers who only use card gateways.
Index ¶
- Constants
- func Metered(v contracts.IAPVerifier, m Meter) contracts.IAPVerifier
- type AppleConfig
- type AppleServerAPI
- type AppleServerAPIConfig
- type AppleVerifier
- type CloudMeter
- type CloudMeterConfig
- type Decision
- type GoogleConfig
- type GoogleVerifier
- func (g *GoogleVerifier) Acknowledge(ctx context.Context, productID, token string, subscription bool) error
- func (g *GoogleVerifier) ParseNotification(payload []byte) (*contracts.StoreNotification, error)
- func (g *GoogleVerifier) Platform() contracts.IAPPlatform
- func (g *GoogleVerifier) VerifyReceipt(ctx context.Context, p contracts.ReceiptParams) (*contracts.IAPEntitlement, error)
- type LocalMeter
- type Meter
- type MeteredTransaction
Constants ¶
const ( // FreeTierMicros is the tracked transaction volume that is free, in micros // (2000 * 1_000_000). Past this, transactions are billable. FreeTierMicros int64 = 2000 * 1_000_000 // FeeRatePerMille is the fee beyond the free tier, in parts per thousand: // 10‰ = 1%. FeeRatePerMille int64 = 10 )
const AppleRootCAG3PEM = `` /* 847-byte string literal not displayed */
AppleRootCAG3PEM is Apple Root CA - G3, the root every StoreKit 2 JWS and App Store Server Notification V2 chains to. Pass it as AppleConfig's RootCertsPEM.
Source: https://www.apple.com/certificateauthority/AppleRootCA-G3.cer SHA-256: 63:34:3A:BF:B8:9A:6A:03:EB:B5:7E:9B:3F:5F:A7:BE:7C:4F:5C:75:6F:30:17:B3:A8:C4:88:C3:65:3E:91:79 Valid until 30 Apr 2039.
Variables ¶
This section is empty.
Functions ¶
func Metered ¶
func Metered(v contracts.IAPVerifier, m Meter) contracts.IAPVerifier
Metered wraps a verifier so its entitlements are gated by a meter. Registering the result with IAPManager is what turns a raw verifier into the paid feature.
Types ¶
type AppleConfig ¶
type AppleConfig struct {
BundleID string
AllowSandbox bool
// RootCertsPEM is Apple's root certificate(s) in PEM. Required: without a
// pinned root there is nothing to anchor the chain to. AppleRootCAG3PEM is
// the one Apple uses.
RootCertsPEM []byte
}
AppleConfig configures the Apple verifier.
type AppleServerAPI ¶ added in v1.9.0
type AppleServerAPI struct {
// contains filtered or unexported fields
}
AppleServerAPI reads subscription state from Apple.
func NewAppleServerAPI ¶ added in v1.9.0
func NewAppleServerAPI(cfg AppleServerAPIConfig) (*AppleServerAPI, error)
NewAppleServerAPI builds the client.
func (*AppleServerAPI) SubscriptionStatus ¶ added in v1.9.0
func (a *AppleServerAPI) SubscriptionStatus(ctx context.Context, originalTransactionID string) (*contracts.IAPEntitlement, error)
SubscriptionStatus returns the current state of the subscription that originalTransactionID started, trying production first and then sandbox (Apple answers 404 on the wrong environment).
type AppleServerAPIConfig ¶ added in v1.9.0
type AppleServerAPIConfig struct {
IssuerID string
KeyID string
// PrivateKeyPEM is the .p8 file's contents.
PrivateKeyPEM []byte
// Verifier checks the signed payloads the API returns (and supplies the
// bundle id).
Verifier *AppleVerifier
// HTTPClient overrides the client; BaseURL and SandboxBaseURL override
// Apple's hosts (tests).
HTTPClient *http.Client
BaseURL string
SandboxBaseURL string
}
AppleServerAPIConfig configures the App Store Server API client.
type AppleVerifier ¶
type AppleVerifier struct {
// contains filtered or unexported fields
}
AppleVerifier verifies StoreKit 2 JWS transactions and V2 notifications.
func NewApple ¶
func NewApple(cfg AppleConfig) (*AppleVerifier, error)
NewApple builds the Apple verifier.
func (*AppleVerifier) ParseNotification ¶
func (a *AppleVerifier) ParseNotification(payload []byte) (*contracts.StoreNotification, error)
ParseNotification verifies an App Store Server Notification V2 and reduces it to the canonical shape, including the purchase state it vouches for.
func (*AppleVerifier) Platform ¶
func (a *AppleVerifier) Platform() contracts.IAPPlatform
func (*AppleVerifier) VerifyReceipt ¶
func (a *AppleVerifier) VerifyReceipt(ctx context.Context, p contracts.ReceiptParams) (*contracts.IAPEntitlement, error)
VerifyReceipt verifies a StoreKit 2 signed transaction (and, when the app sends it, the signed renewal info) and returns the entitlement it proves.
type CloudMeter ¶
type CloudMeter struct {
// contains filtered or unexported fields
}
CloudMeter reports transactions to Nimbus Cloud and enforces its decisions.
func NewCloudMeter ¶
func NewCloudMeter(cfg CloudMeterConfig) (*CloudMeter, error)
NewCloudMeter builds a meter backed by Nimbus Cloud.
func (*CloudMeter) Authorize ¶
func (m *CloudMeter) Authorize(ctx context.Context, t MeteredTransaction) (Decision, error)
Authorize reports a transaction and returns Cloud's decision.
type CloudMeterConfig ¶
type CloudMeterConfig struct {
// APIKey authenticates the developer's Nimbus Cloud account. Required —
// without it there is no account to meter, so the gate fails closed.
APIKey string
// Endpoint overrides the metering URL. Defaults to Nimbus Cloud.
Endpoint string
// HTTPClient overrides the client (tests point it at a mock server).
HTTPClient *http.Client
// FailClosed makes a Cloud outage deny access instead of granting it. Off
// by default; see the failure policy above before turning it on.
FailClosed bool
}
CloudMeterConfig configures the Cloud meter.
type Decision ¶
type Decision struct {
// Allowed is whether the entitlement may be returned to the app.
Allowed bool
// Reason explains a denial, for logs and errors.
Reason string
// TrackedVolumeMicros is the account's cumulative tracked volume after this
// transaction, as the meter understands it.
TrackedVolumeMicros int64
// FeeMicros is what this transaction cost (0 within the free tier).
FeeMicros int64
// OverFreeTier is whether the account has exhausted the free allowance.
OverFreeTier bool
// Reconcile is set when the decision was made locally after a Cloud outage
// and must be re-reported later. The entitlement was still granted.
Reconcile bool
}
Decision is the meter's ruling on a transaction.
type GoogleConfig ¶
type GoogleConfig struct {
// PackageName is the app's package; a purchase is looked up under it.
PackageName string
// ServiceAccountJSON is the Google Cloud service-account key with access to
// the Play Developer API, as downloaded from the console.
ServiceAccountJSON []byte
}
GoogleConfig configures the Google verifier.
type GoogleVerifier ¶
type GoogleVerifier struct {
// contains filtered or unexported fields
}
GoogleVerifier verifies Google Play purchases via the Android Publisher API.
func NewGoogle ¶
func NewGoogle(cfg GoogleConfig) (*GoogleVerifier, error)
NewGoogle builds the Google verifier.
func (*GoogleVerifier) Acknowledge ¶ added in v1.9.0
func (g *GoogleVerifier) Acknowledge(ctx context.Context, productID, token string, subscription bool) error
Acknowledge confirms a purchase to Google. Google refunds and revokes any purchase left unacknowledged for three days, so a server that grants access must acknowledge it. Acknowledging an acknowledged purchase is harmless.
func (*GoogleVerifier) ParseNotification ¶
func (g *GoogleVerifier) ParseNotification(payload []byte) (*contracts.StoreNotification, error)
ParseNotification decodes a Real-time Developer Notification.
Google's RTDNs are not signed the way Apple's are — authenticity comes from the Pub/Sub push being authenticated at the transport, not from a signature in the body — so this decodes and canonicalises rather than verifying a signature. The entitlement itself must still be confirmed by calling VerifyReceipt with the token inside, which is why a forged notification can at worst make the server re-read the truth from Google.
func (*GoogleVerifier) Platform ¶
func (g *GoogleVerifier) Platform() contracts.IAPPlatform
func (*GoogleVerifier) VerifyReceipt ¶
func (g *GoogleVerifier) VerifyReceipt(ctx context.Context, p contracts.ReceiptParams) (*contracts.IAPEntitlement, error)
VerifyReceipt looks a purchase up against the Android Publisher API.
The purchase token is the stable identity of a Google purchase — every renewal keeps it, and every notification names it — so it is returned as OriginalTransactionID; the order id of the latest charge is TransactionID.
type LocalMeter ¶
type LocalMeter struct {
// contains filtered or unexported fields
}
LocalMeter is a process-local Meter: it applies the exact tier and fee rules without a network call. It is the default for development and the reference the Cloud meter is tested against, and it always allows — enforcement of an unpaid account is Nimbus Cloud's job, not a local cache's.
func NewLocalMeter ¶
func NewLocalMeter() *LocalMeter
NewLocalMeter builds an in-memory meter for one tenant.
func (*LocalMeter) Authorize ¶
func (m *LocalMeter) Authorize(_ context.Context, t MeteredTransaction) (Decision, error)
Authorize records the transaction locally and computes its fee.
func (*LocalMeter) TrackedVolume ¶
func (m *LocalMeter) TrackedVolume() int64
TrackedVolume returns the tenant's accumulated volume, for tests and reports.
type Meter ¶
type Meter interface {
// Authorize records a transaction and rules on whether its entitlement may
// be granted. It must fail open on transient errors (see the package note).
Authorize(ctx context.Context, t MeteredTransaction) (Decision, error)
}
Meter authorises and records IAP transactions for billing.
type MeteredTransaction ¶
type MeteredTransaction struct {
Platform contracts.IAPPlatform
TransactionID string
ProductID string
Subject string
PriceMicros int64
Currency string
Environment string // "sandbox" transactions are never metered
}
MeteredTransaction is one verified purchase reported for metering.
func (MeteredTransaction) Billable ¶
func (t MeteredTransaction) Billable() bool
Billable reports whether a transaction counts toward volume and fees at all. A sandbox purchase or a zero-price event never does.