libresilient/__tests__/plugins/signed-integrity.test.js

169 wiersze
6.8 KiB
JavaScript

describe("plugin: signed-integrity", () => {
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.atob = (ascii) => {
return Buffer.from(ascii, 'base64').toString('binary')
}
global.LibResilientPluginConstructors = new Map()
LR = {
log: (component, ...items)=>{
console.debug(component + ' :: ', ...items)
}
}
header = btoa('{"alg": "ES384"}').replace(/\//g, '_').replace(/\+/g, '-').replace(/=/g, '')
payload = btoa('{"integrity": "sha256-eiMrFuthzteJuj8fPwUMyNQMb2SMW7VITmmt2oAxGj0="}').replace(/\//g, '_').replace(/\+/g, '-').replace(/=/g, '')
signature = btoa('FIXME').replace(/\//g, '_').replace(/\+/g, '-').replace(/=/g, '')
global.resolvingFetch = jest.fn((url, init)=>{
var content = '{"test": "success"}'
var status = 200
var statusText = "OK"
if (url == 'https://resilient.is/test.json.integrity') {
content = header + '.' + payload + '.' + signature
} else if (url == 'https://resilient.is/fail.json.integrity') {
content = '{"test": "fail"}'
status = 404
statusText = "Not Found"
}
return Promise.resolve(
new Response(
[content],
{
type: "application/json",
status: status,
statusText: statusText,
headers: {
'ETag': 'TestingETagHeader'
},
url: url
}
)
)
})
init = {
name: 'signed-integrity',
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/signed-integrity.js");
expect(LibResilientPluginConstructors.get('signed-integrity')(LR, init).name).toEqual('signed-integrity');
});
test("it should throw an error when there aren't any wrapped plugins configured", async () => {
require("../../plugins/signed-integrity.js");
init = {
name: 'signed-integrity',
uses: []
}
expect.assertions(2);
try {
await LibResilientPluginConstructors.get('signed-integrity')(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/signed-integrity.js");
init = {
name: 'signed-integrity',
uses: [{
name: 'plugin-1'
},{
name: 'plugin-2'
}]
}
expect.assertions(2);
try {
await LibResilientPluginConstructors.get('signed-integrity')(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 fetch content when integrity data provided without trying to fetch the integrity data URL", async () => {
require("../../plugins/signed-integrity.js");
const response = await LibResilientPluginConstructors.get('signed-integrity')(LR, init).fetch('https://resilient.is/test.json', {
integrity: "sha384-x4iqiH3PIPD51TibGEhTju/WhidcIEcnrpdklYEtIS87f96c4nLyj6CuwUp8kyOo"
});
expect(resolvingFetch).toHaveBeenCalledTimes(1);
expect(await response.json()).toEqual({test: "success"})
expect(response.url).toEqual('https://resilient.is/test.json')
});
test("it should fetch content when integrity data not provided, by also fetching the integrity data URL", async () => {
require("../../plugins/signed-integrity.js");
const response = await LibResilientPluginConstructors.get('signed-integrity')(LR, init).fetch('https://resilient.is/test.json', {});
expect(resolvingFetch).toHaveBeenCalledTimes(2);
expect(resolvingFetch).toHaveBeenNthCalledWith(1, 'https://resilient.is/test.json.integrity')
expect(await response.json()).toEqual({test: "success"})
expect(response.url).toEqual('https://resilient.is/test.json')
});
test("it should fetch content when integrity data not provided, and integrity data URL 404s", async () => {
require("../../plugins/signed-integrity.js");
const response = await LibResilientPluginConstructors.get('signed-integrity')(LR, init).fetch('https://resilient.is/fail.json', {});
expect(resolvingFetch).toHaveBeenCalledTimes(2);
expect(resolvingFetch).toHaveBeenNthCalledWith(1, 'https://resilient.is/fail.json.integrity')
expect(await response.json()).toEqual({test: "success"})
expect(response.url).toEqual('https://resilient.is/fail.json')
});
test("it should refuse to fetch content when integrity data not provided and integrity data URL 404s, but requireIntegrity is set to true", async () => {
require("../../plugins/signed-integrity.js");
var newInit = init
newInit.requireIntegrity = true
expect.assertions(4);
try {
const response = await LibResilientPluginConstructors.get('signed-integrity')(LR, newInit).fetch('https://resilient.is/fail.json', {});
} catch (e) {
expect(resolvingFetch).toHaveBeenCalledTimes(1);
expect(resolvingFetch).toHaveBeenCalledWith('https://resilient.is/fail.json.integrity')
expect(e).toBeInstanceOf(Error)
expect(e.toString()).toMatch('No integrity data available, though required.')
}
});
});