In addition to CBroe's answer, the snippet below represents signature verification implementation as NestJS guard.
// src/common/guards/signature-verification.guard.ts
@Injectable()
export class SignatureVerificationGuard implements CanActivate {
constructor(private readonly configService: ConfigService) {}
canActivate(context: ExecutionContext): boolean {
const {
rawBody,
headers: { 'x-hub-signature': signature },
} = context.switchToHttp().getRequest();
const { sha1 } = parse(signature);
if (!sha1) return false;
const appSecret = this.configService.get('MESSENGER_APP_SECRET');
const digest = createHmac('sha1', appSecret).update(rawBody).digest('hex');
const hashBufferFromBody = Buffer.from(`sha1=${digest}`, 'utf-8');
const bufferFromSignature = Buffer.from(signature, 'utf-8');
if (hashBufferFromBody.length !== bufferFromSignature.length)
return false;
return timingSafeEqual(hashBufferFromBody, bufferFromSignature);
}
}
// src/modules/webhook/webhook.controller.ts
@UseGuards(SignatureVerificationGuard)
@Post()
@HttpCode(HttpStatus.OK)
handleWebhook(@Body() data) {
// ...
}