@onesub/server 0.21.2 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `POST /onesub/webhook/google` is mounted only for deployments that serve
3
+ * Google Play.
4
+ *
5
+ * Why it is conditional at all: unlike Apple's route, it does not authenticate
6
+ * unconditionally — the Pub/Sub OIDC token is verified only when an app declares
7
+ * a `pushAudience` — and its voided-purchase branch needs no Google credentials
8
+ * to run. It cancels a subscription by `purchaseToken`, or deletes a purchase row
9
+ * by `orderId`, straight from the payload. So an Apple-only deployment used to
10
+ * expose an unauthenticated endpoint that could revoke entitlement, with no
11
+ * Google purchases for it to be about.
12
+ *
13
+ * Apple's route stays unconditional, and this file asserts that too: it verifies
14
+ * the `signedPayload` JWS against the bundled Apple roots on every request
15
+ * regardless of config, so it is not open in the same way.
16
+ */
17
+ export {};
18
+ //# sourceMappingURL=webhook-google-mount.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-google-mount.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/webhook-google-mount.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
package/dist/index.cjs CHANGED
@@ -1751,18 +1751,22 @@ var GOOGLE_FAILURE_MESSAGES = {
1751
1751
  message: "Failed to process notification"
1752
1752
  }
1753
1753
  };
1754
+ function servesGoogle(config) {
1755
+ return getAppRegistry(config).apps.some((app) => !!app.google);
1756
+ }
1754
1757
  function warnIfGoogleWebhookOpen(config) {
1755
1758
  if (process.env["NODE_ENV"] !== "production") return;
1759
+ if (!servesGoogle(config)) return;
1756
1760
  const apps = getAppRegistry(config).apps;
1757
1761
  const googleApps = apps.map((a) => a.google).filter((g) => !!g);
1758
- if (googleApps.length > 0 && !googleApps.some((g) => g.pushAudience)) {
1762
+ if (!googleApps.some((g) => g.pushAudience)) {
1759
1763
  log.warn(
1760
1764
  "[onesub] SECURITY: POST /onesub/webhook/google accepts unauthenticated requests \u2014 no configured app sets google.pushAudience, so the Pub/Sub OIDC token is never verified. A caller who knows a purchaseToken or orderId can cancel a subscription or delete a one-time purchase. Set google.pushAudience (and google.pushServiceAccountEmail)."
1761
1765
  );
1762
1766
  }
1763
1767
  if (!apps.some((a) => a.google?.packageName)) {
1764
1768
  log.warn(
1765
- "[onesub] POST /onesub/webhook/google is in open mode \u2014 no configured app declares google.packageName, so notifications for ANY package are accepted. The route is mounted whether or not Google is configured; set google.packageName, or block the path at your proxy if this deployment does not serve Google Play."
1769
+ "[onesub] POST /onesub/webhook/google is in open mode \u2014 no configured app declares google.packageName, so notifications for ANY package are accepted. Set google.packageName on each app you serve."
1766
1770
  );
1767
1771
  }
1768
1772
  }
@@ -1981,10 +1985,12 @@ function createWebhookRouter(config, store, purchaseStore, webhookEventStore, we
1981
1985
  shared.ROUTES.WEBHOOK_APPLE,
1982
1986
  (req, res) => handleAppleWebhook(req, res, config, store, purchaseStore, webhookEventStore, webhookQueue)
1983
1987
  );
1984
- router.post(
1985
- shared.ROUTES.WEBHOOK_GOOGLE,
1986
- (req, res) => handleGoogleWebhook(req, res, config, store, purchaseStore, webhookEventStore, webhookQueue)
1987
- );
1988
+ if (servesGoogle(config)) {
1989
+ router.post(
1990
+ shared.ROUTES.WEBHOOK_GOOGLE,
1991
+ (req, res) => handleGoogleWebhook(req, res, config, store, purchaseStore, webhookEventStore, webhookQueue)
1992
+ );
1993
+ }
1988
1994
  return router;
1989
1995
  }
1990
1996
  var NO_PURCHASE = { valid: false, purchase: null };