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.set('port', process.env.PORT || 1111); | ||||
| app.use(logger('dev')); | ||||
| app.use(bodyParser.json()); | ||||
| app.use(bodyParser.urlencoded({ extended: false })); | ||||
| app.use(cookieParser(config.secretCookie)); | ||||
| app.use(session({ | ||||
|  | @ -287,6 +286,15 @@ app.use(session({ | |||
|     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
 | ||||
| app.use(i18n.init); | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,5 +3,6 @@ | |||
|     "publicKey": "pk_test_this_is_not_real", | ||||
|     "stripeCurrency": "usd", | ||||
|     "stripeDescription": "expressCart payment", | ||||
|     "stripeLogoURL": "http://localhost:1111/images/stripelogo.png" | ||||
|     "stripeLogoURL": "http://localhost:1111/images/stripelogo.png", | ||||
|     "stripeWebhookSecret": "" | ||||
| } | ||||
|  | @ -16,6 +16,9 @@ | |||
|         "stripeLogoURL": { | ||||
|             "type": "string", | ||||
|             "format": "uri-template" | ||||
|         }, | ||||
|         "stripeWebhookSecret": { | ||||
|             "type": "string" | ||||
|         } | ||||
|     }, | ||||
|     "required": [ | ||||
|  |  | |||
|  | @ -7614,7 +7614,8 @@ | |||
|     "qs": { | ||||
|       "version": "6.5.2", | ||||
|       "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": { | ||||
|       "version": "1.1.0", | ||||
|  | @ -8726,13 +8727,18 @@ | |||
|       "dev": true | ||||
|     }, | ||||
|     "stripe": { | ||||
|       "version": "5.10.0", | ||||
|       "resolved": "https://registry.npmjs.org/stripe/-/stripe-5.10.0.tgz", | ||||
|       "integrity": "sha512-AUDmXfNAAY/oOfW87HPO4bDzNWJp8iQd0blVWwwEgPxO1DmEC//foI0C9rhr2ZNsuF6kLypPfNtGB9Uf+RCQzQ==", | ||||
|       "version": "7.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/stripe/-/stripe-7.12.0.tgz", | ||||
|       "integrity": "sha512-h/NMB7E+0WgDuEOdfrS9giYmTfQRvOoKHdYaKzo9V0hxilXopVJd3ZZQ47193rAOHjIhmuCDtQRb3gEEm24gKg==", | ||||
|       "requires": { | ||||
|         "lodash.isplainobject": "^4.0.6", | ||||
|         "qs": "~6.5.1", | ||||
|         "safe-buffer": "^5.1.1" | ||||
|         "qs": "^6.6.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "qs": { | ||||
|           "version": "6.9.0", | ||||
|           "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.0.tgz", | ||||
|           "integrity": "sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA==" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "superagent": { | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ | |||
|     "sanitize-html": "^1.20.1", | ||||
|     "sitemap": "^1.6.0", | ||||
|     "strip-bom": "^3.0.0", | ||||
|     "stripe": "^5.10.0", | ||||
|     "stripe": "^7.12.0", | ||||
|     "uglifycss": "0.0.27" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|  |  | |||
|  | @ -115,13 +115,27 @@ router.post('/checkout_action', (req, res, next) => { | |||
| // Subscription hook from Stripe
 | ||||
| router.all('/subscription_update', async (req, res, next) => { | ||||
|     const db = req.app.db; | ||||
|     const stripeSigSecret = common.getPaymentConfig().stripeWebhookSecret; | ||||
|     const stripeSig = req.headers['stripe-signature']; | ||||
| 
 | ||||
|     if(!req.body.data.object.customer){ | ||||
|     let hook; | ||||
|     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({ | ||||
|         orderCustomer: req.body.data.object.customer, | ||||
|         orderCustomer: hook.data.object.customer, | ||||
|         orderType: 'Subscription' | ||||
|     }); | ||||
| 
 | ||||
|  | @ -130,7 +144,7 @@ router.all('/subscription_update', async (req, res, next) => { | |||
|     } | ||||
| 
 | ||||
|     let orderStatus = 'Paid'; | ||||
|     if(req.body.type === 'invoice.payment_failed'){ | ||||
|     if(hook.type === 'invoice.payment_failed'){ | ||||
|         orderStatus = 'Declined'; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue