UNPKG

atlassian-connect-express

Version:

Library for building Atlassian Add-ons on top of Express

223 lines (192 loc) 5.91 kB
const jwt = require("atlassian-jwt"); const bodyParser = require("body-parser"); const express = require("express"); const http = require("http"); const moment = require("moment"); const helper = require("./test_helper"); const ac = require("../index"); const request = require("request"); const logger = require("./logger"); describe("Webhook", () => { const app = express(); let addon = {}; let server; let hostServer; let addonRegistered = false; beforeAll(() => { ac.store.register("teststore", (logger, opts) => { return require("../lib/store/sequelize")(logger, opts); }); app.set("env", "development"); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); const installedPayload = helper.installedPayload; installedPayload.baseUrl = "http://admin:admin@localhost:3003"; addon = ac( app, { config: { development: { store: { adapter: "teststore", type: "memory" }, hosts: [installedPayload.baseUrl] } } }, logger ); const host = express(); // mock host host.get("/rest/plugins/1.0/", (req, res) => { res.setHeader("upm-token", "123"); res.json({ plugins: [] }); }); host.post("/rest/plugins/1.0/", (req, res) => { request({ url: `${helper.addonBaseUrl}/installed`, qs: { jwt: createValidJwtToken() }, method: "POST", json: installedPayload }); res.status(200).end(); }); return new Promise(resolve => { hostServer = http.createServer(host).listen(3003, () => { server = http.createServer(app).listen(helper.addonPort, async () => { addon.once("host_settings_saved", () => { addonRegistered = true; }); await addon.register(); resolve(); }); }); }); }); afterAll(() => { server.close(); hostServer.close(); }); function createValidJwtToken(req) { const jwtPayload = { iss: helper.installedPayload.clientKey, iat: moment().utc().unix(), exp: moment().utc().add(10, "minutes").unix() }; if (req) { jwtPayload.qsh = jwt.createQueryStringHash(jwt.fromExpressRequest(req)); } return jwt.encode(jwtPayload, helper.installedPayload.sharedSecret); } function createExpiredJwtToken(req) { const jwtPayload = { iss: helper.installedPayload.clientKey, iat: moment().utc().subtract(20, "minutes").unix(), exp: moment().utc().subtract(10, "minutes").unix() }; if (req) { jwtPayload.qsh = jwt.createQueryStringHash(jwt.fromExpressRequest(req)); } return jwt.encode(jwtPayload, helper.installedPayload.sharedSecret); } function fireTestWebhook(route, body, assertWebhookResult, createJwtToken) { const url = helper.addonBaseUrl + route; const waitForRegistrationThenFireWebhook = function () { if (addonRegistered) { fireWebhook(); } else { setTimeout(waitForRegistrationThenFireWebhook, 50); } }; const requestMock = { method: "post", path: route, query: { user_id: "admin" } }; const fireWebhook = function () { request.post( { url, qs: { user_id: "admin", jwt: createJwtToken ? createJwtToken(requestMock) : createValidJwtToken(requestMock) }, json: body }, assertWebhookResult ); }; waitForRegistrationThenFireWebhook(); } function assertCorrectWebhookResult(err, res) { expect(err).toBeNull(); expect(res.statusCode).toEqual(204); } it("should fire an add-on event", () => { const first = new Promise(resolve => { addon.once("plugin_test_hook", (event, body, req) => { expect(event).toEqual("plugin_test_hook"); expect(body.foo).toEqual("bar"); expect(req.query["user_id"]).toEqual("admin"); resolve(); }); }); const second = new Promise(resolve => { fireTestWebhook("/test-hook", { foo: "bar" }, (err, res) => { assertCorrectWebhookResult(err, res); resolve(); }); }); return Promise.all([first, second]); }); it("should perform auth verification for webhooks", () => { const triggered = jest.fn(); addon.once("webhook_auth_verification_triggered", triggered); const successful = jest.fn(); addon.once("webhook_auth_verification_successful", successful); const first = new Promise(resolve => { addon.once("plugin_test_hook", () => { expect(triggered).toHaveBeenCalled(); expect(successful).toHaveBeenCalled(); resolve(); }); }); const second = new Promise(resolve => { fireTestWebhook("/test-hook", { foo: "bar" }, (err, res) => { assertCorrectWebhookResult(err, res); resolve(); }); }); return Promise.all([first, second]); }); it("webhook with expired JWT claim should not be processed", () => { const triggered = jest.fn(); const successful = jest.fn(); addon.once("webhook_auth_verification_triggered", triggered); addon.once("webhook_auth_verification_successful", successful); return new Promise(resolve => { fireTestWebhook( "/test-hook", { foo: "bar" }, (err, res, body) => { expect(err).toBeNull(); expect(res.statusCode).toEqual(401); expect(body.message).toEqual( "Authentication request has expired. Try reloading the page." ); expect(triggered).toHaveBeenCalled(); expect(successful).not.toHaveBeenCalled(); resolve(); }, createExpiredJwtToken ); }); }); });