mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-05 18:49:03 +00:00
docs: shorten the store receipt rules in the badge service protocol
This commit is contained in:
@@ -35,7 +35,7 @@ The client never states what is signed. The tier is that of whatever funded the
|
||||
- `purchaseBadge` → `badgeCredential` — verifies the funding (`apple` JWS offline; `google` product id and token via the Publisher API; `invoice` against webhook-confirmed settlement, `payment_pending` until it lands; `receipt`), records the credit, and issues the first credential, in one round trip. It carries `masterKey` and no `badgeRequest`. The response `receipt` is the recovery bearer secret (model § recovery); the service stores its hash; lifetime badges receive none.
|
||||
- A store transaction is claimed by its own id, read from the evidence before verification, and credited only when the verified transaction carries that same id. A receipt already credited to the signing key is answered from the record, without asking the store.
|
||||
- Errors: `receipt_invalid`, `payment_pending`, `provider_unavailable` — see the classes below; `receipt_used` when another key was credited with it; `product_unavailable` for a product this service does not price; `provider_not_configured` when this deployment has no verifier for the store, terminal for the request since retrying cannot deploy one. `receipt_invalid` and `receipt_used` are the only answers on which the client drops the keys it signed with and finishes the store transaction. Every other answer records nothing and leaves the purchase with its keys, to be presented again at the next trigger.
|
||||
- **What a verifier may answer.** On `receipt_invalid` the client deletes its keys and finishes the store transaction — consumed on Play, finished on StoreKit — so a mistaken `receipt_invalid` loses the buyer's money for good. The opposite mistake costs one request per client trigger, and Play refunds a purchase unacknowledged for three days. So an answer that is not certainly terminal is unreachable.
|
||||
- **Which class an answer belongs to.** The two mistakes do not cost the same, so when it is not certain, answer unreachable. `receipt_invalid` tells the client the purchase is dead: it drops the keys it signed with and finishes the store transaction — consumed on Play, finished on StoreKit — and nothing can present it again, so a buyer answered this by mistake has paid for a badge they can never receive. Answering unreachable by mistake costs one more verification request each time the app presents the purchase again, and a Play purchase left unacknowledged for three days is refunded to the buyer.
|
||||
- **Terminal**, `receipt_invalid` — the store answered about this purchase and cannot change its mind: an Apple signature or certificate chain that does not verify, another app's bundle id, a test purchase (Apple Sandbox, Play `purchaseType` test), a refunded or revoked purchase, Play `purchaseState` canceled.
|
||||
- **Pending**, `payment_pending` — Play `purchaseState` pending.
|
||||
- **Unreachable**, `provider_unavailable` — the store was not asked or did not answer: network, timeout, 5xx, quota, this service's own auth or permission failures, and every Play error response, a 404 from `purchases.products.get` or `purchases.subscriptionsv2.get` and a 400 or 410 calling the token invalid included. Only a purchase record Play returns is a verdict: Play may not yet know a token it has just issued, and nothing tells that apart from one it never issued. A token outside the characters this service will send is not sent, and lands here too, since Play documents no token grammar and our check is not Play's verdict. A product id outside the characters Play does document is terminal, since no product of this app can have one.
|
||||
|
||||
Reference in New Issue
Block a user