describe("plugin: integrity-check", () => { beforeEach(() => { global.nodeFetch = require('node-fetch') global.Request = global.nodeFetch.Request global.Response = global.nodeFetch.Response global.crypto = require('crypto').webcrypto global.Blob = require('buffer').Blob; jest.resetModules(); self = global global.btoa = (bin) => { return Buffer.from(bin, 'binary').toString('base64') } global.LibResilientPluginConstructors = new Map() LR = { log: (component, ...items)=>{ console.debug(component + ' :: ', ...items) } } global.resolvingFetch = jest.fn((url, init)=>{ return Promise.resolve( new Response( ['{"test": "success"}'], { type: "application/json", status: 200, statusText: "OK", headers: { 'ETag': 'TestingETagHeader' }, url: url } ) ) }) init = { name: 'integrity-check', uses: [ { name: 'resolve-all', description: 'Resolves all', version: '0.0.1', fetch: resolvingFetch } ], requireIntegrity: false } requestInit = { integrity: "sha256-eiMrFuthzteJuj8fPwUMyNQMb2SMW7VITmmt2oAxGj0=" } self.log = function(component, ...items) { console.debug(component + ' :: ', ...items) } }) test("it should register in LibResilientPluginConstructors", () => { require("../../plugins/integrity-check.js"); expect(LibResilientPluginConstructors.get('integrity-check')(LR, init).name).toEqual('integrity-check'); }); test("it should throw an error when there aren't any wrapped plugins configured", async () => { require("../../plugins/integrity-check.js"); init = { name: 'integrity-check', uses: [] } expect.assertions(2); try { await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json') } catch (e) { expect(e).toBeInstanceOf(Error) expect(e.toString()).toMatch('Expected exactly one plugin to wrap') } }); test("it should throw an error when there are more than one wrapped plugins configured", async () => { require("../../plugins/integrity-check.js"); init = { name: 'integrity-check', uses: [{ name: 'plugin-1' },{ name: 'plugin-2' }] } expect.assertions(2); try { await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json') } catch (e) { expect(e).toBeInstanceOf(Error) expect(e.toString()).toMatch('Expected exactly one plugin to wrap') } }); test("it should throw an error when an unsupported digest algorithm is used", async () => { require("../../plugins/integrity-check.js"); expect.assertions(1); try { await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json', { integrity: "sha000-eiMrFuthzteJuj8fPwUMyNQMb2SMW7VITmmt2oAxGj0=" }) } catch (e) { expect(e.toString()).toMatch('No digest matched') } }); test("it should return data from the wrapped plugin when no integrity data is available and requireIntegrity is false", async () => { require("../../plugins/integrity-check.js"); const response = await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json'); expect(resolvingFetch).toHaveBeenCalled(); expect(await response.json()).toEqual({test: "success"}) expect(response.url).toEqual('https://resilient.is/test.json') }); test("it should reject no integrity data is available but requireIntegrity is true", async () => { require("../../plugins/integrity-check.js"); init.requireIntegrity = true expect.assertions(2); try { await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json') } catch (e) { expect(e).toBeInstanceOf(Error) expect(e.toString()).toMatch('Integrity data required but not provided for') } }); test("it should check integrity and return data from the wrapped plugin if SHA-256 integrity data matches", async () => { require("../../plugins/integrity-check.js"); const response = await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json', requestInit); expect(resolvingFetch).toHaveBeenCalled(); expect(await response.json()).toEqual({test: "success"}) expect(response.url).toEqual('https://resilient.is/test.json') }); test("it should check integrity and return data from the wrapped plugin if SHA-384 integrity data matches", async () => { require("../../plugins/integrity-check.js"); const response = await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json', { integrity: "sha384-x4iqiH3PIPD51TibGEhTju/WhidcIEcnrpdklYEtIS87f96c4nLyj6CuwUp8kyOo" }); expect(resolvingFetch).toHaveBeenCalled(); expect(await response.json()).toEqual({test: "success"}) expect(response.url).toEqual('https://resilient.is/test.json') }); test("it should check integrity and return data from the wrapped plugin if SHA-512 integrity data matches", async () => { require("../../plugins/integrity-check.js"); const response = await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json', { integrity: "sha512-o+J3lPk7DU8xOJaNfZI5T4Upmaoc9XOVxOWPCFAy4pTgvS8LrJZ8iNis/2ZaryU4bB33cNSXQBxUDvwDxknEBQ==" }); expect(resolvingFetch).toHaveBeenCalled(); expect(await response.json()).toEqual({test: "success"}) expect(response.url).toEqual('https://resilient.is/test.json') }); test("it should check integrity of the data returned from the wrapped plugin and reject if it doesn't match", async () => { require("../../plugins/integrity-check.js"); expect.assertions(1); try { await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json', { integrity: "sha256-INCORRECTINCORRECTINCORRECTINCORRECTINCORREC" }); } catch(e) { expect(e.toString()).toMatch('No digest matched') } }); test("it should check integrity of the data returned from the wrapped plugin and resolve if at least one of multiple integrity hash matches", async () => { require("../../plugins/integrity-check.js"); const response = await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json', { integrity: "sha256-INCORRECTINCORRECTINCORRECTINCORRECTINCORREC sha256-eiMrFuthzteJuj8fPwUMyNQMb2SMW7VITmmt2oAxGj0=" }); expect(resolvingFetch).toHaveBeenCalled(); expect(await response.json()).toEqual({test: "success"}) expect(response.url).toEqual('https://resilient.is/test.json') }); test("it should check integrity of the data returned from the wrapped plugin and reject if all out of multiple integrity hash do not match", async () => { require("../../plugins/integrity-check.js"); expect.assertions(1); try { await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json', { integrity: "sha256-INCORRECTINCORRECTINCORRECTINCORRECTINCORREC sha256-WRONGWRONGWRONGWRONGWRONGWRONGWRONGWRONGWRON" }); } catch(e) { expect(e.toString()).toMatch('No digest matched') } }); });