Skip to content

Commit

Permalink
Issue #386 [Enhancement][WIP] Add integrity-json plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
t2ym committed Sep 4, 2020
1 parent 070b6d3 commit cf76821
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 82 deletions.
8 changes: 8 additions & 0 deletions demo-config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ const targetConfig = {
hook: hookPath,
plugins: plugins,
},
url: {
mappings: [
// [ fullPath, urlPath ] in directory path names
[path.resolve(basePath, 'bower_components'), '/components'], // highest priority in mapping
[path.resolve(basePath, 'demo'), '/components/thin-hook/demo'], // path.resolve(targetConfig.path.base, targetConfig.path.root) is interpreted as root
[hookPath, '/components/thin-hook'], // for hook.min.js
],
},
mode: {
enableDebugging: false,
devtoolsDisabled: true,
Expand Down
29 changes: 29 additions & 0 deletions demo-config/integrity-json/targets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
@license https://github.com/t2ym/thin-hook/blob/master/LICENSE.md
Copyright (c) 2020, Tetsuya Mori <[email protected]>. All rights reserved.
*/
const path = require('path');

// return globs for target entries in integrity.json
const targets = (targetConfig) => {
const destPath = path.resolve(targetConfig.path.base, targetConfig.path.root);
return [
path.resolve(targetConfig.path.hook, 'hook.min.js'),
path.resolve(destPath, '**/*'),
path.resolve(targetConfig.path.base, 'bower_components/**/*'),
// integrity.json itself
'!' + path.resolve(destPath, 'integrity.json'),
'!' + path.resolve(destPath, '**/*.gz'),
'!' + path.resolve(destPath, 'errorReport.json'),
// decoded index.html
'!' + path.resolve(destPath, targetConfig.path.decodedIndexHtml),
// encoded index.html
'!' + path.resolve(destPath, targetConfig.path.encodedIndexHtml),
'!' + path.resolve(targetConfig.path.base, 'bower_components/**/test/**/*'),
'!' + path.resolve(targetConfig.path.base, 'bower_components/**/demo/**/*'),
];
}

module.exports = {
targets: targets,
};
84 changes: 2 additions & 82 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ if (!gulp.series) {
}

const targetConfig = require('./demo-config/config.js');
console.log('targetConfig', targetConfig);
console.log('targetConfig', JSON.stringify(targetConfig, null, 2));

const hook = require('./hook.js');

Expand Down Expand Up @@ -214,87 +214,7 @@ targetConfig.task('keys');

targetConfig.task('integrity-js');

// generate demo/integrity.json for static contents
// Note: toWebPath() and gulp.src() have to be customized for the target application.
// TODO: Handle cross origin contents
gulp.task('integrity-json', () => {
const integrityJSONPath = 'demo/integrity.json';
const entryPageRelativeFilePath = 'demo/index.html';
const entryPagePath = entryPageRelativeFilePath.split('/')[0] + '/'
let files = [];
let cwd;
let base;
let integrity = { version: targetConfig['get-version'].version };
// toWebPath() must be customized for the target application
let toWebPath = function (fullpath) { // convert full file path to URL path for the target application
// for components via polyserve
const componentRootPath = '/components'
const thisComponentPath = cwd.split(path.sep).pop(); // 'thin-hook'
const mappedComponentPath = 'bower_components'; // should be customized
let fullPaths = fullpath.split(path.sep);
let cwdPaths = cwd.split(path.sep);
let relativePaths = fullPaths.slice(cwdPaths.length);
let paths = [];
paths.push(componentRootPath);
if (relativePaths[0] === mappedComponentPath) {
paths = paths.concat(relativePaths.slice(1));
}
else {
paths.push(thisComponentPath);
paths = paths.concat(relativePaths);
}
return paths.join('/');
};
return gulp.src([
'hook.min.js',
'demo/**/*',
'bower_components/**/*',
// 'node_modules/**/*', // this demo does not use components directly from node_modules
// integrity.json itself
'!' + integrityJSONPath,
'!demo/**/*.gz',
'!demo/errorReport.json',
// original index.html
'!demo/original-index.html',
'!demo/index.html',
'!node_modules/**/*', // this demo does not use components directly from node_modules
'!test/**/*',
'!lib/**/*',
'!demo-keys/**/*',
'!demo-backend/**/*',
'!examples/**/*',
'!bower_components/**/test/**/*',
'!bower_components/**/demo/**/*',
], { base: '.' })
.pipe(through.obj(
function (file, enc, callback) {
if (file.contents) {
let hash = hook.utils.createHash('sha256');
hash.update(file.contents);
let digest = hash.digest('base64');
cwd = file.cwd;
base = file.base;
files.push([toWebPath(file.path), digest]);
}
callback(null, null);
},
function (callback) {
files.sort((a, b) => a[0].localeCompare(b[0]));
for (let file of files) {
integrity[file[0]] = file[1];
}
//console.log(JSON.stringify(integrity, null, 2));
this.push(new File({
cwd: cwd,
base: base,
path: integrityJSONPath,
contents: Buffer.from(JSON.stringify(integrity, null, 2)),
}));
callback();
}
))
.pipe(gulp.dest('.'));
});
targetConfig.task('integrity-json');

targetConfig.task('policy');

Expand Down
69 changes: 69 additions & 0 deletions plugins/integrity-json/configurator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
@license https://github.com/t2ym/thin-hook/blob/master/LICENSE.md
Copyright (c) 2020, Tetsuya Mori <[email protected]>. All rights reserved.
*/
const path = require('path');
const { preprocess } = require('preprocess');
const through = require('through2');
const gulp = require('gulp');
const createHash = require('sha.js');
const File = require('vinyl');

const pluginName = 'integrity-json';

// generate integrity.json for static contents
const configurator = (targetConfig) => {
const configPath = path.resolve(targetConfig.path.base, targetConfig.path.config, pluginName);
const destPath = path.resolve(targetConfig.path.base, targetConfig.path.root);
const pluginDirname = __dirname;
const integrityJSONPath = path.resolve(destPath, 'integrity.json');
let files = [];
let integrity = {};
let toUrlPath = function (fullPath) { // convert full file path to URL path for the target application
let urlPath;
for (let [ _fullPath, _urlPath ] of targetConfig.url.mappings) {
if (fullPath.startsWith(_fullPath + '/')) {
urlPath = path.join(_urlPath, fullPath.substring(_fullPath.length + '/'.length));
break;
}
}
if (!urlPath) {
throw new Error(`${pluginName}: toUrlPath(): "${fullPath}" cannot be mapped to URL`);
}
return urlPath;
};
return () => gulp.src(require(path.resolve(configPath, 'targets.js')).targets(targetConfig), { base: targetConfig.path.base })
.pipe(through.obj(
function (file, enc, callback) {
if (file.contents) {
let hash = createHash('sha256');
hash.update(file.contents);
let digest = hash.digest('base64');
files.push([toUrlPath(file.path), digest]);
}
callback(null, null);
},
function (callback) {
integrity.version = targetConfig['get-version'].version;
files.sort((a, b) => a[0].localeCompare(b[0]));
for (let file of files) {
integrity[file[0]] = file[1];
}
//console.log(JSON.stringify(integrity, null, 2));
this.push(new File({
cwd: targetConfig.path.base,
base: targetConfig.path.base,
path: integrityJSONPath,
contents: Buffer.from(JSON.stringify(integrity, null, 2)),
}));
callback();
}
))
.pipe(gulp.dest(targetConfig.path.base));
}

module.exports = {
configurator,
name: pluginName,
dependencies: [ 'get-version' ],
};

0 comments on commit cf76821

Please sign in to comment.