Properly handle stripe hook with sig verification
parent
e2e0fa2a00
commit
bf6c35ea50
10
app.js
10
app.js
|
@ -272,7 +272,6 @@ app.enable('trust proxy');
|
||||||
app.use(helmet());
|
app.use(helmet());
|
||||||
app.set('port', process.env.PORT || 1111);
|
app.set('port', process.env.PORT || 1111);
|
||||||
app.use(logger('dev'));
|
app.use(logger('dev'));
|
||||||
app.use(bodyParser.json());
|
|
||||||
app.use(bodyParser.urlencoded({ extended: false }));
|
app.use(bodyParser.urlencoded({ extended: false }));
|
||||||
app.use(cookieParser(config.secretCookie));
|
app.use(cookieParser(config.secretCookie));
|
||||||
app.use(session({
|
app.use(session({
|
||||||
|
@ -287,6 +286,15 @@ app.use(session({
|
||||||
store: store
|
store: store
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
app.use(bodyParser.json({
|
||||||
|
// Only on Stripe URL's which need the rawBody
|
||||||
|
verify: (req, res, buf) => {
|
||||||
|
if(req.originalUrl === '/stripe/subscription_update'){
|
||||||
|
req.rawBody = buf.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
// Set locales from session
|
// Set locales from session
|
||||||
app.use(i18n.init);
|
app.use(i18n.init);
|
||||||
|
|
||||||
|
|
|
@ -3,5 +3,6 @@
|
||||||
"publicKey": "pk_test_this_is_not_real",
|
"publicKey": "pk_test_this_is_not_real",
|
||||||
"stripeCurrency": "usd",
|
"stripeCurrency": "usd",
|
||||||
"stripeDescription": "expressCart payment",
|
"stripeDescription": "expressCart payment",
|
||||||
"stripeLogoURL": "http://localhost:1111/images/stripelogo.png"
|
"stripeLogoURL": "http://localhost:1111/images/stripelogo.png",
|
||||||
|
"stripeWebhookSecret": ""
|
||||||
}
|
}
|
|
@ -16,6 +16,9 @@
|
||||||
"stripeLogoURL": {
|
"stripeLogoURL": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uri-template"
|
"format": "uri-template"
|
||||||
|
},
|
||||||
|
"stripeWebhookSecret": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
@ -7614,7 +7614,8 @@
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.5.2",
|
"version": "6.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"quick-lru": {
|
"quick-lru": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
@ -8726,13 +8727,18 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"stripe": {
|
"stripe": {
|
||||||
"version": "5.10.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/stripe/-/stripe-5.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/stripe/-/stripe-7.12.0.tgz",
|
||||||
"integrity": "sha512-AUDmXfNAAY/oOfW87HPO4bDzNWJp8iQd0blVWwwEgPxO1DmEC//foI0C9rhr2ZNsuF6kLypPfNtGB9Uf+RCQzQ==",
|
"integrity": "sha512-h/NMB7E+0WgDuEOdfrS9giYmTfQRvOoKHdYaKzo9V0hxilXopVJd3ZZQ47193rAOHjIhmuCDtQRb3gEEm24gKg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lodash.isplainobject": "^4.0.6",
|
"qs": "^6.6.0"
|
||||||
"qs": "~6.5.1",
|
},
|
||||||
"safe-buffer": "^5.1.1"
|
"dependencies": {
|
||||||
|
"qs": {
|
||||||
|
"version": "6.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.0.tgz",
|
||||||
|
"integrity": "sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"superagent": {
|
"superagent": {
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
"sanitize-html": "^1.20.1",
|
"sanitize-html": "^1.20.1",
|
||||||
"sitemap": "^1.6.0",
|
"sitemap": "^1.6.0",
|
||||||
"strip-bom": "^3.0.0",
|
"strip-bom": "^3.0.0",
|
||||||
"stripe": "^5.10.0",
|
"stripe": "^7.12.0",
|
||||||
"uglifycss": "0.0.27"
|
"uglifycss": "0.0.27"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -115,13 +115,27 @@ router.post('/checkout_action', (req, res, next) => {
|
||||||
// Subscription hook from Stripe
|
// Subscription hook from Stripe
|
||||||
router.all('/subscription_update', async (req, res, next) => {
|
router.all('/subscription_update', async (req, res, next) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
|
const stripeSigSecret = common.getPaymentConfig().stripeWebhookSecret;
|
||||||
|
const stripeSig = req.headers['stripe-signature'];
|
||||||
|
|
||||||
if(!req.body.data.object.customer){
|
let hook;
|
||||||
return res.status(400).json({ message: 'Customer not found' });
|
if(stripeSigSecret){
|
||||||
|
try{
|
||||||
|
hook = await stripe.webhooks.constructEvent(req.rawBody, stripeSig, stripeSigSecret);
|
||||||
|
console.info('Stripe Webhook received');
|
||||||
|
}catch(err){
|
||||||
|
return res.status(400).send(`Webhook Error: ${err.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!hook.data.object.customer){
|
||||||
|
return res.status(400).json({ message: 'Customer not found' });
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
hook = req.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
const order = await db.orders.findOne({
|
const order = await db.orders.findOne({
|
||||||
orderCustomer: req.body.data.object.customer,
|
orderCustomer: hook.data.object.customer,
|
||||||
orderType: 'Subscription'
|
orderType: 'Subscription'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -130,7 +144,7 @@ router.all('/subscription_update', async (req, res, next) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
let orderStatus = 'Paid';
|
let orderStatus = 'Paid';
|
||||||
if(req.body.type === 'invoice.payment_failed'){
|
if(hook.type === 'invoice.payment_failed'){
|
||||||
orderStatus = 'Declined';
|
orderStatus = 'Declined';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue