payment-kit 1.29.1 → 1.29.3
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.
- package/api/dev.ts +41 -2
- package/api/hono.d.ts +42 -0
- package/api/node-sqlite.d.ts +12 -0
- package/api/src/bootstrap.ts +47 -0
- package/api/src/crons/base.ts +3 -3
- package/api/src/crons/currency.ts +1 -1
- package/api/src/crons/index.ts +41 -37
- package/api/src/crons/metering-subscription-detection.ts +1 -1
- package/api/src/crons/overdue-detection.ts +2 -2
- package/api/src/crons/retry-pending-events.ts +6 -0
- package/api/src/crons/tenant-fanout.ts +82 -0
- package/api/src/host-node/did-connect-runtime-node.ts +33 -0
- package/api/src/host-node/serve-static-arc.ts +68 -0
- package/api/src/host-node/serve-static.ts +41 -0
- package/api/src/index.ts +22 -161
- package/api/src/integrations/app-store/client.ts +3 -4
- package/api/src/integrations/app-store/handlers/subscription.ts +7 -7
- package/api/src/integrations/app-store/signed-data-verifier.ts +3 -2
- package/api/src/integrations/arcblock/token.ts +21 -7
- package/api/src/integrations/google-play/handlers/subscription.ts +6 -6
- package/api/src/integrations/google-play/handlers/voided.ts +2 -2
- package/api/src/integrations/google-play/verify.ts +3 -2
- package/api/src/integrations/iap-reconcile.ts +3 -5
- package/api/src/integrations/stripe/handlers/invoice.ts +2 -2
- package/api/src/integrations/stripe/handlers/subscription.ts +3 -3
- package/api/src/libs/archive/query.ts +19 -0
- package/api/src/libs/audit.ts +61 -4
- package/api/src/libs/auth.ts +247 -47
- package/api/src/libs/context.ts +89 -1
- package/api/src/libs/currency.ts +2 -2
- package/api/src/libs/dayjs.ts +8 -2
- package/api/src/libs/did-connect/runtime-did-connect-js.ts +88 -0
- package/api/src/libs/did-connect/tenant-identity.ts +221 -0
- package/api/src/libs/drivers/auth-storage.ts +118 -0
- package/api/src/libs/drivers/cron.ts +264 -0
- package/api/src/libs/drivers/db.ts +170 -0
- package/api/src/libs/drivers/identity.ts +142 -0
- package/api/src/libs/drivers/index.ts +40 -0
- package/api/src/libs/drivers/locks.ts +226 -0
- package/api/src/libs/drivers/migrate-runner.ts +70 -0
- package/api/src/libs/drivers/queue.ts +104 -0
- package/api/src/libs/drivers/secrets.ts +194 -0
- package/api/src/libs/env.ts +170 -54
- package/api/src/libs/exchange-rate/service.ts +7 -6
- package/api/src/libs/http-fetch-adapter.ts +60 -0
- package/api/src/libs/invoice.ts +1 -1
- package/api/src/libs/lock.ts +51 -47
- package/api/src/libs/logger.ts +48 -8
- package/api/src/libs/notification/index.ts +1 -1
- package/api/src/libs/notification/template/customer-credit-low-balance.ts +2 -1
- package/api/src/libs/notification/template/customer-revenue-succeeded.ts +1 -1
- package/api/src/libs/notification/template/customer-reward-succeeded.ts +1 -1
- package/api/src/libs/overdraft-protection.ts +1 -1
- package/api/src/libs/payout.ts +1 -1
- package/api/src/libs/queue/index.ts +271 -52
- package/api/src/libs/queue/runtime.ts +175 -0
- package/api/src/libs/resource.ts +3 -3
- package/api/src/libs/secrets.ts +38 -0
- package/api/src/libs/session.ts +3 -2
- package/api/src/libs/subscription.ts +5 -5
- package/api/src/libs/tenant.ts +92 -0
- package/api/src/libs/url.ts +3 -3
- package/api/src/libs/util.ts +21 -13
- package/api/src/middlewares/hono/cdn.ts +63 -0
- package/api/src/middlewares/hono/context.ts +80 -0
- package/api/src/middlewares/hono/csrf.ts +83 -0
- package/api/src/middlewares/hono/fallback.ts +194 -0
- package/api/src/middlewares/hono/pipeline.ts +73 -0
- package/api/src/middlewares/hono/resource-mount.ts +42 -0
- package/api/src/middlewares/hono/resource.ts +63 -0
- package/api/src/middlewares/hono/security.ts +209 -0
- package/api/src/middlewares/hono/session.ts +114 -0
- package/api/src/middlewares/hono/xss.ts +61 -0
- package/api/src/queues/auto-recharge.ts +12 -10
- package/api/src/queues/checkout-session.ts +38 -21
- package/api/src/queues/credit-consume.ts +40 -36
- package/api/src/queues/credit-grant.ts +25 -18
- package/api/src/queues/credit-reconciliation.ts +7 -5
- package/api/src/queues/discount-status.ts +9 -6
- package/api/src/queues/event.ts +41 -11
- package/api/src/queues/exchange-rate-health.ts +49 -30
- package/api/src/queues/invoice.ts +18 -15
- package/api/src/queues/notification.ts +14 -7
- package/api/src/queues/payment.ts +64 -37
- package/api/src/queues/payout.ts +37 -21
- package/api/src/queues/refund.ts +36 -18
- package/api/src/queues/subscription.ts +83 -53
- package/api/src/queues/token-transfer.ts +15 -10
- package/api/src/queues/usage-record.ts +8 -5
- package/api/src/queues/vendors/commission.ts +7 -5
- package/api/src/queues/vendors/fulfillment-coordinator.ts +17 -13
- package/api/src/queues/vendors/fulfillment.ts +4 -2
- package/api/src/queues/vendors/return-processor.ts +5 -3
- package/api/src/queues/vendors/return-scanner.ts +5 -4
- package/api/src/queues/vendors/status-check.ts +10 -7
- package/api/src/queues/webhook.ts +60 -32
- package/api/src/routes/connect/shared.ts +1 -2
- package/api/src/routes/connect/subscribe.ts +3 -3
- package/api/src/routes/{archive.ts → hono/archive.ts} +69 -64
- package/api/src/routes/{auto-recharge-configs.ts → hono/auto-recharge-configs.ts} +39 -28
- package/api/src/routes/{checkout-sessions.ts → hono/checkout-sessions.ts} +790 -923
- package/api/src/routes/{coupons.ts → hono/coupons.ts} +93 -76
- package/api/src/routes/{credit-grants.ts → hono/credit-grants.ts} +140 -126
- package/api/src/routes/hono/credit-tokens.ts +43 -0
- package/api/src/routes/{credit-transactions.ts → hono/credit-transactions.ts} +37 -29
- package/api/src/routes/{customers.ts → hono/customers.ts} +199 -224
- package/api/src/routes/{donations.ts → hono/donations.ts} +41 -32
- package/api/src/routes/{entitlements.ts → hono/entitlements.ts} +28 -25
- package/api/src/routes/{events.ts → hono/events.ts} +107 -71
- package/api/src/routes/{exchange-rate-providers.ts → hono/exchange-rate-providers.ts} +138 -126
- package/api/src/routes/hono/exchange-rates.ts +77 -0
- package/api/src/routes/hono/index.ts +115 -0
- package/api/src/routes/{integrations → hono/integrations}/app-store.ts +68 -48
- package/api/src/routes/{integrations → hono/integrations}/google-play.ts +78 -58
- package/api/src/routes/hono/integrations/stripe.ts +74 -0
- package/api/src/routes/{invoices.ts → hono/invoices.ts} +253 -244
- package/api/src/routes/{meter-events.ts → hono/meter-events.ts} +120 -110
- package/api/src/routes/hono/meters.ts +288 -0
- package/api/src/routes/hono/passports.ts +73 -0
- package/api/src/routes/{payment-currencies.ts → hono/payment-currencies.ts} +219 -197
- package/api/src/routes/{payment-intents.ts → hono/payment-intents.ts} +136 -132
- package/api/src/routes/{payment-links.ts → hono/payment-links.ts} +145 -128
- package/api/src/routes/{payment-methods.ts → hono/payment-methods.ts} +125 -93
- package/api/src/routes/{payment-stats.ts → hono/payment-stats.ts} +30 -25
- package/api/src/routes/{payouts.ts → hono/payouts.ts} +55 -47
- package/api/src/routes/{prices.ts → hono/prices.ts} +265 -242
- package/api/src/routes/{pricing-table.ts → hono/pricing-table.ts} +94 -87
- package/api/src/routes/{products.ts → hono/products.ts} +172 -159
- package/api/src/routes/{promotion-codes.ts → hono/promotion-codes.ts} +207 -185
- package/api/src/routes/hono/redirect.ts +24 -0
- package/api/src/routes/{refunds.ts → hono/refunds.ts} +98 -83
- package/api/src/routes/{settings.ts → hono/settings.ts} +64 -55
- package/api/src/routes/{subscription-items.ts → hono/subscription-items.ts} +64 -57
- package/api/src/routes/{subscriptions.ts → hono/subscriptions.ts} +475 -528
- package/api/src/routes/{tax-rates.ts → hono/tax-rates.ts} +71 -70
- package/api/src/routes/hono/tool.ts +69 -0
- package/api/src/routes/{usage-records.ts → hono/usage-records.ts} +47 -42
- package/api/src/routes/{vendor.ts → hono/vendor.ts} +315 -167
- package/api/src/routes/{webhook-attempts.ts → hono/webhook-attempts.ts} +17 -13
- package/api/src/routes/hono/webhook-endpoints.ts +126 -0
- package/api/src/service.ts +814 -0
- package/api/src/store/migrations/20230911-seeding.ts +2 -1
- package/api/src/store/migrations/20260609-remove-did-space-jobs.ts +23 -0
- package/api/src/store/migrations/20260610-tenant-columns.ts +40 -0
- package/api/src/store/migrations/20260611-tenant-backfill.ts +33 -0
- package/api/src/store/models/auto-recharge-config.ts +22 -10
- package/api/src/store/models/checkout-session.ts +15 -14
- package/api/src/store/models/coupon.ts +29 -20
- package/api/src/store/models/credit-grant.ts +38 -29
- package/api/src/store/models/credit-transaction.ts +32 -21
- package/api/src/store/models/customer.ts +19 -17
- package/api/src/store/models/discount.ts +11 -2
- package/api/src/store/models/entitlement-grant.ts +21 -9
- package/api/src/store/models/entitlement-product.ts +21 -9
- package/api/src/store/models/entitlement.ts +19 -10
- package/api/src/store/models/event.ts +18 -9
- package/api/src/store/models/exchange-rate-provider.ts +17 -4
- package/api/src/store/models/invoice-item.ts +18 -9
- package/api/src/store/models/invoice.ts +16 -8
- package/api/src/store/models/meter-event.ts +27 -9
- package/api/src/store/models/meter.ts +31 -22
- package/api/src/store/models/payment-currency.ts +25 -8
- package/api/src/store/models/payment-intent.ts +15 -6
- package/api/src/store/models/payment-link.ts +15 -6
- package/api/src/store/models/payment-method.ts +38 -22
- package/api/src/store/models/payment-stat.ts +18 -9
- package/api/src/store/models/payout.ts +15 -6
- package/api/src/store/models/price-quote.ts +17 -8
- package/api/src/store/models/price.ts +24 -12
- package/api/src/store/models/pricing-table.ts +29 -20
- package/api/src/store/models/product-vendor.ts +20 -10
- package/api/src/store/models/product.ts +15 -6
- package/api/src/store/models/promotion-code.ts +14 -6
- package/api/src/store/models/refund.ts +15 -6
- package/api/src/store/models/revenue-snapshot.ts +21 -9
- package/api/src/store/models/setting.ts +18 -9
- package/api/src/store/models/setup-intent.ts +36 -27
- package/api/src/store/models/subscription-item.ts +21 -9
- package/api/src/store/models/subscription-schedule.ts +21 -9
- package/api/src/store/models/subscription.ts +21 -10
- package/api/src/store/models/tax-rate.ts +29 -21
- package/api/src/store/models/usage-record.ts +11 -2
- package/api/src/store/models/webhook-attempt.ts +18 -9
- package/api/src/store/models/webhook-endpoint.ts +18 -9
- package/api/src/store/scoped-core.ts +55 -0
- package/api/src/store/scoped.ts +247 -0
- package/api/src/store/sequelize.ts +82 -23
- package/api/src/store/sql-migrations.ts +20 -0
- package/api/src/store/tenant-backfill.ts +260 -0
- package/api/src/store/tenant-model.ts +124 -0
- package/api/src/store/tenant-tables.ts +50 -0
- package/api/tests/bootstrap/bootstrap.spec.ts +162 -0
- package/api/tests/crons/tenant-fanout.spec.ts +158 -0
- package/api/tests/embedded/embedded-multi-mode-d3.spec.ts +257 -0
- package/api/tests/fixtures/bare-query-violation.ts +13 -0
- package/api/tests/fixtures/core-env-violation.ts +10 -0
- package/api/tests/fixtures/host-read-violation.ts +19 -0
- package/api/tests/fixtures/tenants.ts +4 -0
- package/api/tests/integrations/iap-tenant.spec.ts +284 -0
- package/api/tests/libs/archive-query.spec.ts +26 -0
- package/api/tests/libs/audit-tenant.spec.ts +153 -0
- package/api/tests/libs/context.spec.ts +204 -0
- package/api/tests/libs/core-config.spec.ts +115 -0
- package/api/tests/libs/cron-driver-d2.spec.ts +237 -0
- package/api/tests/libs/crons-conservation-d2.spec.ts +52 -0
- package/api/tests/libs/did-connect-runtime-js.spec.ts +98 -0
- package/api/tests/libs/did-connect-tenant-identity.spec.ts +159 -0
- package/api/tests/libs/lock-tenant.spec.ts +66 -0
- package/api/tests/libs/scoped.spec.ts +222 -0
- package/api/tests/libs/secrets-facade.spec.ts +52 -0
- package/api/tests/libs/service-host.spec.ts +37 -0
- package/api/tests/libs/tenancy-slot-authority.spec.ts +209 -0
- package/api/tests/libs/tenant-middleware.spec.ts +42 -0
- package/api/tests/libs/tenant-scanner.spec.ts +120 -0
- package/api/tests/middlewares/hono/cdn.spec.ts +70 -0
- package/api/tests/middlewares/hono/context.spec.ts +113 -0
- package/api/tests/middlewares/hono/csrf.spec.ts +136 -0
- package/api/tests/middlewares/hono/fallback.spec.ts +67 -0
- package/api/tests/middlewares/hono/pipeline.spec.ts +47 -0
- package/api/tests/middlewares/hono/security.spec.ts +181 -0
- package/api/tests/middlewares/hono/session.spec.ts +42 -0
- package/api/tests/middlewares/hono/xss.spec.ts +81 -0
- package/api/tests/models/tenant-backfill.spec.ts +287 -0
- package/api/tests/models/tenant-columns-model.spec.ts +46 -0
- package/api/tests/models/tenant-columns.spec.ts +161 -0
- package/api/tests/queues/credit-consume-batch.spec.ts +8 -1
- package/api/tests/queues/credit-consume.spec.ts +8 -1
- package/api/tests/queues/event-tenant.spec.ts +292 -0
- package/api/tests/queues/exchange-rate-health-tenant-d6.spec.ts +62 -0
- package/api/tests/queues/queue-parity.spec.ts +249 -0
- package/api/tests/queues/queue-runtime-surface.spec.ts +277 -0
- package/api/tests/queues/queue-teardown-d2.spec.ts +127 -0
- package/api/tests/queues/tenant-matrix-a.spec.ts +245 -0
- package/api/tests/queues/tenant-matrix-b.spec.ts +168 -0
- package/api/tests/routes/connect/hono-attach.spec.ts +107 -0
- package/api/tests/service/collapse.spec.ts +96 -0
- package/api/tests/service/didconnect-storage-slot.spec.ts +60 -0
- package/api/tests/service/fail-closed-http.spec.ts +79 -0
- package/api/tests/service/static-arc-handler.spec.ts +101 -0
- package/api/tests/service/static-externalized.spec.ts +48 -0
- package/api/tests/store/tenant-crosscut.spec.ts +202 -0
- package/api/tests/store/tenant-model-spike.spec.ts +177 -0
- package/api/tests/store/tenant-model.spec.ts +162 -0
- package/api/tests/store/tenant-residual.spec.ts +196 -0
- package/api/third.d.ts +4 -0
- package/blocklet.yml +1 -1
- package/cloudflare/MIGRATION-RUNBOOK.md +3 -8
- package/cloudflare/README.md +34 -27
- package/cloudflare/STAGING-MIGRATION-GUIDE.md +3 -15
- package/cloudflare/build.ts +33 -13
- package/cloudflare/cf-adapter.ts +419 -0
- package/cloudflare/did-connect-runtime.ts +96 -0
- package/cloudflare/did-connect-token-storage.ts +151 -0
- package/cloudflare/esbuild-cf-config.cjs +407 -0
- package/cloudflare/migrations/0006_tenant_columns.sql +46 -0
- package/cloudflare/migrations/0007_tenant_backfill_indexes.sql +65 -0
- package/cloudflare/migrations/0008_schema_parity.sql +16 -0
- package/cloudflare/migrations/0009_remove_did_space_jobs.sql +5 -0
- package/cloudflare/queue-runtime-mode.ts +13 -0
- package/cloudflare/run-build.js +33 -403
- package/cloudflare/scripts/cf-package-import-probe.mjs +90 -0
- package/cloudflare/scripts/didconnect-mock-smoke.mjs +140 -0
- package/cloudflare/shims/blocklet-sdk/asset-host-transformer.ts +20 -0
- package/cloudflare/shims/blocklet-sdk/config.ts +8 -1
- package/cloudflare/shims/blocklet-sdk/login.ts +12 -0
- package/cloudflare/shims/blocklet-sdk/service-api.ts +14 -0
- package/cloudflare/shims/blocklet-sdk/session.ts +4 -2
- package/cloudflare/shims/blocklet-sdk/util-constants.ts +8 -0
- package/cloudflare/shims/blocklet-sdk/wallet-authenticator.ts +16 -1
- package/cloudflare/shims/blocklet-sdk/wallet-handler.ts +18 -3
- package/cloudflare/shims/cron.ts +38 -158
- package/cloudflare/shims/events.ts +124 -0
- package/cloudflare/shims/fastq.ts +15 -1
- package/cloudflare/shims/nedb-storage.ts +16 -8
- package/cloudflare/shims/xss.ts +8 -0
- package/cloudflare/tenant-middleware.ts +36 -0
- package/cloudflare/tests/cf-adapter.spec.ts +244 -0
- package/cloudflare/tests/did-connect-token-storage.spec.ts +105 -0
- package/cloudflare/tests/tenant-middleware.spec.ts +160 -0
- package/cloudflare/tests/worker-handler-gate.spec.ts +69 -0
- package/cloudflare/vite.config.ts +53 -45
- package/cloudflare/worker.ts +261 -448
- package/cloudflare/wrangler.json +0 -6
- package/cloudflare/wrangler.jsonc +0 -6
- package/cloudflare/wrangler.local-e2e.jsonc +25 -0
- package/cloudflare/wrangler.staging.json +0 -6
- package/jest.config.js +3 -1
- package/package.json +33 -38
- package/scripts/bootstrap-inject.ts +166 -0
- package/scripts/core-env-whitelist.json +1 -0
- package/scripts/e2e-12b-runtime.ts +149 -0
- package/scripts/e2e-core-config.ts +125 -0
- package/scripts/e2e-d1-tenancy.ts +116 -0
- package/scripts/e2e-d2-cron-queue.ts +139 -0
- package/scripts/e2e-d3-embedded-multi.ts +171 -0
- package/scripts/e2e-hono-s2.ts +125 -0
- package/scripts/e2e-hono-s3e.ts +135 -0
- package/scripts/e2e-hono-s4.ts +114 -0
- package/scripts/e2e-migration-contract.ts +100 -0
- package/scripts/e2e-s0.ts +61 -0
- package/scripts/e2e-s1.ts +107 -0
- package/scripts/e2e-s2.ts +178 -0
- package/scripts/e2e-s3.ts +110 -0
- package/scripts/e2e-s4.ts +191 -0
- package/scripts/e2e-s5.ts +139 -0
- package/scripts/e2e-s6.ts +127 -0
- package/scripts/e2e-tenant-model.ts +119 -0
- package/scripts/e2e-tenant-worker.ts +199 -0
- package/scripts/gen-sql-migrations.js +46 -0
- package/scripts/phase8-codemod.js +219 -0
- package/scripts/phase9a-env-getters-codemod.js +82 -0
- package/scripts/scan-core-env.js +109 -0
- package/scripts/scan-tenant-queries.js +235 -0
- package/scripts/schema-drift-guard.ts +210 -0
- package/scripts/tenant-scan-whitelist.json +1 -0
- package/src/app.tsx +2 -1
- package/src/env.d.ts +13 -1
- package/src/libs/service-host.ts +13 -0
- package/tsconfig.json +1 -1
- package/vite.arc.config.ts +159 -0
- package/api/src/libs/did-space.ts +0 -235
- package/api/src/libs/middleware.ts +0 -50
- package/api/src/libs/security.ts +0 -192
- package/api/src/queues/space.ts +0 -662
- package/api/src/routes/credit-tokens.ts +0 -38
- package/api/src/routes/exchange-rates.ts +0 -87
- package/api/src/routes/index.ts +0 -142
- package/api/src/routes/integrations/stripe.ts +0 -61
- package/api/src/routes/meters.ts +0 -274
- package/api/src/routes/passports.ts +0 -68
- package/api/src/routes/redirect.ts +0 -20
- package/api/src/routes/tool.ts +0 -65
- package/api/src/routes/webhook-endpoints.ts +0 -126
- package/api/tests/routes/credit-grants.spec.ts +0 -1261
- package/cloudflare/did-connect-auth.ts +0 -527
- package/cloudflare/shims/did-space-js.ts +0 -17
- package/cloudflare/shims/did-space.ts +0 -11
- package/cloudflare/shims/express-compat/index.ts +0 -80
- package/cloudflare/shims/express-compat/types.ts +0 -41
- package/cloudflare/shims/lock.ts +0 -115
- package/cloudflare/shims/queue.ts +0 -611
- package/cloudflare/tests/shims/queue-delayed-persist.spec.ts +0 -87
- package/cloudflare/tests/shims/queue-scheduled.spec.ts +0 -186
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Phase 3 (express→hono) — hono fork of @blocklet/sdk/lib/middlewares/session.js
|
|
2
|
+
// (sessionMiddleware). NOT in the Phase 1 fork set, but used by many resource
|
|
3
|
+
// routes (customers, checkout-sessions, payment-currencies, auto-recharge-configs,
|
|
4
|
+
// …) via `sessionMiddleware({ accessKey: true })`. Unlike authenticate(), this is
|
|
5
|
+
// NOT a gate: it POPULATES c.set('user', …) when a login token OR access key is
|
|
6
|
+
// present and otherwise just calls next() (the downstream handler decides). The
|
|
7
|
+
// token verification (verifyLoginToken / verifyAccessKey / verifyComponentCall /
|
|
8
|
+
// verifySignedToken) + the optional blacklist check are reused verbatim; only the
|
|
9
|
+
// req plumbing becomes a thin hono shim for getTokenFromReq.
|
|
10
|
+
import type { MiddlewareHandler } from 'hono';
|
|
11
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
12
|
+
import { getTokenFromReq } from '@abtnode/util/lib/get-token-from-req';
|
|
13
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
14
|
+
import {
|
|
15
|
+
verifyLoginToken,
|
|
16
|
+
verifyAccessKey,
|
|
17
|
+
verifyComponentCall,
|
|
18
|
+
verifySignedToken,
|
|
19
|
+
} from '@blocklet/sdk/lib/util/verify-session';
|
|
20
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
21
|
+
import { isLoginToken, isAccessKey } from '@blocklet/sdk/lib/util/login';
|
|
22
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
23
|
+
import config from '@blocklet/sdk/lib/config';
|
|
24
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
25
|
+
import serviceApi from '@blocklet/sdk/lib/util/service-api';
|
|
26
|
+
import { isTestEnv } from '../../libs/env';
|
|
27
|
+
|
|
28
|
+
interface SessionOptions {
|
|
29
|
+
loginToken?: boolean;
|
|
30
|
+
componentCall?: boolean;
|
|
31
|
+
signedToken?: string;
|
|
32
|
+
strictMode?: boolean;
|
|
33
|
+
accessKey?: boolean;
|
|
34
|
+
signedTokenKey?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function sessionMiddleware(options: SessionOptions = {}): MiddlewareHandler {
|
|
38
|
+
const {
|
|
39
|
+
loginToken = true,
|
|
40
|
+
componentCall = false,
|
|
41
|
+
signedToken = '',
|
|
42
|
+
strictMode = false,
|
|
43
|
+
accessKey = false,
|
|
44
|
+
signedTokenKey = '__jwt',
|
|
45
|
+
} = options;
|
|
46
|
+
|
|
47
|
+
return async (c, next) => {
|
|
48
|
+
let result: any = null;
|
|
49
|
+
// a thin express-req shim covering exactly what getTokenFromReq /
|
|
50
|
+
// verifyComponentCall read (query / cookie+authorization headers / method / url / body).
|
|
51
|
+
const url = new URL(c.req.url);
|
|
52
|
+
const shimReq: any = {
|
|
53
|
+
query: c.req.query(),
|
|
54
|
+
headers: { cookie: c.req.header('cookie'), authorization: c.req.header('authorization') },
|
|
55
|
+
get: (h: string) => c.req.header(h),
|
|
56
|
+
method: c.req.method,
|
|
57
|
+
originalUrl: url.pathname + url.search,
|
|
58
|
+
body: c.get('sanitizedBody') ?? {},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
if (loginToken || accessKey) {
|
|
63
|
+
const { _duplicate: hasDuplicate, token: loginTokenValue } = await getTokenFromReq(shimReq, {
|
|
64
|
+
cookie: { key: 'login_token' },
|
|
65
|
+
});
|
|
66
|
+
if (hasDuplicate) {
|
|
67
|
+
return c.text('Access token found in multiple locations', 400);
|
|
68
|
+
}
|
|
69
|
+
if (loginTokenValue && typeof loginTokenValue === 'string') {
|
|
70
|
+
if (!isTestEnv()) {
|
|
71
|
+
const blockletSettings = config.getBlockletSettings();
|
|
72
|
+
if (blockletSettings.enableBlacklist) {
|
|
73
|
+
const { data: checkResult } = await serviceApi.post('/api/user/checkToken', { token: loginTokenValue });
|
|
74
|
+
if (!checkResult.valid) {
|
|
75
|
+
if (strictMode) {
|
|
76
|
+
return c.text('Access token is blocked', 401);
|
|
77
|
+
}
|
|
78
|
+
// not strict → treat as unauthenticated and proceed. NOT awaited
|
|
79
|
+
// on purpose: awaiting would pull downstream route errors into this
|
|
80
|
+
// try/catch and wrongly report them as 401 (parity with the express
|
|
81
|
+
// `next(); return;`, which does not await downstream).
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/return-await
|
|
83
|
+
return next();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (isLoginToken(loginTokenValue)) {
|
|
88
|
+
result = await verifyLoginToken({ token: loginTokenValue, strictMode });
|
|
89
|
+
} else if (isAccessKey(loginTokenValue) && accessKey) {
|
|
90
|
+
result = await verifyAccessKey({ token: loginTokenValue, strictMode });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!result && componentCall) {
|
|
96
|
+
result = await verifyComponentCall({ req: shimReq, strictMode });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!result && signedToken) {
|
|
100
|
+
const token = c.req.query(signedTokenKey) || '';
|
|
101
|
+
result = await verifySignedToken({ token, strictMode });
|
|
102
|
+
}
|
|
103
|
+
} catch (err: any) {
|
|
104
|
+
return c.json({ error: err.message }, 401);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (result) {
|
|
108
|
+
c.set('user', result);
|
|
109
|
+
}
|
|
110
|
+
return next();
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export default sessionMiddleware;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Phase 1 (express→hono) — hono fork of @blocklet/xss (cjs/index.js:26).
|
|
2
|
+
//
|
|
3
|
+
// The express version sanitizes body/params/headers/query IN PLACE. hono's
|
|
4
|
+
// Request is immutable and the query/params/headers are never reflected as HTML
|
|
5
|
+
// (pure JSON API → Joi + parameterized Sequelize), so this fork DELIBERATELY
|
|
6
|
+
// NARROWS to body-only sanitization (design §7, decided 2026-06-12). The
|
|
7
|
+
// query/params/headers narrowing is locked by an explicit spec assertion.
|
|
8
|
+
//
|
|
9
|
+
// This middleware is the SINGLE body read-point: it consumes the request body
|
|
10
|
+
// once, sanitizes it, and stores it on c.set('sanitizedBody'). Downstream routes
|
|
11
|
+
// MUST read c.get('sanitizedBody') and NEVER call c.req.json() again — hono's
|
|
12
|
+
// bodyCache holds the UN-sanitized original, so a re-read is a security hole
|
|
13
|
+
// (design §7). The Stripe webhook (raw-body) is mounted so it never passes
|
|
14
|
+
// through this middleware (Phase 3e).
|
|
15
|
+
import type { MiddlewareHandler } from 'hono';
|
|
16
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
17
|
+
import { initSanitize } from '@blocklet/xss';
|
|
18
|
+
|
|
19
|
+
// allowedKeys: [] matches the express call site `xss({ allowedKeys: [] })`.
|
|
20
|
+
const sanitize = initSanitize({ allowedKeys: [] });
|
|
21
|
+
|
|
22
|
+
// Raw-body routes whose bytes must reach the handler unconsumed — the Stripe
|
|
23
|
+
// webhook verifies its HMAC signature over the EXACT received bytes. Parity with
|
|
24
|
+
// the express app shell, which routes this path around the json/body middleware
|
|
25
|
+
// (service.ts buildNodeHandler). The route reads c.req.arrayBuffer() itself.
|
|
26
|
+
const RAW_BODY_PREFIXES = ['/api/integrations/stripe/webhook'];
|
|
27
|
+
|
|
28
|
+
export function xss(): MiddlewareHandler {
|
|
29
|
+
return async (c, next) => {
|
|
30
|
+
if (RAW_BODY_PREFIXES.some((p) => c.req.path.startsWith(p))) {
|
|
31
|
+
c.set('sanitizedBody', undefined);
|
|
32
|
+
return next();
|
|
33
|
+
}
|
|
34
|
+
// Parse the body by CONTENT-TYPE, not method — express's body-parser parses a
|
|
35
|
+
// json/form body on ANY method (including a GET with a body, which a few
|
|
36
|
+
// routes use, e.g. customers GET /:id reading body.create). A request with no
|
|
37
|
+
// parseable content-type yields no sanitizedBody (routes read `?? {}`, matching
|
|
38
|
+
// express.json()'s empty {} ).
|
|
39
|
+
const contentType = c.req.header('content-type') || '';
|
|
40
|
+
let body: unknown;
|
|
41
|
+
if (contentType.includes('application/json')) {
|
|
42
|
+
// single read; empty body → {} to match express.json() (which yields {}),
|
|
43
|
+
// malformed JSON throws (→ app.onError, parity with the express 400 path).
|
|
44
|
+
const raw = await c.req.text();
|
|
45
|
+
body = raw === '' ? {} : JSON.parse(raw);
|
|
46
|
+
} else if (
|
|
47
|
+
contentType.includes('application/x-www-form-urlencoded') ||
|
|
48
|
+
contentType.includes('multipart/form-data')
|
|
49
|
+
) {
|
|
50
|
+
body = await c.req.parseBody();
|
|
51
|
+
} else {
|
|
52
|
+
// no parseable body content-type (or no body) — nothing to sanitize
|
|
53
|
+
body = undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
c.set('sanitizedBody', body === undefined ? undefined : sanitize(body));
|
|
57
|
+
return next();
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default xss;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { BN } from '@ocap/util';
|
|
2
|
-
|
|
3
2
|
import { Op } from 'sequelize';
|
|
4
|
-
import
|
|
3
|
+
import { systemFindByPk, systemFindOne } from '../store/scoped';
|
|
4
|
+
|
|
5
|
+
import createQueue, { assertJobObjectTenant } from '../libs/queue';
|
|
5
6
|
import {
|
|
6
7
|
AutoRechargeConfig,
|
|
7
8
|
ChainType,
|
|
@@ -48,13 +49,14 @@ export async function processAutoRecharge(job: AutoRechargeJobData) {
|
|
|
48
49
|
logger.info('Processing auto recharge job', { job });
|
|
49
50
|
const { customer_id: customerId, currency_id: currencyId } = job;
|
|
50
51
|
|
|
51
|
-
const customer = await Customer
|
|
52
|
+
const customer = await systemFindByPk(Customer, customerId);
|
|
52
53
|
if (!customer) {
|
|
53
54
|
logger.error('Customer not found', { customerId });
|
|
54
55
|
return;
|
|
55
56
|
}
|
|
57
|
+
assertJobObjectTenant(customer);
|
|
56
58
|
|
|
57
|
-
const currency = await PaymentCurrency
|
|
59
|
+
const currency = await systemFindByPk(PaymentCurrency, currencyId);
|
|
58
60
|
if (!currency) {
|
|
59
61
|
logger.error('Currency not found', { currencyId });
|
|
60
62
|
return;
|
|
@@ -63,7 +65,7 @@ export async function processAutoRecharge(job: AutoRechargeJobData) {
|
|
|
63
65
|
// Check if the associated meter is inactive
|
|
64
66
|
if (currency.type === 'credit') {
|
|
65
67
|
// Find meter by currency_id (meter.currency_id -> PaymentCurrency) or by metadata.meter_id
|
|
66
|
-
const meter = await Meter
|
|
68
|
+
const meter = await systemFindOne(Meter, {
|
|
67
69
|
where: { currency_id: currencyId },
|
|
68
70
|
});
|
|
69
71
|
if (meter && meter.status === 'inactive') {
|
|
@@ -77,7 +79,7 @@ export async function processAutoRecharge(job: AutoRechargeJobData) {
|
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
// 1. find auto recharge config
|
|
80
|
-
const config = (await AutoRechargeConfig
|
|
82
|
+
const config = (await systemFindOne(AutoRechargeConfig, {
|
|
81
83
|
where: {
|
|
82
84
|
customer_id: customerId,
|
|
83
85
|
currency_id: currencyId,
|
|
@@ -378,7 +380,7 @@ async function createInvoiceForAutoRecharge({
|
|
|
378
380
|
}
|
|
379
381
|
|
|
380
382
|
// Check for existing invoice
|
|
381
|
-
const existInvoice = await Invoice
|
|
383
|
+
const existInvoice = await systemFindOne(Invoice, {
|
|
382
384
|
where: {
|
|
383
385
|
customer_id: customer.id,
|
|
384
386
|
currency_id: rechargeCurrency.id,
|
|
@@ -633,21 +635,21 @@ export async function checkAndTriggerAutoRecharge(
|
|
|
633
635
|
}
|
|
634
636
|
|
|
635
637
|
// T2b: Reuse caller-provided currency to avoid redundant DB query
|
|
636
|
-
const currency = options?.currency ?? (await PaymentCurrency
|
|
638
|
+
const currency = options?.currency ?? (await systemFindByPk(PaymentCurrency, currencyId));
|
|
637
639
|
|
|
638
640
|
// Reuse caller-provided meter when available to avoid redundant DB query
|
|
639
641
|
let meterPromise: Promise<any>;
|
|
640
642
|
if (options?.meter != null) {
|
|
641
643
|
meterPromise = Promise.resolve(options.meter);
|
|
642
644
|
} else if (currency?.type === 'credit') {
|
|
643
|
-
meterPromise = Meter
|
|
645
|
+
meterPromise = systemFindOne(Meter, { where: { currency_id: currencyId } });
|
|
644
646
|
} else {
|
|
645
647
|
meterPromise = Promise.resolve(null);
|
|
646
648
|
}
|
|
647
649
|
|
|
648
650
|
const [meter, config] = await Promise.all([
|
|
649
651
|
meterPromise,
|
|
650
|
-
AutoRechargeConfig
|
|
652
|
+
systemFindOne(AutoRechargeConfig, {
|
|
651
653
|
where: {
|
|
652
654
|
customer_id: customer.id,
|
|
653
655
|
currency_id: currencyId,
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
2
|
import { Op } from 'sequelize';
|
|
3
|
+
import { systemFindAll, systemFindByPk, systemFindOne } from '../store/scoped';
|
|
3
4
|
|
|
4
5
|
import { mintNftForCheckoutSession } from '../integrations/arcblock/nft';
|
|
5
6
|
import { ensurePassportIssued } from '../integrations/blocklet/passport';
|
|
6
7
|
import { ensureInvoiceForCheckout } from '../routes/connect/shared';
|
|
8
|
+
import { withTenant } from '../libs/context';
|
|
7
9
|
import dayjs from '../libs/dayjs';
|
|
8
10
|
import { events } from '../libs/event';
|
|
9
11
|
import logger from '../libs/logger';
|
|
10
|
-
import createQueue from '../libs/queue';
|
|
12
|
+
import createQueue, { assertJobObjectTenant } from '../libs/queue';
|
|
11
13
|
import {
|
|
12
14
|
CheckoutSession,
|
|
13
15
|
Customer,
|
|
@@ -40,11 +42,12 @@ export const checkoutSessionQueue = createQueue<CheckoutSessionJob>({
|
|
|
40
42
|
});
|
|
41
43
|
|
|
42
44
|
export async function handleCheckoutSessionJob(job: CheckoutSessionJob): Promise<void> {
|
|
43
|
-
const checkoutSession = await CheckoutSession
|
|
45
|
+
const checkoutSession = await systemFindByPk(CheckoutSession, job.id);
|
|
44
46
|
if (!checkoutSession) {
|
|
45
47
|
logger.warn('CheckoutSession not found', { id: job.id });
|
|
46
48
|
return;
|
|
47
49
|
}
|
|
50
|
+
assertJobObjectTenant(checkoutSession);
|
|
48
51
|
if (job.action === 'expire') {
|
|
49
52
|
if (checkoutSession.status !== 'open') {
|
|
50
53
|
logger.info('Skip expire CheckoutSession since status is not open', {
|
|
@@ -80,23 +83,34 @@ export async function handleCheckoutSessionJob(job: CheckoutSessionJob): Promise
|
|
|
80
83
|
export async function startCheckoutSessionQueue() {
|
|
81
84
|
// Auto populate subscription queue
|
|
82
85
|
const now = dayjs().unix();
|
|
83
|
-
const checkoutSessions = await CheckoutSession
|
|
86
|
+
const checkoutSessions = await systemFindAll(CheckoutSession, {
|
|
84
87
|
where: {
|
|
85
88
|
status: 'open',
|
|
86
89
|
expires_at: { [Op.lte]: now },
|
|
87
90
|
},
|
|
88
91
|
});
|
|
89
92
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
// Per-record tenant context: queue push stamps the job tenant via getInstanceDid,
|
|
94
|
+
// which fails closed in multi mode without it. for-of + await (not forEach(async),
|
|
95
|
+
// which leaks an unhandledRejection → FATAL on boot); per-record catch isolates.
|
|
96
|
+
for (const checkoutSession of checkoutSessions) {
|
|
97
|
+
const dispatch = async () => {
|
|
98
|
+
const exist = await checkoutSessionQueue.get(checkoutSession.id);
|
|
99
|
+
if (!exist) {
|
|
100
|
+
checkoutSessionQueue.push({
|
|
101
|
+
id: checkoutSession.id,
|
|
102
|
+
job: { id: checkoutSession.id, action: 'expire' },
|
|
103
|
+
runAt: checkoutSession.expires_at,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
try {
|
|
108
|
+
// eslint-disable-next-line no-await-in-loop
|
|
109
|
+
await (checkoutSession.instance_did ? withTenant(checkoutSession.instance_did, dispatch) : dispatch());
|
|
110
|
+
} catch (error) {
|
|
111
|
+
logger.error('startCheckoutSessionQueue: re-queue failed', { id: checkoutSession.id, error });
|
|
98
112
|
}
|
|
99
|
-
}
|
|
113
|
+
}
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
checkoutSessionQueue.on('failed', ({ id, job, error }) => {
|
|
@@ -146,7 +160,7 @@ events.on('checkout.session.expired', async (checkoutSession: CheckoutSession) =
|
|
|
146
160
|
});
|
|
147
161
|
} else {
|
|
148
162
|
// Do some reverse lookup if invoice is not related to checkout session
|
|
149
|
-
const invoice = await Invoice
|
|
163
|
+
const invoice = await systemFindOne(Invoice, { where: { checkout_session_id: checkoutSession.id } });
|
|
150
164
|
if (invoice) {
|
|
151
165
|
await destroyExistingInvoice(invoice);
|
|
152
166
|
logger.info('Invoice and InvoiceItem for checkout session deleted on expire', {
|
|
@@ -165,10 +179,10 @@ events.on('checkout.session.expired', async (checkoutSession: CheckoutSession) =
|
|
|
165
179
|
}
|
|
166
180
|
|
|
167
181
|
if (checkoutSession.payment_intent_id && checkoutSession.payment_status !== 'paid') {
|
|
168
|
-
const paymentIntent = await PaymentIntent
|
|
182
|
+
const paymentIntent = await systemFindByPk(PaymentIntent, checkoutSession.payment_intent_id);
|
|
169
183
|
const stripePaymentId = paymentIntent?.payment_details?.stripe?.payment_intent_id;
|
|
170
184
|
if (paymentIntent && stripePaymentId) {
|
|
171
|
-
const method = await PaymentMethod
|
|
185
|
+
const method = await systemFindByPk(PaymentMethod, paymentIntent.payment_method_id);
|
|
172
186
|
if (method?.type === 'stripe') {
|
|
173
187
|
const client = method.getStripeClient();
|
|
174
188
|
try {
|
|
@@ -198,12 +212,12 @@ events.on('checkout.session.expired', async (checkoutSession: CheckoutSession) =
|
|
|
198
212
|
|
|
199
213
|
const subscriptionIds = getCheckoutSessionSubscriptionIds(checkoutSession);
|
|
200
214
|
if (subscriptionIds.length > 0) {
|
|
201
|
-
const subscriptions = await Subscription
|
|
215
|
+
const subscriptions = await systemFindAll(Subscription, { where: { id: { [Op.in]: subscriptionIds } } });
|
|
202
216
|
await Promise.all(
|
|
203
217
|
subscriptions.map(async (subscription) => {
|
|
204
218
|
const stripeSubscriptionId = subscription?.payment_details?.stripe?.subscription_id;
|
|
205
219
|
if (subscription && stripeSubscriptionId) {
|
|
206
|
-
const method = await PaymentMethod
|
|
220
|
+
const method = await systemFindByPk(PaymentMethod, subscription.default_payment_method_id);
|
|
207
221
|
if (method?.type === 'stripe') {
|
|
208
222
|
const client = method.getStripeClient();
|
|
209
223
|
try {
|
|
@@ -245,7 +259,7 @@ events.on('checkout.session.expired', async (checkoutSession: CheckoutSession) =
|
|
|
245
259
|
|
|
246
260
|
// update price lock status
|
|
247
261
|
for (const item of checkoutSession.line_items) {
|
|
248
|
-
const price = await Price
|
|
262
|
+
const price = await systemFindByPk(Price, item.price_id);
|
|
249
263
|
if (price?.locked) {
|
|
250
264
|
const used = await price.isUsed(false);
|
|
251
265
|
logger.info('Price used status recheck on expire', {
|
|
@@ -269,11 +283,12 @@ events.on('checkout.session.expired', async (checkoutSession: CheckoutSession) =
|
|
|
269
283
|
events.on(
|
|
270
284
|
'checkout.session.pending_invoice',
|
|
271
285
|
async ({ checkoutSessionId, paymentIntentId }: { checkoutSessionId: string; paymentIntentId: string }) => {
|
|
272
|
-
const checkoutSession = await CheckoutSession
|
|
286
|
+
const checkoutSession = await systemFindByPk(CheckoutSession, checkoutSessionId);
|
|
273
287
|
if (!checkoutSession) {
|
|
274
288
|
logger.warn('CheckoutSession not found for pending invoice', { checkoutSessionId });
|
|
275
289
|
return;
|
|
276
290
|
}
|
|
291
|
+
assertJobObjectTenant(checkoutSession);
|
|
277
292
|
if (checkoutSession.invoice_id) {
|
|
278
293
|
logger.info('Invoice already exists for checkout session', {
|
|
279
294
|
checkoutSessionId,
|
|
@@ -293,15 +308,17 @@ events.on(
|
|
|
293
308
|
return;
|
|
294
309
|
}
|
|
295
310
|
|
|
296
|
-
const paymentIntent = await PaymentIntent
|
|
311
|
+
const paymentIntent = await systemFindByPk(PaymentIntent, paymentIntentId);
|
|
297
312
|
if (!paymentIntent) {
|
|
298
313
|
return;
|
|
299
314
|
}
|
|
315
|
+
assertJobObjectTenant(paymentIntent);
|
|
300
316
|
|
|
301
|
-
const customer = await Customer
|
|
317
|
+
const customer = await systemFindByPk(Customer, checkoutSession.customer_id);
|
|
302
318
|
if (!customer) {
|
|
303
319
|
return;
|
|
304
320
|
}
|
|
321
|
+
assertJobObjectTenant(customer);
|
|
305
322
|
|
|
306
323
|
await ensureInvoiceForCheckout({
|
|
307
324
|
checkoutSession,
|