diff --git a/apps/meteor/app/api/server/router.ts b/apps/meteor/app/api/server/router.ts index b11b3e603e5..a919ffb2ac0 100644 --- a/apps/meteor/app/api/server/router.ts +++ b/apps/meteor/app/api/server/router.ts @@ -166,7 +166,7 @@ export class Router< // eslint-disable-next-line no-empty } catch {} - return { ...overrideBodyParams }; + return {}; } private parseQueryParams(request: HonoRequest) { diff --git a/apps/meteor/app/integrations/server/api/api.js b/apps/meteor/app/integrations/server/api/api.js index 451a125e1b0..9cb9068fa34 100644 --- a/apps/meteor/app/integrations/server/api/api.js +++ b/apps/meteor/app/integrations/server/api/api.js @@ -94,7 +94,7 @@ async function executeIntegrationRest() { } const content_raw = Buffer.concat(buffers).toString('utf8'); const protocol = `${this.request.headers.get('x-forwarded-proto')}:` || 'http:'; - const url = new URL(this.request.url, `${protocol}//${this.request.headers.host}`); + const url = new URL(this.request.url, `${protocol}//${this.request.headers.get('host')}`); const request = { url: { @@ -325,13 +325,22 @@ const middleware = async (c, next) => { } try { - const body = Object.fromEntries(new URLSearchParams(await req.raw.clone().text())); - if (!body || typeof body !== 'object' || !('payload' in body) || Object.keys(body).length !== 1) { + const content = await req.raw.clone().text(); + const body = Object.fromEntries(new URLSearchParams(content)); + if (!body || typeof body !== 'object' || Object.keys(body).length !== 1) { return next(); } - // need to compose the full payload in this weird way because body-parser thought it was a form - c.set('bodyParams-override', JSON.parse(body.payload)); + if (body.payload) { + // need to compose the full payload in this weird way because body-parser thought it was a form + c.set('bodyParams-override', JSON.parse(body.payload)); + return next(); + } + incomingLogger.debug({ + msg: 'Body received as application/x-www-form-urlencoded without the "payload" key, parsed as string', + content, + }); + c.set('bodyParams-override', JSON.parse(content)); } catch (e) { c.body(JSON.stringify({ success: false, error: e.message }), 400); } diff --git a/apps/meteor/tests/end-to-end/api/incoming-integrations.ts b/apps/meteor/tests/end-to-end/api/incoming-integrations.ts index 34b459dcdf9..49212300115 100644 --- a/apps/meteor/tests/end-to-end/api/incoming-integrations.ts +++ b/apps/meteor/tests/end-to-end/api/incoming-integrations.ts @@ -398,6 +398,81 @@ describe('[Incoming Integrations]', () => { await removeIntegration(withScript._id, 'incoming'); }); + + it('should send a message if the payload is a application/x-www-form-urlencoded JSON(when not set, default one) but theres no "payload" key, its just a string, the integration has a valid script', async () => { + const payload = { test: 'test' }; + let withScript: IIntegration | undefined; + + await updatePermission('manage-incoming-integrations', ['admin']); + await request + .post(api('integrations.create')) + .set(credentials) + .send({ + type: 'webhook-incoming', + name: 'Incoming test with script and default content-type', + enabled: true, + alias: 'test', + username: 'rocket.cat', + scriptEnabled: true, + overrideDestinationChannelEnabled: false, + channel: '#general', + script: + 'const buildMessage = (obj) => {\n' + + ' \n' + + ' const template = `[#VALUE](${ obj.test })`;\n' + + ' \n' + + ' return {\n' + + ' text: template\n' + + ' };\n' + + ' };\n' + + ' \n' + + ' class Script {\n' + + ' process_incoming_request({ request }) {\n' + + ' msg = buildMessage(request.content);\n' + + ' \n' + + ' return {\n' + + ' content:{\n' + + ' text: msg.text\n' + + ' }\n' + + ' };\n' + + ' }\n' + + ' }\n' + + ' \n', + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('integration').and.to.be.an('object'); + withScript = res.body.integration; + }); + + if (!withScript) { + throw new Error('Integration not created'); + } + + await request + .post(`/hooks/${withScript._id}/${withScript.token}`) + .send(JSON.stringify(payload)) + .expect(200) + .expect(async () => { + return request + .get(api('channels.messages')) + .set(credentials) + .query({ + roomId: 'GENERAL', + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('messages').and.to.be.an('array'); + expect(!!(res.body.messages as IMessage[]).find((m) => m.msg === '[#VALUE](test)')).to.be.true; + }); + }); + + await removeIntegration(withScript._id, 'incoming'); + }); }); describe('[/integrations.history]', () => {