diff --git a/package.json b/package.json index 222ce39595..0f29bf5098 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "@tryghost/members-importer": "0.5.1", "@tryghost/members-offers": "0.10.7", "@tryghost/members-ssr": "1.0.20", - "@tryghost/members-stripe-service": "0.8.1", + "@tryghost/members-stripe-service": "0.8.2", "@tryghost/metrics": "1.0.5", "@tryghost/minifier": "0.1.10", "@tryghost/mw-error-handler": "0.1.2", diff --git a/test/e2e-api/members/webhooks.test.js b/test/e2e-api/members/webhooks.test.js index 332d12e49f..c42b39c81c 100644 --- a/test/e2e-api/members/webhooks.test.js +++ b/test/e2e-api/members/webhooks.test.js @@ -162,6 +162,109 @@ describe('Members API', function () { to: 'checkout-webhook-test@email.com' }); }); + + it('Does not 500 if the member is unknown', async function () { + const setupIntent = { + id: 'setup_intent_456', + payment_method: 'card_456', + metadata: { + customer_id: 'cus_456', + subscription_id: 'sub_456' + } + }; + + const paymentMethod = { + id: 'card_456' + }; + + const webhookPayload = JSON.stringify({ + type: 'checkout.session.completed', + data: { + object: { + mode: 'setup', + customer: 'cus_456', + setup_intent: 'setup_intent_456' + } + } + }); + + const webhookSignature = stripe.webhooks.generateTestHeaderString({ + payload: webhookPayload, + secret: process.env.WEBHOOK_SECRET + }); + + const subscription = { + id: 'sub_456', + customer: 'cus_456', + status: 'active', + items: { + type: 'list', + data: [{ + id: 'item_456', + price: { + id: 'price_456', + product: 'product_456', + active: true, + nickname: 'Monthly', + currency: 'USD', + recurring: { + interval: 'month' + }, + unit_amount: 500, + type: 'recurring' + } + }] + }, + start_date: Date.now() / 1000, + current_period_end: Date.now() / 1000 + (60 * 60 * 24 * 31), + cancel_at_period_end: false + }; + + nock('https://api.stripe.com') + .persist() + .get(/v1\/.*/) + .reply((uri, body) => { + const [match, resource, id] = uri.match(/\/?v1\/(\w+)\/?(\w+)/) || [null]; + + if (!match) { + return [500]; + } + + if (resource === 'setup_intents') { + return [200, setupIntent]; + } + + if (resource === 'subscriptions') { + return [200, subscription]; + } + }); + + nock('https://api.stripe.com') + .persist() + .post(/v1\/.*/) + .reply((uri, body) => { + const [match, resource, id, action] = uri.match(/\/?v1\/(\w+)(?:\/?(\w+)){0,2}/) || [null]; + + if (!match) { + return [500]; + } + + if (resource === 'payment_methods') { + return [200, paymentMethod]; + } + + if (resource === 'subscriptions') { + return [200, subscription]; + } + + return [500]; + }); + + await membersAgent.post('/webhooks/stripe/') + .body(webhookPayload) + .header('stripe-signature', webhookSignature) + .expectStatus(200); + }); }); }); }); diff --git a/yarn.lock b/yarn.lock index 7f80a291c3..1b9e843b53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1958,6 +1958,14 @@ lodash "^4.17.21" uuid "^8.3.2" +"@tryghost/errors@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@tryghost/errors/-/errors-1.2.2.tgz#643009ba20770279577fe2778cdf1f816ad13e90" + integrity sha512-81PnsWWayCLQgeBYpslyrMRmSIuflarxxR4tz7ZOIuptybAiKaD3S4GhTZLAXUOi38S62wJBoS/qTzRF6sIzng== + dependencies: + lodash "^4.17.21" + uuid "^8.3.2" + "@tryghost/errors@^0.2.10", "@tryghost/errors@^0.2.11", "@tryghost/errors@^0.2.14": version "0.2.17" resolved "https://registry.yarnpkg.com/@tryghost/errors/-/errors-0.2.17.tgz#9b89f3845256ace5650593f41cc86d64965b56ed" @@ -2243,7 +2251,17 @@ jsonwebtoken "^8.5.1" lodash "^4.17.11" -"@tryghost/members-stripe-service@0.8.1", "@tryghost/members-stripe-service@^0.8.1": +"@tryghost/members-stripe-service@0.8.2": + version "0.8.2" + resolved "https://registry.yarnpkg.com/@tryghost/members-stripe-service/-/members-stripe-service-0.8.2.tgz#9a59b6ba95e523750d1989e14f5d6e5f354938bb" + integrity sha512-Tnkqaqqk5wWwDxcknZ+lqRNmbMwu8GbwzV4bFblymBdV/lOy87CMFMhw324pVSDagTLx/cWqoDkkfoF1aM93dw== + dependencies: + "@tryghost/debug" "^0.1.4" + "@tryghost/errors" "1.2.2" + leaky-bucket "^2.2.0" + stripe "^8.174.0" + +"@tryghost/members-stripe-service@^0.8.1": version "0.8.1" resolved "https://registry.yarnpkg.com/@tryghost/members-stripe-service/-/members-stripe-service-0.8.1.tgz#5af1be427a524ca5d016205117c1322914c0fbbf" integrity sha512-GFjm/GjtCsn3M1nhAB4p+0zoJZFw3Ca+djtp3pGqvJSiN2muPaa4N5aZsqf51QTDgAv+5TTkGIBf4HGVUQsY/w==