Skip to content

Commit 211ad75

Browse files
authored
fix: enable gatehub signature check (#1757)
1 parent 8c0349a commit 211ad75

2 files changed

Lines changed: 49 additions & 37 deletions

File tree

packages/wallet/backend/src/app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import { GateHubService } from '@/gatehub/service'
4949
import { CardController } from './card/controller'
5050
import { CardService } from './card/service'
5151
import { isRafikiSignedWebhook } from '@/middleware/isRafikiSignedWebhook'
52-
// import { isGateHubSignedWebhook } from '@/middleware/isGateHubSignedWebhook'
52+
import { isGateHubSignedWebhook } from '@/middleware/isGateHubSignedWebhook'
5353

5454
export interface Bindings {
5555
env: Env
@@ -317,7 +317,7 @@ export class App {
317317
router.get('/iframe-urls/:type', isAuth, gateHubController.getIframeUrl)
318318
router.post(
319319
'/gatehub-webhooks',
320-
// isGateHubSignedWebhook,
320+
isGateHubSignedWebhook(env, logger),
321321
gateHubController.webhook
322322
)
323323
router.post(
Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,57 @@
11
import type { NextFunction, Request, Response } from 'express'
22
import { Unauthorized } from '@shared/backend'
3-
import { env } from '@/config/env'
43
import { createHmac } from 'crypto'
4+
import { Env } from '@/config/env'
5+
import { Logger } from 'winston'
56

67
const TOLERANCE_MILLISECONDS = 5000
7-
export const isGateHubSignedWebhook = async (
8-
req: Request,
9-
res: Response,
10-
next: NextFunction
11-
): Promise<void> => {
12-
try {
13-
if (!req.body.timestamp) {
14-
// Respond with 200 on initial setup call
15-
res.status(200).json()
16-
return
17-
}
18-
19-
const body = JSON.stringify(req.body)
20-
const key = Buffer.from(env.GATEHUB_WEBHOOK_SECRET, 'hex')
21-
const messageBuffer = Buffer.from(body, 'utf-8')
22-
23-
const requestSignature = createHmac('sha256', key)
24-
.update(messageBuffer)
25-
.digest('hex')
26-
27-
const timeDiffMilliseconds =
28-
new Date().getTime() - parseFloat(req.body.timestamp)
298

30-
// Check the difference of the received and current timestamp based on your tolerance
31-
const timestampIsValid = timeDiffMilliseconds < TOLERANCE_MILLISECONDS
32-
const signatureIsValid =
33-
requestSignature === req.headers['x-gh-webhook-signature']
34-
35-
const isSignatureValid = timestampIsValid && signatureIsValid
36-
37-
if (!isSignatureValid) {
38-
throw new Unauthorized('Invalid signature header')
9+
export const isGateHubSignedWebhook = (env: Env, logger: Logger) => {
10+
const verify = async (
11+
req: Request,
12+
res: Response,
13+
next: NextFunction
14+
): Promise<void> => {
15+
try {
16+
if (!req.body.timestamp) {
17+
// Respond with 200 on initial setup call
18+
res.status(200).json()
19+
return
20+
}
21+
22+
const body = JSON.stringify(req.body)
23+
const key = Buffer.from(env.GATEHUB_WEBHOOK_SECRET, 'hex')
24+
const messageBuffer = Buffer.from(body, 'utf-8')
25+
26+
const requestSignature = createHmac('sha256', key)
27+
.update(messageBuffer)
28+
.digest('hex')
29+
30+
const timeDiffMilliseconds =
31+
new Date().getTime() - parseFloat(req.body.timestamp)
32+
const webhookSignature = req.headers['x-gh-webhook-signature']
33+
34+
// Check the difference of the received and current timestamp based on your tolerance
35+
const timestampIsValid = timeDiffMilliseconds < TOLERANCE_MILLISECONDS
36+
const signatureIsValid = requestSignature === webhookSignature
37+
38+
const isSignatureValid = timestampIsValid && signatureIsValid
39+
40+
if (!isSignatureValid) {
41+
logger.warn('GateHub invalid signature', {
42+
timestampIsValid,
43+
signatureIsValid,
44+
body,
45+
webhookSignature
46+
})
47+
throw new Unauthorized('Invalid signature header')
48+
}
49+
} catch (e) {
50+
next(e)
3951
}
40-
} catch (e) {
41-
next(e)
52+
53+
next()
4254
}
4355

44-
next()
56+
return verify
4557
}

0 commit comments

Comments
 (0)