kopia lustrzana https://gitlab.com/rysiekpl/libresilient
104 wiersze
4.0 KiB
JavaScript
104 wiersze
4.0 KiB
JavaScript
/* ========================================================================= *\
|
|
|* === basic-integrity: pre-configured subresource integrity for content === *|
|
|
\* ========================================================================= */
|
|
|
|
/**
|
|
* this plugin does not implement any push method
|
|
*/
|
|
// no polluting of the global namespace please
|
|
(function(LRPC){
|
|
// this never changes
|
|
const pluginName = "basic-integrity"
|
|
LRPC.set(pluginName, (LR, init={})=>{
|
|
|
|
/*
|
|
* plugin config settings
|
|
*/
|
|
|
|
// sane defaults
|
|
let defaultConfig = {
|
|
// list of plugins to wrap
|
|
// this should always contain exactly one element, but still needs to be an array
|
|
// as this is what the Service Worker script expects
|
|
uses: [{
|
|
name: "alt-fetch"
|
|
}],
|
|
// integrity data for each piece of content
|
|
// absolute URL -> integrity data (string)
|
|
// integrity data can contain multiple integrity hashes, space-separated, as per:
|
|
// https://w3c.github.io/webappsec-subresource-integrity/#agility
|
|
integrity: {},
|
|
// if an URL has no integrity data associated with it, should it be allowed or not?
|
|
requireIntegrity: true
|
|
}
|
|
|
|
// merge the defaults with settings from LibResilientConfig
|
|
let config = {...defaultConfig, ...init}
|
|
|
|
// reality check: if no wrapped plugin configured, or more than one, complain
|
|
if (config.uses.length != 1) {
|
|
throw new Error(`Expected exactly one plugin to wrap, but ${config.uses.length} configured.`)
|
|
}
|
|
|
|
/**
|
|
* getting content using the wrapped plugin, but providing integrity data
|
|
*/
|
|
let fetchContent = (url, init={}) => {
|
|
LR.log(pluginName, `handling: ${url}`)
|
|
|
|
// integrity data
|
|
// a string, where we will combine integrity data from init
|
|
// and from the plugin config, if they exist
|
|
let integrity = ""
|
|
|
|
// do we have integrity data in init?
|
|
if ('integrity' in init) {
|
|
integrity = init.integrity
|
|
}
|
|
|
|
// do we have integrity data in config?
|
|
// TODO: how should we treat relative URLs? how does regular fetch() treat them
|
|
if (url in config.integrity) {
|
|
integrity += ' ' + config.integrity[url]
|
|
}
|
|
|
|
// some cleanup
|
|
integrity = integrity.trim()
|
|
|
|
// reality check
|
|
if (integrity != '') {
|
|
// so we have some integrity data; great, let's use it!
|
|
init.integrity = integrity
|
|
|
|
// no integrity data available, are we even allowed to proceed?
|
|
} else if (config.requireIntegrity) {
|
|
|
|
// bail if integrity data is not available
|
|
throw new Error(`Integrity data required but not provided for: ${url}`)
|
|
}
|
|
|
|
// log
|
|
LR.log(pluginName, `integrity for: ${url}\n- ${integrity}`)
|
|
|
|
// fetch using the configured wrapped plugin
|
|
//
|
|
// NOTICE: we have no way of knowing if the wrapped plugin performs any actual integrity check
|
|
// NOTICE: if the wrapped plugin doesn't actually check integrity,
|
|
// NOTICE: setting integrity here is not going to do anything
|
|
return config.uses[0].fetch(url, init)
|
|
}
|
|
|
|
// and add ourselves to it
|
|
// with some additional metadata
|
|
return {
|
|
name: pluginName,
|
|
description: `verifying subresource integrity for resources fetched by other plugins`,
|
|
version: 'COMMIT_UNKNOWN',
|
|
fetch: fetchContent,
|
|
uses: config.uses
|
|
}
|
|
|
|
})
|
|
// done with not polluting the global namespace
|
|
})(LibResilientPluginConstructors)
|