diff --git a/packages/backend-core/src/middleware/tests/contentSecurityPolicy.spec.ts b/packages/backend-core/src/middleware/tests/contentSecurityPolicy.spec.ts index 0c5838e7fe..2c8d01a979 100644 --- a/packages/backend-core/src/middleware/tests/contentSecurityPolicy.spec.ts +++ b/packages/backend-core/src/middleware/tests/contentSecurityPolicy.spec.ts @@ -1,10 +1,19 @@ import crypto from "crypto" import contentSecurityPolicy from "../contentSecurityPolicy" +import { app } from "../../cache" +import { Feature, App } from "@budibase/types" +import { users, licenses } from "../../../tests/core/utilities/structures" +import { doInAppContext } from "../../context" jest.mock("crypto", () => ({ randomBytes: jest.fn(), randomUUID: jest.fn(), })) +jest.mock("../../cache", () => ({ + app: { + getAppMetadata: jest.fn(), + }, +})) describe("contentSecurityPolicy middleware", () => { let ctx: any @@ -57,19 +66,71 @@ describe("contentSecurityPolicy middleware", () => { }) it("should handle errors and log an error message", async () => { + // Ctx setup to let us try and use CSP whitelist + const fakeAppId = "app_sdfdsfsdfsdf" + ctx.appId = fakeAppId + ctx.user = { + license: { + features: [Feature.CUSTOM_APP_SCRIPTS], + }, + } + const consoleSpy = jest.spyOn(console, "error").mockImplementation() const error = new Error("Test error") // @ts-ignore - crypto.randomBytes.mockImplementation(() => { + app.getAppMetadata.mockImplementation(() => { throw error }) + await contentSecurityPolicy(ctx, next) + + expect(app.getAppMetadata).toHaveBeenCalledWith(fakeAppId) + expect(consoleSpy).toHaveBeenCalledWith( + `Error occurred in Content-Security-Policy middleware: ${error}` + ) + expect(next).toHaveBeenCalled() + consoleSpy.mockRestore() + }) + + it("should add custom CSP whitelist", async () => { + const appId = "app_foo" + const domain = "https://*.foo.bar" + + // Ctx setup to let us try and use CSP whitelist + ctx.appId = appId + ctx.user = users.user() + ctx.user.license = licenses.license({ + features: [Feature.CUSTOM_APP_SCRIPTS], + }) + + // @ts-ignore + app.getAppMetadata.mockImplementation(function (): App { + return { + appId, + type: "foo", + version: "1", + componentLibraries: [], + name: "foo", + url: "/foo", + template: undefined, + instance: { _id: appId }, + tenantId: ctx.user.tenantId, + status: "foo", + scripts: [ + { + id: "foo", + name: "Test", + location: "Head", + cspWhitelist: domain, + }, + ], + } + }) await contentSecurityPolicy(ctx, next) - expect(consoleSpy).toHaveBeenCalledWith( - `Error occurred in Content-Security-Policy middleware: ${error}` - ) - expect(next).not.toHaveBeenCalled() - consoleSpy.mockRestore() + const cspHeader = ctx.set.mock.calls[0][1] + expect(cspHeader).toContain(`default-src 'self' ${domain};`) + expect(app.getAppMetadata).toHaveBeenCalledWith(appId) + expect(next).toHaveBeenCalled() }) })