@actuate-media/plugin-commerce 0.0.14 → 0.1.1
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/CHANGELOG.md +43 -0
- package/dist/__tests__/checkout.test.d.ts +2 -0
- package/dist/__tests__/checkout.test.d.ts.map +1 -0
- package/dist/__tests__/checkout.test.js +68 -0
- package/dist/__tests__/checkout.test.js.map +1 -0
- package/dist/__tests__/index.test.js +6 -11
- package/dist/__tests__/index.test.js.map +1 -1
- package/dist/__tests__/webhooks.test.d.ts +2 -0
- package/dist/__tests__/webhooks.test.d.ts.map +1 -0
- package/dist/__tests__/webhooks.test.js +71 -0
- package/dist/__tests__/webhooks.test.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -10
- package/dist/index.js.map +1 -1
- package/dist/stripe/checkout.d.ts +10 -0
- package/dist/stripe/checkout.d.ts.map +1 -1
- package/dist/stripe/checkout.js +16 -2
- package/dist/stripe/checkout.js.map +1 -1
- package/dist/stripe/webhooks.d.ts +21 -1
- package/dist/stripe/webhooks.d.ts.map +1 -1
- package/dist/stripe/webhooks.js +56 -5
- package/dist/stripe/webhooks.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# @actuate-media/plugin-commerce
|
|
2
2
|
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- cd8a061: Remove dead sidebar nav from bundled plugins and guard the whole class.
|
|
8
|
+
|
|
9
|
+
`plugin-ai`, `plugin-commerce`, and `plugin-blocks` each advertised
|
|
10
|
+
`adminNavItems` paths (`/ai/*`, `/commerce/*`, `/blocks`) that the admin router
|
|
11
|
+
has no view for — plugins cannot register views, and these plugins register no
|
|
12
|
+
collection backing those paths — so every one of those sidebar links landed on
|
|
13
|
+
the 404 page. The commerce items were also duplicates of the working collection
|
|
14
|
+
nav (its collections already appear under the "Commerce" group at their real
|
|
15
|
+
`/<slug>` routes).
|
|
16
|
+
- Dropped the dead `adminNavItems` from all three plugins. Commerce collections
|
|
17
|
+
remain reachable at `/products`, `/orders`, `/discounts`, …; plugin-ai and
|
|
18
|
+
plugin-blocks are backend/page-builder plugins with no standalone admin route.
|
|
19
|
+
- Added `cms-admin`'s `router/admin-routes` resolver (`adminPathResolves`) plus
|
|
20
|
+
a table-driven test asserting **every** bundled plugin's nav paths resolve to a
|
|
21
|
+
real view, and a drift test that keeps the known-route list in sync with
|
|
22
|
+
`AdminRoot`. This is the systemic guard for a bug class that has now shipped in
|
|
23
|
+
published packages three times.
|
|
24
|
+
|
|
25
|
+
## 0.1.0
|
|
26
|
+
|
|
27
|
+
### Minor Changes
|
|
28
|
+
|
|
29
|
+
- d278add: Verify Stripe webhook signatures and lock in the checkout money-mapping.
|
|
30
|
+
|
|
31
|
+
The webhook handler previously "verified" a payload by only checking that the
|
|
32
|
+
signature and secret strings were non-empty before parsing it — so a forged POST
|
|
33
|
+
with any non-empty `Stripe-Signature` would be processed as a real event (a fake
|
|
34
|
+
`payment_intent.succeeded` is a direct fraud risk). `handleStripeWebhook` now
|
|
35
|
+
performs real HMAC-SHA256 verification via a new exported `verifyStripeSignature`
|
|
36
|
+
(a dependency-free equivalent of `stripe.webhooks.constructEvent`: signed-payload
|
|
37
|
+
HMAC, constant-time compare, multi-`v1` key rotation, and timestamp replay
|
|
38
|
+
tolerance).
|
|
39
|
+
|
|
40
|
+
The money-critical checkout mapping (dollar→integer-cents rounding for line items
|
|
41
|
+
and shipping, discounts, metadata) is extracted into a pure, exported
|
|
42
|
+
`buildCheckoutSessionParams` so it is unit-tested independently of the
|
|
43
|
+
(still-stubbed) Stripe API call. Adds 15 behavioral tests covering signature
|
|
44
|
+
accept/reject/replay/rotation, event routing, and cents/shipping/discount mapping.
|
|
45
|
+
|
|
3
46
|
## 0.0.14
|
|
4
47
|
|
|
5
48
|
### Patch Changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/checkout.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { buildCheckoutSessionParams } from '../stripe/checkout.js';
|
|
3
|
+
const base = { successUrl: '/success', cancelUrl: '/cancel' };
|
|
4
|
+
const lineItem = (over = {}) => ({
|
|
5
|
+
productId: 'p1',
|
|
6
|
+
name: 'Widget',
|
|
7
|
+
quantity: 1,
|
|
8
|
+
unitPrice: 5,
|
|
9
|
+
...over,
|
|
10
|
+
});
|
|
11
|
+
describe('buildCheckoutSessionParams', () => {
|
|
12
|
+
it('converts dollar unit prices to integer cents (float-safe)', () => {
|
|
13
|
+
const params = buildCheckoutSessionParams({
|
|
14
|
+
...base,
|
|
15
|
+
lineItems: [lineItem({ unitPrice: 19.99, quantity: 2 })],
|
|
16
|
+
});
|
|
17
|
+
const li = params.line_items[0];
|
|
18
|
+
expect(li.price_data.unit_amount).toBe(1999); // 19.99*100 = 1998.999… → round
|
|
19
|
+
expect(li.quantity).toBe(2);
|
|
20
|
+
expect(params.mode).toBe('payment');
|
|
21
|
+
expect(params.success_url).toBe('/success');
|
|
22
|
+
});
|
|
23
|
+
it('rounds a value that floats below the integer (10.1 → 1010c)', () => {
|
|
24
|
+
const params = buildCheckoutSessionParams({
|
|
25
|
+
...base,
|
|
26
|
+
lineItems: [lineItem({ unitPrice: 10.1 })],
|
|
27
|
+
});
|
|
28
|
+
expect(params.line_items[0].price_data.unit_amount).toBe(1010);
|
|
29
|
+
});
|
|
30
|
+
it('includes variant metadata + image only when present', () => {
|
|
31
|
+
const withVariant = buildCheckoutSessionParams({
|
|
32
|
+
...base,
|
|
33
|
+
lineItems: [lineItem({ variantId: 'v1', image: 'https://img/x.png' })],
|
|
34
|
+
});
|
|
35
|
+
const pd = withVariant.line_items[0].price_data.product_data;
|
|
36
|
+
expect(pd.metadata).toEqual({ productId: 'p1', variantId: 'v1' });
|
|
37
|
+
expect(pd.images).toEqual(['https://img/x.png']);
|
|
38
|
+
const bare = buildCheckoutSessionParams({ ...base, lineItems: [lineItem()] });
|
|
39
|
+
const pd2 = bare.line_items[0].price_data.product_data;
|
|
40
|
+
expect(pd2.metadata).toEqual({ productId: 'p1' });
|
|
41
|
+
expect(pd2.images).toEqual([]);
|
|
42
|
+
});
|
|
43
|
+
it('maps shipping options to fixed_amount cents', () => {
|
|
44
|
+
const params = buildCheckoutSessionParams({
|
|
45
|
+
...base,
|
|
46
|
+
lineItems: [lineItem()],
|
|
47
|
+
shippingOptions: [{ id: 's1', label: 'Express', amount: 12.5 }],
|
|
48
|
+
});
|
|
49
|
+
const so = params.shipping_options[0];
|
|
50
|
+
expect(so.shipping_rate_data.fixed_amount).toEqual({ amount: 1250, currency: 'usd' });
|
|
51
|
+
expect(so.shipping_rate_data.display_name).toBe('Express');
|
|
52
|
+
});
|
|
53
|
+
it('adds discounts + customer_email only when provided', () => {
|
|
54
|
+
const full = buildCheckoutSessionParams({
|
|
55
|
+
...base,
|
|
56
|
+
lineItems: [lineItem()],
|
|
57
|
+
discountCode: 'SAVE10',
|
|
58
|
+
customerEmail: 'a@b.com',
|
|
59
|
+
});
|
|
60
|
+
expect(full.discounts).toEqual([{ coupon: 'SAVE10' }]);
|
|
61
|
+
expect(full.customer_email).toBe('a@b.com');
|
|
62
|
+
const bare = buildCheckoutSessionParams({ ...base, lineItems: [lineItem()] });
|
|
63
|
+
expect(bare.discounts).toBeUndefined();
|
|
64
|
+
expect(bare.customer_email).toBeUndefined();
|
|
65
|
+
expect(bare.shipping_options).toBeUndefined();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=checkout.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout.test.js","sourceRoot":"","sources":["../../src/__tests__/checkout.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAA;AAElE,MAAM,IAAI,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,CAAA;AAC7D,MAAM,QAAQ,GAAG,CAAC,OAAgC,EAAE,EAAE,EAAE,CAAC,CAAC;IACxD,SAAS,EAAE,IAAI;IACf,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC;IACX,SAAS,EAAE,CAAC;IACZ,GAAG,IAAI;CACR,CAAC,CAAA;AAEF,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,MAAM,GAAG,0BAA0B,CAAC;YACxC,GAAG,IAAI;YACP,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;SACzD,CAAC,CAAA;QACF,MAAM,EAAE,GAAI,MAAM,CAAC,UAAoB,CAAC,CAAC,CAAC,CAAA;QAC1C,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,CAAC,gCAAgC;QAC7E,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC3B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACnC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,MAAM,GAAG,0BAA0B,CAAC;YACxC,GAAG,IAAI;YACP,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;SAC3C,CAAC,CAAA;QACF,MAAM,CAAE,MAAM,CAAC,UAAoB,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,WAAW,GAAG,0BAA0B,CAAC;YAC7C,GAAG,IAAI;YACP,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;SACvE,CAAC,CAAA;QACF,MAAM,EAAE,GAAI,WAAW,CAAC,UAAoB,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAA;QACvE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACjE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAA;QAEhD,MAAM,IAAI,GAAG,0BAA0B,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAA;QAC7E,MAAM,GAAG,GAAI,IAAI,CAAC,UAAoB,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAA;QACjE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACjD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAChC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,MAAM,GAAG,0BAA0B,CAAC;YACxC,GAAG,IAAI;YACP,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC;YACvB,eAAe,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;SAChE,CAAC,CAAA;QACF,MAAM,EAAE,GAAI,MAAM,CAAC,gBAA0B,CAAC,CAAC,CAAC,CAAA;QAChD,MAAM,CAAC,EAAE,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QACrF,MAAM,CAAC,EAAE,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC5D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,IAAI,GAAG,0BAA0B,CAAC;YACtC,GAAG,IAAI;YACP,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC;YACvB,YAAY,EAAE,QAAQ;YACtB,aAAa,EAAE,SAAS;SACzB,CAAC,CAAA;QACF,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAA;QACtD,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAE3C,MAAM,IAAI,GAAG,0BAA0B,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAA;QAC7E,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,CAAA;QACtC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,aAAa,EAAE,CAAA;QAC3C,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,aAAa,EAAE,CAAA;IAC/C,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -13,18 +13,13 @@ describe('commerce', () => {
|
|
|
13
13
|
expect(plugin.collections).toBeDefined();
|
|
14
14
|
expect(Object.keys(plugin.collections ?? {}).length).toBeGreaterThan(0);
|
|
15
15
|
});
|
|
16
|
-
it('
|
|
16
|
+
it('does not register dead admin nav items', () => {
|
|
17
|
+
// The old /commerce/* nav paths had no admin view and duplicated the
|
|
18
|
+
// working collection nav — commerce collections already surface under
|
|
19
|
+
// their "Commerce" group at /products, /orders, /discounts, …. Guarded
|
|
20
|
+
// centrally by cms-admin's plugin-nav-resolves test.
|
|
17
21
|
const plugin = commercePlugin();
|
|
18
|
-
expect(plugin.adminNavItems).
|
|
19
|
-
{ label: 'Products', icon: 'package', path: '/commerce/products' },
|
|
20
|
-
{ label: 'Orders', icon: 'shopping-cart', path: '/commerce/orders' },
|
|
21
|
-
{ label: 'Discounts', icon: 'percent', path: '/commerce/discounts' },
|
|
22
|
-
{
|
|
23
|
-
label: 'Commerce Dashboard',
|
|
24
|
-
icon: 'bar-chart',
|
|
25
|
-
path: '/commerce/dashboard',
|
|
26
|
-
},
|
|
27
|
-
]);
|
|
22
|
+
expect(plugin.adminNavItems).toBeUndefined();
|
|
28
23
|
});
|
|
29
24
|
it('registers hooks', () => {
|
|
30
25
|
const plugin = commercePlugin();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;YAC/B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;YACnC,MAAM,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC3C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAA;YACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;QACzE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;YAC/B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;YACnC,MAAM,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC3C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAA;YACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;QACzE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,qEAAqE;YACrE,sEAAsE;YACtE,uEAAuE;YACvE,qDAAqD;YACrD,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;YAC/B,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,aAAa,EAAE,CAAA;QAC9C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;YACzB,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;YAC/B,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;YAC/C,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAA;QACzD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;YACtC,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,CAAC,CAAA;YACjC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACtC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/webhooks.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { createHmac } from 'node:crypto';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { handleStripeWebhook, verifyStripeSignature } from '../stripe/webhooks.js';
|
|
4
|
+
const SECRET = 'whsec_test';
|
|
5
|
+
const NOW = 1_700_000_000_000; // fixed ms for deterministic replay checks
|
|
6
|
+
const NOW_SEC = Math.floor(NOW / 1000);
|
|
7
|
+
function sign(payload, ts = NOW_SEC, secret = SECRET) {
|
|
8
|
+
const sig = createHmac('sha256', secret).update(`${ts}.${payload}`).digest('hex');
|
|
9
|
+
return `t=${ts},v1=${sig}`;
|
|
10
|
+
}
|
|
11
|
+
describe('verifyStripeSignature', () => {
|
|
12
|
+
it('accepts a valid signature within the tolerance window', () => {
|
|
13
|
+
const payload = JSON.stringify({ type: 'x' });
|
|
14
|
+
expect(() => verifyStripeSignature(payload, sign(payload), SECRET, { now: NOW })).not.toThrow();
|
|
15
|
+
});
|
|
16
|
+
it('rejects a tampered payload', () => {
|
|
17
|
+
const header = sign('{"amount":100}');
|
|
18
|
+
expect(() => verifyStripeSignature('{"amount":999}', header, SECRET, { now: NOW })).toThrow(/mismatch/);
|
|
19
|
+
});
|
|
20
|
+
it('rejects a signature made with a different secret', () => {
|
|
21
|
+
const payload = '{}';
|
|
22
|
+
expect(() => verifyStripeSignature(payload, sign(payload, NOW_SEC, 'whsec_other'), SECRET, { now: NOW })).toThrow(/mismatch/);
|
|
23
|
+
});
|
|
24
|
+
it('rejects an out-of-tolerance timestamp (replay protection)', () => {
|
|
25
|
+
const payload = '{}';
|
|
26
|
+
expect(() => verifyStripeSignature(payload, sign(payload, NOW_SEC - 10_000), SECRET, { now: NOW })).toThrow(/tolerance/);
|
|
27
|
+
});
|
|
28
|
+
it('rejects a missing signature or missing secret', () => {
|
|
29
|
+
expect(() => verifyStripeSignature('{}', '', SECRET, { now: NOW })).toThrow(/Missing webhook signature/);
|
|
30
|
+
expect(() => verifyStripeSignature('{}', sign('{}'), '', { now: NOW })).toThrow(/Missing webhook signing secret/);
|
|
31
|
+
});
|
|
32
|
+
it('rejects a malformed signature header', () => {
|
|
33
|
+
expect(() => verifyStripeSignature('{}', 'garbage', SECRET, { now: NOW })).toThrow(/Malformed/);
|
|
34
|
+
});
|
|
35
|
+
it('accepts when any of multiple v1 signatures matches (key rotation)', () => {
|
|
36
|
+
const payload = '{}';
|
|
37
|
+
const good = createHmac('sha256', SECRET).update(`${NOW_SEC}.${payload}`).digest('hex');
|
|
38
|
+
const header = `t=${NOW_SEC},v1=deadbeef,v1=${good}`;
|
|
39
|
+
expect(() => verifyStripeSignature(payload, header, SECRET, { now: NOW })).not.toThrow();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('handleStripeWebhook', () => {
|
|
43
|
+
function evt(type, object = {}) {
|
|
44
|
+
const payload = JSON.stringify({ type, data: { object } });
|
|
45
|
+
return { payload, header: sign(payload) };
|
|
46
|
+
}
|
|
47
|
+
it('routes each known event type to handled=true', async () => {
|
|
48
|
+
for (const type of [
|
|
49
|
+
'checkout.session.completed',
|
|
50
|
+
'payment_intent.succeeded',
|
|
51
|
+
'charge.refunded',
|
|
52
|
+
]) {
|
|
53
|
+
const { payload, header } = evt(type);
|
|
54
|
+
const res = await handleStripeWebhook(payload, header, SECRET, { now: NOW });
|
|
55
|
+
expect(res).toMatchObject({ handled: true, event: type });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
it('returns handled=false for an unknown but authentic event', async () => {
|
|
59
|
+
const { payload, header } = evt('customer.created');
|
|
60
|
+
const res = await handleStripeWebhook(payload, header, SECRET, { now: NOW });
|
|
61
|
+
expect(res).toEqual({ handled: false, event: 'customer.created' });
|
|
62
|
+
});
|
|
63
|
+
it('does NOT process a forged event (invalid signature)', async () => {
|
|
64
|
+
// A fake "payment succeeded" — this must be rejected, not handled.
|
|
65
|
+
const payload = JSON.stringify({ type: 'payment_intent.succeeded', data: { object: {} } });
|
|
66
|
+
const res = await handleStripeWebhook(payload, `t=${NOW_SEC},v1=forged`, SECRET, { now: NOW });
|
|
67
|
+
expect(res.handled).toBe(false);
|
|
68
|
+
expect(res.error).toMatch(/verification failed/i);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=webhooks.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.test.js","sourceRoot":"","sources":["../../src/__tests__/webhooks.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAKpF,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE;QACP,SAAS,EAAE,MAAM,CAAA;QACjB,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;IACD,GAAG,CAAC,EAAE;QACJ,aAAa,CAAC,EAAE,OAAO,CAAA;KACxB,CAAA;IACD,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,OAAO,CAAA;KAClB,CAAA;CACF;AAED,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,MAAM,GAAE,oBAAyB,GAAG,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAKpF,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE;QACP,SAAS,EAAE,MAAM,CAAA;QACjB,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;IACD,GAAG,CAAC,EAAE;QACJ,aAAa,CAAC,EAAE,OAAO,CAAA;KACxB,CAAA;IACD,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,OAAO,CAAA;KAClB,CAAA;CACF;AAED,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,MAAM,GAAE,oBAAyB,GAAG,gBAAgB,CAYlF;AAED,YAAY,EAAE,oBAAoB,IAAI,cAAc,EAAE,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -8,16 +8,11 @@ export function commercePlugin(config = {}) {
|
|
|
8
8
|
name: 'commerce',
|
|
9
9
|
fields: commerceFields,
|
|
10
10
|
collections: commerceCollections,
|
|
11
|
-
adminNavItems:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
label: 'Commerce Dashboard',
|
|
17
|
-
icon: 'bar-chart',
|
|
18
|
-
path: '/commerce/dashboard',
|
|
19
|
-
},
|
|
20
|
-
],
|
|
11
|
+
// No adminNavItems: the commerce collections already surface in the sidebar
|
|
12
|
+
// under their "Commerce" group at their real /<slug> routes (/products,
|
|
13
|
+
// /orders, /discounts, …). The old /commerce/* items pointed at routes the
|
|
14
|
+
// admin router has no view for, so they were dead 404s that also duplicated
|
|
15
|
+
// the working collection nav. Guarded by cms-admin's plugin-nav-resolves test.
|
|
21
16
|
hooks: commerceHooks,
|
|
22
17
|
});
|
|
23
18
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAyB,MAAM,gCAAgC,CAAA;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAgB1C,iGAAiG;AACjG,MAAM,UAAU,cAAc,CAAC,SAA+B,EAAE;IAC9D,OAAO,YAAY,CAAC;QAClB,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,cAAc;QACtB,WAAW,EAAE,mBAAmB;QAChC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAyB,MAAM,gCAAgC,CAAA;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAgB1C,iGAAiG;AACjG,MAAM,UAAU,cAAc,CAAC,SAA+B,EAAE;IAC9D,OAAO,YAAY,CAAC;QAClB,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,cAAc;QACtB,WAAW,EAAE,mBAAmB;QAChC,4EAA4E;QAC5E,wEAAwE;QACxE,2EAA2E;QAC3E,4EAA4E;QAC5E,+EAA+E;QAC/E,KAAK,EAAE,aAAa;KACrB,CAAC,CAAA;AACJ,CAAC;AAGD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -24,6 +24,16 @@ export interface CheckoutSession {
|
|
|
24
24
|
url: string;
|
|
25
25
|
expiresAt: Date;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Build the Stripe Checkout Session params from cart line items and options.
|
|
29
|
+
*
|
|
30
|
+
* Pure and money-critical: it converts dollar amounts to integer cents
|
|
31
|
+
* (`Math.round(x * 100)`) for every line item and shipping rate. Extracted from
|
|
32
|
+
* `createCheckoutSession` so this mapping is unit-testable independently of the
|
|
33
|
+
* (still-stubbed) Stripe API call — a cents-rounding or field-shape bug here is
|
|
34
|
+
* a real overcharge/undercharge once the SDK is wired.
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildCheckoutSessionParams(options: CheckoutSessionOptions): Record<string, unknown>;
|
|
27
37
|
/** Creates a Stripe Checkout session from cart line items and configuration. */
|
|
28
38
|
export declare function createCheckoutSession(options: CheckoutSessionOptions): Promise<CheckoutSession>;
|
|
29
39
|
//# sourceMappingURL=checkout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../../src/stripe/checkout.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,gBAAgB,EAAE,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,cAAc,EAAE,CAAA;IAClC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,IAAI,CAAA;CAChB;AAED,gFAAgF;AAChF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../../src/stripe/checkout.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,gBAAgB,EAAE,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,cAAc,EAAE,CAAA;IAClC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,IAAI,CAAA;CAChB;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,sBAAsB,GAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwCzB;AAED,gFAAgF;AAChF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC,CAa1B"}
|
package/dist/stripe/checkout.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Build the Stripe Checkout Session params from cart line items and options.
|
|
3
|
+
*
|
|
4
|
+
* Pure and money-critical: it converts dollar amounts to integer cents
|
|
5
|
+
* (`Math.round(x * 100)`) for every line item and shipping rate. Extracted from
|
|
6
|
+
* `createCheckoutSession` so this mapping is unit-testable independently of the
|
|
7
|
+
* (still-stubbed) Stripe API call — a cents-rounding or field-shape bug here is
|
|
8
|
+
* a real overcharge/undercharge once the SDK is wired.
|
|
9
|
+
*/
|
|
10
|
+
export function buildCheckoutSessionParams(options) {
|
|
3
11
|
const stripeLineItems = options.lineItems.map((item) => ({
|
|
4
12
|
price_data: {
|
|
5
13
|
currency: 'usd',
|
|
@@ -34,7 +42,13 @@ export async function createCheckoutSession(options) {
|
|
|
34
42
|
if (options.discountCode) {
|
|
35
43
|
sessionParams['discounts'] = [{ coupon: options.discountCode }];
|
|
36
44
|
}
|
|
45
|
+
return sessionParams;
|
|
46
|
+
}
|
|
47
|
+
/** Creates a Stripe Checkout session from cart line items and configuration. */
|
|
48
|
+
export async function createCheckoutSession(options) {
|
|
49
|
+
const sessionParams = buildCheckoutSessionParams(options);
|
|
37
50
|
// TODO: Call Stripe SDK — stripe.checkout.sessions.create(sessionParams)
|
|
51
|
+
void sessionParams;
|
|
38
52
|
const expiresAt = new Date();
|
|
39
53
|
expiresAt.setMinutes(expiresAt.getMinutes() + 30);
|
|
40
54
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkout.js","sourceRoot":"","sources":["../../src/stripe/checkout.ts"],"names":[],"mappings":"AA8BA
|
|
1
|
+
{"version":3,"file":"checkout.js","sourceRoot":"","sources":["../../src/stripe/checkout.ts"],"names":[],"mappings":"AA8BA;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAA+B;IAE/B,MAAM,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvD,UAAU,EAAE;YACV,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE;gBACZ,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;gBACtC,QAAQ,EAAE;oBACR,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACzD;aACF;YACD,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;SAC9C;QACD,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACxB,CAAC,CAAC,CAAA;IAEH,MAAM,aAAa,GAA4B;QAC7C,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,eAAe;QAC3B,WAAW,EAAE,OAAO,CAAC,UAAU;QAC/B,UAAU,EAAE,OAAO,CAAC,SAAS;QAC7B,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAA;IAED,IAAI,OAAO,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;QACpC,aAAa,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACxE,kBAAkB,EAAE;gBAClB,YAAY,EAAE,GAAG,CAAC,KAAK;gBACvB,IAAI,EAAE,cAAc;gBACpB,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE;aACxE;SACF,CAAC,CAAC,CAAA;IACL,CAAC;IAED,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,aAAa,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;IACjE,CAAC;IAED,OAAO,aAAa,CAAA;AACtB,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAA+B;IAE/B,MAAM,aAAa,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAA;IAEzD,yEAAyE;IACzE,KAAK,aAAa,CAAA;IAClB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAA;IAC5B,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAA;IAEjD,OAAO;QACL,EAAE,EAAE,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE;QAC3B,GAAG,EAAE,2CAA2C,IAAI,CAAC,GAAG,EAAE,EAAE;QAC5D,SAAS;KACV,CAAA;AACH,CAAC"}
|
|
@@ -3,6 +3,26 @@ export interface WebhookResult {
|
|
|
3
3
|
event: string;
|
|
4
4
|
error?: string;
|
|
5
5
|
}
|
|
6
|
+
export interface VerifyOptions {
|
|
7
|
+
/** Reject events whose timestamp is further than this from now. Default 300s. */
|
|
8
|
+
toleranceSeconds?: number;
|
|
9
|
+
/** Current time in ms — injectable for deterministic tests. Default Date.now(). */
|
|
10
|
+
now?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Verify a Stripe webhook signature (the `Stripe-Signature` header) against the
|
|
14
|
+
* raw request body using the endpoint's signing secret. This is a
|
|
15
|
+
* dependency-free equivalent of `stripe.webhooks.constructEvent`:
|
|
16
|
+
*
|
|
17
|
+
* signed_payload = `${t}.${rawBody}`
|
|
18
|
+
* expected = HMAC-SHA256(signed_payload, secret) // hex
|
|
19
|
+
* valid = any provided v1 == expected (constant-time) AND |now - t| ≤ tolerance
|
|
20
|
+
*
|
|
21
|
+
* Throws on any failure. Multiple `v1` signatures (key rotation) are supported.
|
|
22
|
+
* Without this, a forged POST with any non-empty signature would be processed —
|
|
23
|
+
* a fake "payment succeeded" is a direct money/fraud risk.
|
|
24
|
+
*/
|
|
25
|
+
export declare function verifyStripeSignature(payload: string, signatureHeader: string, secret: string, options?: VerifyOptions): void;
|
|
6
26
|
/** Verifies and processes a Stripe webhook event payload. */
|
|
7
|
-
export declare function handleStripeWebhook(payload: string, signature: string, secret: string): Promise<WebhookResult>;
|
|
27
|
+
export declare function handleStripeWebhook(payload: string, signature: string, secret: string, options?: VerifyOptions): Promise<WebhookResult>;
|
|
8
28
|
//# sourceMappingURL=webhooks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/stripe/webhooks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/stripe/webhooks.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAUD,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC1B,IAAI,CAkCN;AAgCD,6DAA6D;AAC7D,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,aAAa,CAAC,CA8BxB"}
|
package/dist/stripe/webhooks.js
CHANGED
|
@@ -1,3 +1,57 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
/** Default replay-protection window, matching Stripe's SDK (5 minutes). */
|
|
3
|
+
const DEFAULT_TOLERANCE_SECONDS = 300;
|
|
4
|
+
/**
|
|
5
|
+
* Verify a Stripe webhook signature (the `Stripe-Signature` header) against the
|
|
6
|
+
* raw request body using the endpoint's signing secret. This is a
|
|
7
|
+
* dependency-free equivalent of `stripe.webhooks.constructEvent`:
|
|
8
|
+
*
|
|
9
|
+
* signed_payload = `${t}.${rawBody}`
|
|
10
|
+
* expected = HMAC-SHA256(signed_payload, secret) // hex
|
|
11
|
+
* valid = any provided v1 == expected (constant-time) AND |now - t| ≤ tolerance
|
|
12
|
+
*
|
|
13
|
+
* Throws on any failure. Multiple `v1` signatures (key rotation) are supported.
|
|
14
|
+
* Without this, a forged POST with any non-empty signature would be processed —
|
|
15
|
+
* a fake "payment succeeded" is a direct money/fraud risk.
|
|
16
|
+
*/
|
|
17
|
+
export function verifyStripeSignature(payload, signatureHeader, secret, options = {}) {
|
|
18
|
+
if (!secret)
|
|
19
|
+
throw new Error('Missing webhook signing secret');
|
|
20
|
+
if (!signatureHeader)
|
|
21
|
+
throw new Error('Missing webhook signature');
|
|
22
|
+
let timestamp;
|
|
23
|
+
const signatures = [];
|
|
24
|
+
for (const part of signatureHeader.split(',')) {
|
|
25
|
+
const eq = part.indexOf('=');
|
|
26
|
+
if (eq === -1)
|
|
27
|
+
continue;
|
|
28
|
+
const key = part.slice(0, eq).trim();
|
|
29
|
+
const value = part.slice(eq + 1).trim();
|
|
30
|
+
if (key === 't')
|
|
31
|
+
timestamp = value;
|
|
32
|
+
else if (key === 'v1')
|
|
33
|
+
signatures.push(value);
|
|
34
|
+
}
|
|
35
|
+
if (!timestamp || signatures.length === 0) {
|
|
36
|
+
throw new Error('Malformed webhook signature header');
|
|
37
|
+
}
|
|
38
|
+
const timestampSec = Number(timestamp);
|
|
39
|
+
if (!Number.isFinite(timestampSec))
|
|
40
|
+
throw new Error('Invalid webhook timestamp');
|
|
41
|
+
const nowSec = Math.floor((options.now ?? Date.now()) / 1000);
|
|
42
|
+
const tolerance = options.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
|
|
43
|
+
if (Math.abs(nowSec - timestampSec) > tolerance) {
|
|
44
|
+
throw new Error('Webhook timestamp outside tolerance (possible replay)');
|
|
45
|
+
}
|
|
46
|
+
const expected = createHmac('sha256', secret).update(`${timestamp}.${payload}`).digest('hex');
|
|
47
|
+
const expectedBuf = Buffer.from(expected);
|
|
48
|
+
const matches = signatures.some((sig) => {
|
|
49
|
+
const sigBuf = Buffer.from(sig);
|
|
50
|
+
return sigBuf.length === expectedBuf.length && timingSafeEqual(sigBuf, expectedBuf);
|
|
51
|
+
});
|
|
52
|
+
if (!matches)
|
|
53
|
+
throw new Error('Webhook signature mismatch');
|
|
54
|
+
}
|
|
1
55
|
async function handleCheckoutCompleted(session) {
|
|
2
56
|
const customerEmail = session['customer_email'];
|
|
3
57
|
const paymentIntentId = session['payment_intent'];
|
|
@@ -19,13 +73,10 @@ async function handleChargeRefunded(charge) {
|
|
|
19
73
|
console.info(`[commerce:webhook] Charge refunded — charge=${chargeId} intent=${paymentIntentId} refunded=${amountRefunded}`);
|
|
20
74
|
}
|
|
21
75
|
/** Verifies and processes a Stripe webhook event payload. */
|
|
22
|
-
export async function handleStripeWebhook(payload, signature, secret) {
|
|
76
|
+
export async function handleStripeWebhook(payload, signature, secret, options = {}) {
|
|
23
77
|
let event;
|
|
24
78
|
try {
|
|
25
|
-
|
|
26
|
-
if (!signature || !secret) {
|
|
27
|
-
throw new Error('Missing webhook signature or secret');
|
|
28
|
-
}
|
|
79
|
+
verifyStripeSignature(payload, signature, secret, options);
|
|
29
80
|
event = JSON.parse(payload);
|
|
30
81
|
}
|
|
31
82
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/stripe/webhooks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/stripe/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAazD,2EAA2E;AAC3E,MAAM,yBAAyB,GAAG,GAAG,CAAA;AASrC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAe,EACf,eAAuB,EACvB,MAAc,EACd,UAAyB,EAAE;IAE3B,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;IAC9D,IAAI,CAAC,eAAe;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;IAElE,IAAI,SAA6B,CAAA;IACjC,MAAM,UAAU,GAAa,EAAE,CAAA;IAC/B,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAC5B,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,SAAQ;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QACvC,IAAI,GAAG,KAAK,GAAG;YAAE,SAAS,GAAG,KAAK,CAAA;aAC7B,IAAI,GAAG,KAAK,IAAI;YAAE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC/C,CAAC;IACD,IAAI,CAAC,SAAS,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;IACvD,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,CAAA;IACtC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;IAEhF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;IAC7D,MAAM,SAAS,GAAG,OAAO,CAAC,gBAAgB,IAAI,yBAAyB,CAAA;IACvE,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,YAAY,CAAC,GAAG,SAAS,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAA;IAC1E,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC7F,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QACtC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC/B,OAAO,MAAM,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACrF,CAAC,CAAC,CAAA;IACF,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;AAC7D,CAAC;AAED,KAAK,UAAU,uBAAuB,CAAC,OAAgC;IACrE,MAAM,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAuB,CAAA;IACrE,MAAM,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAuB,CAAA;IACvE,MAAM,WAAW,GAAG,OAAO,CAAC,cAAc,CAAuB,CAAA;IAEjE,8CAA8C;IAC9C,OAAO,CAAC,IAAI,CACV,iDAAiD,aAAa,YAAY,eAAe,UAAU,WAAW,EAAE,CACjH,CAAA;AACH,CAAC;AAED,KAAK,UAAU,sBAAsB,CAAC,aAAsC;IAC1E,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAuB,CAAA;IAC1D,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAuB,CAAA;IAE5D,oDAAoD;IACpD,OAAO,CAAC,IAAI,CAAC,iDAAiD,QAAQ,WAAW,MAAM,EAAE,CAAC,CAAA;AAC5F,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,MAA+B;IACjE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAuB,CAAA;IACnD,MAAM,cAAc,GAAG,MAAM,CAAC,iBAAiB,CAAuB,CAAA;IACtE,MAAM,eAAe,GAAG,MAAM,CAAC,gBAAgB,CAAuB,CAAA;IAEtE,wEAAwE;IACxE,OAAO,CAAC,IAAI,CACV,+CAA+C,QAAQ,WAAW,eAAe,aAAa,cAAc,EAAE,CAC/G,CAAA;AACH,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAe,EACf,SAAiB,EACjB,MAAc,EACd,UAAyB,EAAE;IAE3B,IAAI,KAAkB,CAAA;IAEtB,IAAI,CAAC;QACH,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;QAC1D,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAA;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,gCAAgC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;SAC1F,CAAA;IACH,CAAC;IAED,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,4BAA4B;YAC/B,MAAM,uBAAuB,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAChD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;QAE7C,KAAK,0BAA0B;YAC7B,MAAM,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAC/C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;QAE7C,KAAK,iBAAiB;YACpB,MAAM,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAC7C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;QAE7C;YACE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;IAChD,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actuate-media/plugin-commerce",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@types/react": "^19.0.0",
|
|
29
29
|
"typescript": "^5.7.0",
|
|
30
30
|
"vitest": "^4.1.0",
|
|
31
|
-
"@actuate-media/cms-core": "0.93.
|
|
31
|
+
"@actuate-media/cms-core": "0.93.3"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@actuate-media/cms-core": ">=0.1.0",
|