diff --git a/src/creator.ts b/src/creator.ts index a4faedd8..1e163727 100644 --- a/src/creator.ts +++ b/src/creator.ts @@ -538,7 +538,7 @@ export class BaseSlashCreator extends (EventEmitter as any as new () => TypedEve const signature = treq.headers['x-signature-ed25519'] as string; const timestamp = treq.headers['x-signature-timestamp'] as string; - const verified = await this._verify(JSON.stringify(treq.body), signature, timestamp); + const verified = await this._verify(treq.rawBody || JSON.stringify(treq.body), signature, timestamp); if (!verified) { this.emit('debug', 'A request failed to be verified'); diff --git a/src/server.ts b/src/server.ts index 705427a9..2bb23254 100644 --- a/src/server.ts +++ b/src/server.ts @@ -61,6 +61,8 @@ export interface TransformedRequest { request: any; /** The response class from a Server, depending on what server it is. */ response: any; + /** The raw string of the body. */ + rawBody?: string; } /** diff --git a/src/servers/bun.ts b/src/servers/bun.ts index ea629ce1..bee249f7 100644 --- a/src/servers/bun.ts +++ b/src/servers/bun.ts @@ -34,7 +34,8 @@ export class BunServer extends Server { headers: Object.fromEntries(request.headers.entries()), body: body ? JSON.parse(body) : body, request, - response: null + response: null, + rawBody: body }, async (response) => { if (response.files) { diff --git a/src/servers/cfworker.ts b/src/servers/cfworker.ts index a2191919..22407d12 100644 --- a/src/servers/cfworker.ts +++ b/src/servers/cfworker.ts @@ -29,7 +29,8 @@ export class CloudflareWorkerServer extends Server { headers: Object.fromEntries(request.headers.entries()), body: body ? JSON.parse(body) : body, request, - response: null + response: null, + rawBody: body }, async (response) => { if (response.files) { diff --git a/src/servers/fastify.ts b/src/servers/fastify.ts index efadcf1b..37a41405 100644 --- a/src/servers/fastify.ts +++ b/src/servers/fastify.ts @@ -30,27 +30,41 @@ export class FastifyServer extends Server { /** @private */ createEndpoint(path: string, handler: ServerRequestHandler) { - this.app.post(path, (req: any, res: any) => - handler( - { - headers: req.headers, - body: req.body, - request: req, - response: res - }, - async (response) => { - res.status(response.status || 200); - if (response.headers) res.headers(response.headers); - if (response.files) { - const data = new MultipartData(); - res.header('Content-Type', 'multipart/form-data; boundary=' + data.boundary); - for (const i in response.files) data.attach(`files[${i}]`, response.files[i].file, response.files[i].name); - data.attach('payload_json', JSON.stringify(response.body)); - res.send(Buffer.concat(data.finish())); - } else res.send(response.body); + this.app.register(async (app: any) => { + // Capture and set the raw payload with a scoped parser + app.addContentTypeParser( + 'application/json', + { parseAs: 'string', asString: true }, + (request: any, payload: any, done: any) => { + request.rawBody = payload; + app.getDefaultJsonParser('remove', 'remove')(request, payload, done); } - ) - ); + ); + + app.post(path, (req: any, res: any) => + handler( + { + headers: req.headers, + body: req.body, + request: req, + response: res, + rawBody: req.rawBody + }, + async (response) => { + res.status(response.status || 200); + if (response.headers) res.headers(response.headers); + if (response.files) { + const data = new MultipartData(); + res.header('Content-Type', 'multipart/form-data; boundary=' + data.boundary); + for (const i in response.files) + data.attach(`files[${i}]`, response.files[i].file, response.files[i].name); + data.attach('payload_json', JSON.stringify(response.body)); + res.send(Buffer.concat(data.finish())); + } else res.send(response.body); + } + ) + ); + }); } /** @private */ diff --git a/src/servers/lambda.ts b/src/servers/lambda.ts index 04211b0c..ac993560 100644 --- a/src/servers/lambda.ts +++ b/src/servers/lambda.ts @@ -33,7 +33,8 @@ export class AWSLambdaServer extends Server { headers: splitHeaders(event.headers), body: event.body ? JSON.parse(event.body) : {}, request: event, - response: callback + response: callback, + rawBody: event.body ?? '' }, async (response) => { const responseHeaders = joinHeaders(response.headers);