kopia lustrzana https://gitlab.com/rysiekpl/libresilient
254 wiersze
9.1 KiB
JavaScript
254 wiersze
9.1 KiB
JavaScript
import {
|
|
describe,
|
|
it,
|
|
beforeEach,
|
|
beforeAll
|
|
} from "https://deno.land/std@0.183.0/testing/bdd.ts";
|
|
|
|
import {
|
|
assertThrows,
|
|
assertRejects,
|
|
assertEquals
|
|
} from "https://deno.land/std@0.183.0/testing/asserts.ts";
|
|
|
|
import {
|
|
assertSpyCall,
|
|
assertSpyCalls,
|
|
spy,
|
|
} from "https://deno.land/std@0.183.0/testing/mock.ts";
|
|
|
|
beforeAll(async ()=>{
|
|
|
|
window.resolvingFetch = (url, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
['{"test": "success"}'],
|
|
{
|
|
type: "application/json",
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: url
|
|
}
|
|
)
|
|
)
|
|
}
|
|
|
|
/*
|
|
* prototype of the plugin init object
|
|
*/
|
|
window.initPrototype = {
|
|
name: 'integrity-check',
|
|
uses: [
|
|
{
|
|
name: 'resolve-all',
|
|
description: 'Resolves all',
|
|
version: '0.0.1',
|
|
fetch: null
|
|
}
|
|
]
|
|
}
|
|
|
|
/*
|
|
* integrity data in init object to be passed to fetch()
|
|
* for the plugin to verify
|
|
*/
|
|
window.requestInit = {
|
|
sha256: {
|
|
integrity: "sha256-eiMrFuthzteJuj8fPwUMyNQMb2SMW7VITmmt2oAxGj0="
|
|
},
|
|
sha384: {
|
|
integrity: "sha384-x4iqiH3PIPD51TibGEhTju/WhidcIEcnrpdklYEtIS87f96c4nLyj6CuwUp8kyOo"
|
|
},
|
|
sha512: {
|
|
integrity: "sha512-o+J3lPk7DU8xOJaNfZI5T4Upmaoc9XOVxOWPCFAy4pTgvS8LrJZ8iNis/2ZaryU4bB33cNSXQBxUDvwDxknEBQ=="
|
|
}
|
|
}
|
|
})
|
|
|
|
/**
|
|
* we need to do all of this before each test in order to reset the fetch() use counter
|
|
* and make sure window.init is clean and not modified by previous tests
|
|
*/
|
|
beforeEach(()=>{
|
|
window.fetch = spy(window.resolvingFetch)
|
|
window.init = {
|
|
...window.initPrototype
|
|
}
|
|
window.init.uses[0].fetch = window.fetch
|
|
})
|
|
|
|
describe('browser: integrity-check plugin', async () => {
|
|
window.LibResilientPluginConstructors = new Map()
|
|
window.LR = {
|
|
log: (component, ...items)=>{
|
|
console.debug(component + ' :: ', ...items)
|
|
}
|
|
}
|
|
|
|
window.resolvingFetch = null
|
|
window.fetch = null
|
|
window.subtle = crypto.subtle
|
|
|
|
await import("../../../plugins/integrity-check/index.js");
|
|
|
|
it("should register in LibResilientPluginConstructors", () => {
|
|
assertEquals(
|
|
LibResilientPluginConstructors
|
|
.get('integrity-check')(LR, init).name,
|
|
'integrity-check');
|
|
});
|
|
|
|
it("should throw an error when there aren't any wrapped plugins configured", () => {
|
|
init = {
|
|
name: 'integrity-check',
|
|
uses: []
|
|
}
|
|
assertThrows(
|
|
()=>{
|
|
return LibResilientPluginConstructors.get('integrity-check')(LR, init)
|
|
},
|
|
Error,
|
|
'Expected exactly one plugin to wrap, but 0 configured.'
|
|
)
|
|
});
|
|
|
|
it("should throw an error when there are more than one wrapped plugins configured", () => {
|
|
init = {
|
|
name: 'integrity-check',
|
|
uses: ['plugin-one', 'plugin-two']
|
|
}
|
|
assertThrows(
|
|
()=>{
|
|
return LibResilientPluginConstructors.get('integrity-check')(LR, init)
|
|
},
|
|
Error,
|
|
'Expected exactly one plugin to wrap, but 2 configured.'
|
|
)
|
|
});
|
|
|
|
it("should throw an error when an unsupported digest algorithm is used", async () => {
|
|
|
|
assertRejects(async ()=>{
|
|
return await LibResilientPluginConstructors
|
|
.get('integrity-check')(LR, init)
|
|
.fetch('https://resilient.is/test.json', {
|
|
integrity: "sha000-eiMrFuthzteJuj8fPwUMyNQMb2SMW7VITmmt2oAxGj0="
|
|
})
|
|
},
|
|
Error,
|
|
'No digest matched for:'
|
|
)
|
|
});
|
|
|
|
it("it should return data from the wrapped plugin when no integrity data is available and requireIntegrity is false (default)", async () => {
|
|
|
|
const response = await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json');
|
|
|
|
assertEquals(await response.json(), {test: "success"})
|
|
assertSpyCalls(fetch, 1)
|
|
assertSpyCall(fetch, 0, {
|
|
args: ['https://resilient.is/test.json', {}]
|
|
})
|
|
});
|
|
|
|
it("should reject no integrity data is available but requireIntegrity is true", async () => {
|
|
|
|
init.requireIntegrity = true
|
|
|
|
assertRejects(async ()=>{
|
|
return await LibResilientPluginConstructors
|
|
.get('integrity-check')(LR, init)
|
|
.fetch('https://resilient.is/test.json')
|
|
},
|
|
Error,
|
|
'Integrity data required but not provided for:'
|
|
)
|
|
});
|
|
|
|
it("should check integrity and return data from the wrapped plugin if SHA-256 integrity data matches", async () => {
|
|
|
|
const response = await LibResilientPluginConstructors
|
|
.get('integrity-check')(LR, init)
|
|
.fetch('https://resilient.is/test.json', requestInit.sha256);
|
|
|
|
assertEquals(await response.json(), {test: "success"})
|
|
assertSpyCalls(fetch, 1)
|
|
assertSpyCall(fetch, 0, {
|
|
args: ['https://resilient.is/test.json', requestInit.sha256]
|
|
})
|
|
});
|
|
|
|
it("should check integrity and return data from the wrapped plugin if SHA-384 integrity data matches", async () => {
|
|
|
|
const response = await LibResilientPluginConstructors
|
|
.get('integrity-check')(LR, init)
|
|
.fetch('https://resilient.is/test.json', requestInit.sha384);
|
|
|
|
assertEquals(await response.json(), {test: "success"})
|
|
assertSpyCalls(fetch, 1)
|
|
assertSpyCall(fetch, 0, {
|
|
args: ['https://resilient.is/test.json', requestInit.sha384]
|
|
})
|
|
});
|
|
|
|
it("should check integrity and return data from the wrapped plugin if SHA-512 integrity data matches", async () => {
|
|
|
|
const response = await LibResilientPluginConstructors
|
|
.get('integrity-check')(LR, init)
|
|
.fetch('https://resilient.is/test.json', requestInit.sha512);
|
|
|
|
assertEquals(await response.json(), {test: "success"})
|
|
assertSpyCalls(fetch, 1)
|
|
assertSpyCall(fetch, 0, {
|
|
args: ['https://resilient.is/test.json', requestInit.sha512]
|
|
})
|
|
});
|
|
|
|
it("should check integrity of the data returned from the wrapped plugin and reject if it doesn't match", async () => {
|
|
|
|
assertRejects(async ()=>{
|
|
return await LibResilientPluginConstructors
|
|
.get('integrity-check')(LR, init)
|
|
.fetch('https://resilient.is/test.json', {
|
|
integrity: "sha256-INCORRECTINCORRECTINCORRECTINCORRECTINCORREC"
|
|
});
|
|
},
|
|
Error,
|
|
'No digest matched for:'
|
|
)
|
|
});
|
|
|
|
it("should check integrity of the data returned from the wrapped plugin and resolve if at least one of multiple integrity hash matches", async () => {
|
|
|
|
const response = await LibResilientPluginConstructors.get('integrity-check')(LR, init).fetch('https://resilient.is/test.json', {
|
|
integrity: "sha256-INCORRECTINCORRECTINCORRECTINCORRECTINCORREC sha256-eiMrFuthzteJuj8fPwUMyNQMb2SMW7VITmmt2oAxGj0="
|
|
});
|
|
|
|
assertEquals(await response.json(), {test: "success"})
|
|
assertSpyCalls(fetch, 1)
|
|
assertSpyCall(fetch, 0, {
|
|
args: ['https://resilient.is/test.json',
|
|
{
|
|
integrity: "sha256-INCORRECTINCORRECTINCORRECTINCORRECTINCORREC sha256-eiMrFuthzteJuj8fPwUMyNQMb2SMW7VITmmt2oAxGj0="
|
|
}]
|
|
})
|
|
});
|
|
|
|
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 () => {
|
|
|
|
assertRejects(async ()=>{
|
|
return await LibResilientPluginConstructors
|
|
.get('integrity-check')(LR, init)
|
|
.fetch('https://resilient.is/test.json', {
|
|
integrity: "sha256-INCORRECTINCORRECTINCORRECTINCORRECTINCORREC sha256-WRONGWRONGWRONGWRONGWRONGWRONGWRONGWRONGWRON"
|
|
});
|
|
},
|
|
Error,
|
|
'No digest matched for:'
|
|
)
|
|
});
|
|
})
|