/* ========================================================================= *\ |* === 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 // relative 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? 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)