@localnerve/csp-hashes 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Return a Vinyl transform object stream to process html files for
5
5
  * generating the required CSP hashes for inline and attribute scripts, styles.
6
6
  *
7
- * Copyright (c) 2022 Alex Grant (@localnerve), LocalNerve LLC
7
+ * Copyright (c) 2022-2023 Alex Grant (@localnerve), LocalNerve LLC
8
8
  * Licensed under the MIT license.
9
9
  */
10
10
  /* eslint-env node */
package/lib/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Return a Vinyl transform object stream to process html files for
5
5
  * generating the required CSP hashes for inline and attribute scripts, styles.
6
6
  *
7
- * Copyright (c) 2022 Alex Grant (@localnerve), LocalNerve LLC
7
+ * Copyright (c) 2022-2023 Alex Grant (@localnerve), LocalNerve LLC
8
8
  * Licensed under the MIT license.
9
9
  */
10
10
  import { Transform } from 'stream';
@@ -4,7 +4,7 @@
4
4
  * A convenience method to remove the content of a Content-Security-Policy in a meta tag.
5
5
  * Useful for development builds that need to ignore CSP meta tags.
6
6
  *
7
- * Copyright (c) 2022 Alex Grant (@localnerve), LocalNerve LLC
7
+ * Copyright (c) 2022-2023 Alex Grant (@localnerve), LocalNerve LLC
8
8
  * Licensed under the MIT license.
9
9
  */
10
10
  import { Transform } from 'stream';
package/license.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2022, Alex Grant, LocalNerve, LLC
1
+ Copyright 2022-2023, Alex Grant, LocalNerve, LLC
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
package/package.json CHANGED
@@ -1,31 +1,24 @@
1
1
  {
2
2
  "name": "@localnerve/csp-hashes",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Flexible library to generate CSP hashes",
5
- "main": "dist/index.js",
5
+ "main": "index.js",
6
6
  "type": "module",
7
7
  "exports": {
8
- "import": "./dist/index.js",
9
- "require": "./dist/cjs/index.js",
10
- "default": "./dist/index.js"
8
+ "import": "./index.js",
9
+ "default": "./index.js"
11
10
  },
12
11
  "scripts": {
13
12
  "lint": "eslint .",
14
- "transpile": "babel --out-dir ./dist/cjs index.js && babel --out-dir ./dist/cjs/lib ./lib",
15
- "preprepublishOnly": "rimraf ./dist && npm run transpile",
16
- "prepublishOnly": "node -e 'require(\"fs\").copyFileSync(\"./index.js\", \"./dist/index.js\");'",
17
- "postprepublishOnly": "node -e 'require(\"fs\").cpSync(\"./lib\", \"./dist/lib\", {recursive: true});'",
18
13
  "pretest": "node -e 'try{require(\"fs\").symlinkSync(\"../lib\", \"./__tests__/lib\");}catch(e){}'",
19
14
  "test": "jest",
20
15
  "test:debug": "node --inspect-brk ./node_modules/.bin/jest"
21
16
  },
22
17
  "devDependencies": {
23
- "@babel/cli": "^7.19.3",
24
18
  "@babel/preset-env": "^7.20.2",
25
- "eslint": "^8.30.0",
26
- "jest": "^29.3.1",
27
- "rimraf": "^3.0.2",
28
- "vinyl": "^2.2.1"
19
+ "eslint": "^8.33.0",
20
+ "jest": "^29.4.1",
21
+ "vinyl": "^3.0.0"
29
22
  },
30
23
  "dependencies": {
31
24
  "cheerio": "^1.0.0-rc.12"
package/readme.md CHANGED
@@ -8,6 +8,7 @@
8
8
 
9
9
  ## Contents
10
10
  + [Overview](#overview)
11
+ + [Breaking Changes](#breaking-changes)
11
12
  + [API](#API)
12
13
  + [Options](#options)
13
14
  + [Callback Function](#callback-function)
@@ -15,11 +16,15 @@
15
16
  + [Example Usage](#example-usage)
16
17
  + [CSP Headers](#build-step-to-maintain-csp-headers)
17
18
  + [Meta Tag](#build-step-to-maintain-csp-meta-tags)
19
+ + [Non-Esm Usage](#non-esm-usage)
18
20
  + [MIT License](#license)
19
21
 
20
22
  ## Overview
21
23
  This Nodejs library generates script and style inline element and attribute hashes. It is for use in the generation of HTTP content security policy (CSP) headers or to replace/update Meta tags as a website build step. Ready for use with [Gulp](https://github.com/gulpjs/gulp).
22
24
 
25
+ ## Breaking Changes
26
+ + As of Version 2+, this is an ES Module. See [Non-Esm Usage](#non-esm-usage) for how to use outside of ESM.
27
+
23
28
  ## Prerequisites
24
29
  + NodeJS 14+
25
30
 
@@ -154,6 +159,19 @@ export function stripCspMetaContents (settings) {
154
159
  }
155
160
  ```
156
161
 
162
+ ### Non-ESM usage
163
+ As of Version 2, this package is an ES Module, making it incompatible with `require`. To use outside of ESM, you can use this with a dynamic import as in the following example:
164
+
165
+ ```javascript
166
+ import('@localnerve/csp-hashes').then(({ hashstream }) => {
167
+ hashstream({
168
+ callback: (p, hashes, contents) => {
169
+ // do stuff
170
+ }
171
+ });
172
+ });
173
+ ```
174
+
157
175
  ## LICENSE
158
176
 
159
177
  * [MIT, Alex Grant, LocalNerve, LLC](license.md)
package/dist/cjs/index.js DELETED
@@ -1,24 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "default", {
7
- enumerable: true,
8
- get: function () {
9
- return _index.hashstream;
10
- }
11
- });
12
- Object.defineProperty(exports, "hashstream", {
13
- enumerable: true,
14
- get: function () {
15
- return _index.hashstream;
16
- }
17
- });
18
- Object.defineProperty(exports, "removeCspMeta", {
19
- enumerable: true,
20
- get: function () {
21
- return _index.removeCspMeta;
22
- }
23
- });
24
- var _index = require("./lib/index.js");
@@ -1,111 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = exports.hashstream = hashstream;
7
- Object.defineProperty(exports, "removeCspMeta", {
8
- enumerable: true,
9
- get: function () {
10
- return _removeCspMeta.removeCspMeta;
11
- }
12
- });
13
- var _stream = require("stream");
14
- var _crypto = _interopRequireDefault(require("crypto"));
15
- var _cheerio = _interopRequireDefault(require("cheerio"));
16
- var _removeCspMeta = require("./removeCspMeta.js");
17
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
- /**
19
- * CSP Hashes.
20
- *
21
- * Return a Vinyl transform object stream to process html files for
22
- * generating the required CSP hashes for inline and attribute scripts, styles.
23
- *
24
- * Copyright (c) 2022 Alex Grant (@localnerve), LocalNerve LLC
25
- * Licensed under the MIT license.
26
- */
27
-
28
- /**
29
- * Collect all CSP Hashes and fill the given `hashes` structure.
30
- *
31
- * @param {Function} hashFn - Creates and formats a csp hash
32
- * @param {Buffer} html - The html content
33
- * @param {Object} hashes - The hash structure to fill
34
- */
35
- function collectHashes(hashFn, html, hashes) {
36
- const $ = _cheerio.default.load(html);
37
- Object.keys(hashes).forEach(what => {
38
- hashes[what].elements = $(`${what}:not([src])`).map((i, el) => hashFn($(el).html())).toArray();
39
- });
40
- hashes.style.attributes.push(...$('[style]').map((i, el) => hashFn($(el).attr('style'))).toArray());
41
- const eventHandlerRe = /^on/i;
42
- const jsUrlRe = /^javascript:/i;
43
- $('*').each(function (i, el) {
44
- for (const attrName in el.attribs) {
45
- if (eventHandlerRe.test(attrName)) {
46
- hashes.script.attributes.push(hashFn(el.attribs[attrName]));
47
- }
48
- if (jsUrlRe.test(el.attribs[attrName])) {
49
- hashes.script.attributes.push(hashFn(el.attribs[attrName].split(jsUrlRe)[1]));
50
- }
51
- }
52
- });
53
- }
54
-
55
- /**
56
- * hashstream
57
- * Accepts the processing options and returns the Vinyl transform object stream.
58
- *
59
- * @param {Object} options
60
- * @param {Function} options.callback - Function to call to process the csp hashes.
61
- * @param {String} [options.algo] - hash algorithm, default sha256. Can be sha384, sha512.
62
- * @param {Boolean} [options.replace] - True if callback is used for meta html replacements, defaults to false.
63
- * @returns Transform object stream to process Vinyl objects.
64
- */
65
- function hashstream({
66
- algo = 'sha256',
67
- replace = false,
68
- callback = null
69
- } = {}) {
70
- if (!/^sha(256|384|512)$/.test(algo)) {
71
- throw new Error('algo option must be one of "sha256", "sha384", or "sha512" only.');
72
- }
73
- if (typeof callback !== 'function') {
74
- throw new Error('callback option must be a valid function.');
75
- }
76
- const createHash = r => _crypto.default.createHash(algo).update(r).digest('base64');
77
- const formatHash = h => `'${algo}-${h}'`;
78
- const makeCSPHash = s => formatHash(createHash(s));
79
- const transformObjectStream = new _stream.Transform({
80
- objectMode: true,
81
- transform: (vinyl, enc, done) => {
82
- const path = vinyl.path;
83
- const content = vinyl.contents;
84
- const hashes = {
85
- script: {
86
- elements: [],
87
- attributes: [],
88
- get all() {
89
- return this.elements.concat(this.attributes);
90
- }
91
- },
92
- style: {
93
- elements: [],
94
- attributes: [],
95
- get all() {
96
- return this.elements.concat(this.attributes);
97
- }
98
- }
99
- };
100
- collectHashes(makeCSPHash, content, hashes);
101
- if (replace) {
102
- const s = callback(path, hashes, content.toString());
103
- vinyl.contents = Buffer.from(s, enc);
104
- } else {
105
- callback(path, hashes);
106
- }
107
- done(null, vinyl);
108
- }
109
- });
110
- return transformObjectStream;
111
- }
@@ -1,35 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = exports.removeCspMeta = removeCspMeta;
7
- var _stream = require("stream");
8
- /**
9
- * removeCspMeta.js
10
- *
11
- * A convenience method to remove the content of a Content-Security-Policy in a meta tag.
12
- * Useful for development builds that need to ignore CSP meta tags.
13
- *
14
- * Copyright (c) 2022 Alex Grant (@localnerve), LocalNerve LLC
15
- * Licensed under the MIT license.
16
- */
17
-
18
- function removeCspMeta() {
19
- return new _stream.Transform({
20
- objectMode: true,
21
- transform: (vinyl, enc, done) => {
22
- var _vinyl$contents;
23
- let e = null;
24
- const input = vinyl === null || vinyl === void 0 ? void 0 : (_vinyl$contents = vinyl.contents) === null || _vinyl$contents === void 0 ? void 0 : _vinyl$contents.toString();
25
- if (input) {
26
- const output = input.replace(/("?Content-Security-Policy"?)(\s+)(content=")([^"]+)"/i, '$1$2$3$2"');
27
- vinyl.contents = Buffer.from(output, enc);
28
- } else {
29
- e = new Error('removeCspMeta could not get Vinyl object file contents');
30
- e.errorCode = 'EBADINPUT';
31
- }
32
- done(e, vinyl);
33
- }
34
- });
35
- }
package/dist/index.js DELETED
@@ -1,11 +0,0 @@
1
- /**
2
- * CSP Hashes.
3
- *
4
- * Return a Vinyl transform object stream to process html files for
5
- * generating the required CSP hashes for inline and attribute scripts, styles.
6
- *
7
- * Copyright (c) 2022 Alex Grant (@localnerve), LocalNerve LLC
8
- * Licensed under the MIT license.
9
- */
10
- /* eslint-env node */
11
- export { hashstream as default, hashstream, removeCspMeta } from './lib/index.js';
package/dist/lib/index.js DELETED
@@ -1,121 +0,0 @@
1
- /**
2
- * CSP Hashes.
3
- *
4
- * Return a Vinyl transform object stream to process html files for
5
- * generating the required CSP hashes for inline and attribute scripts, styles.
6
- *
7
- * Copyright (c) 2022 Alex Grant (@localnerve), LocalNerve LLC
8
- * Licensed under the MIT license.
9
- */
10
- import { Transform } from 'stream';
11
- import crypto from 'crypto';
12
- import cheerio from 'cheerio';
13
- export { removeCspMeta } from './removeCspMeta.js';
14
-
15
- /**
16
- * Collect all CSP Hashes and fill the given `hashes` structure.
17
- *
18
- * @param {Function} hashFn - Creates and formats a csp hash
19
- * @param {Buffer} html - The html content
20
- * @param {Object} hashes - The hash structure to fill
21
- */
22
- function collectHashes (hashFn, html, hashes) {
23
- const $ = cheerio.load(html);
24
-
25
- Object.keys(hashes).forEach(what => {
26
- hashes[what].elements = $(`${what}:not([src])`).map(
27
- (i, el) => hashFn($(el).html())
28
- ).toArray();
29
- });
30
-
31
- hashes.style.attributes.push(
32
- ...$('[style]').map((i, el) => hashFn($(el).attr('style'))).toArray()
33
- );
34
-
35
- const eventHandlerRe = /^on/i;
36
- const jsUrlRe = /^javascript:/i;
37
-
38
- $('*').each(function (i, el) {
39
- for (const attrName in el.attribs) {
40
- if (eventHandlerRe.test(attrName)) {
41
- hashes.script.attributes.push(
42
- hashFn(el.attribs[attrName])
43
- );
44
- }
45
- if (jsUrlRe.test(el.attribs[attrName])) {
46
- hashes.script.attributes.push(
47
- hashFn(el.attribs[attrName].split(jsUrlRe)[1])
48
- );
49
- }
50
- }
51
- });
52
- }
53
-
54
- /**
55
- * hashstream
56
- * Accepts the processing options and returns the Vinyl transform object stream.
57
- *
58
- * @param {Object} options
59
- * @param {Function} options.callback - Function to call to process the csp hashes.
60
- * @param {String} [options.algo] - hash algorithm, default sha256. Can be sha384, sha512.
61
- * @param {Boolean} [options.replace] - True if callback is used for meta html replacements, defaults to false.
62
- * @returns Transform object stream to process Vinyl objects.
63
- */
64
- export function hashstream ({
65
- algo = 'sha256',
66
- replace = false,
67
- callback = null
68
- } = {}) {
69
-
70
- if (!/^sha(256|384|512)$/.test(algo)) {
71
- throw new Error('algo option must be one of "sha256", "sha384", or "sha512" only.');
72
- }
73
-
74
- if (typeof callback !== 'function') {
75
- throw new Error('callback option must be a valid function.');
76
- }
77
-
78
- const createHash = r => crypto.createHash(algo).update(r).digest('base64');
79
- const formatHash = h => `'${algo}-${h}'`;
80
- const makeCSPHash = s => formatHash(createHash(s));
81
-
82
- const transformObjectStream = new Transform({
83
- objectMode: true,
84
- transform: (vinyl, enc, done) => {
85
- const path = vinyl.path;
86
- const content = vinyl.contents;
87
-
88
- const hashes = {
89
- script: {
90
- elements: [],
91
- attributes: [],
92
- get all () {
93
- return this.elements.concat(this.attributes);
94
- }
95
- },
96
- style: {
97
- elements: [],
98
- attributes: [],
99
- get all () {
100
- return this.elements.concat(this.attributes);
101
- }
102
- }
103
- };
104
-
105
- collectHashes(makeCSPHash, content, hashes);
106
-
107
- if (replace) {
108
- const s = callback(path, hashes, content.toString());
109
- vinyl.contents = Buffer.from(s, enc);
110
- } else {
111
- callback(path, hashes);
112
- }
113
-
114
- done(null, vinyl);
115
- }
116
- });
117
-
118
- return transformObjectStream;
119
- }
120
-
121
- export { hashstream as default }
@@ -1,32 +0,0 @@
1
- /**
2
- * removeCspMeta.js
3
- *
4
- * A convenience method to remove the content of a Content-Security-Policy in a meta tag.
5
- * Useful for development builds that need to ignore CSP meta tags.
6
- *
7
- * Copyright (c) 2022 Alex Grant (@localnerve), LocalNerve LLC
8
- * Licensed under the MIT license.
9
- */
10
- import { Transform } from 'stream';
11
-
12
- export function removeCspMeta () {
13
- return new Transform({
14
- objectMode: true,
15
- transform: (vinyl, enc, done) => {
16
- let e = null;
17
- const input = vinyl?.contents?.toString();
18
- if (input) {
19
- const output = input.replace(
20
- /("?Content-Security-Policy"?)(\s+)(content=")([^"]+)"/i, '$1$2$3$2"'
21
- );
22
- vinyl.contents = Buffer.from(output, enc);
23
- } else {
24
- e = new Error('removeCspMeta could not get Vinyl object file contents');
25
- e.errorCode = 'EBADINPUT';
26
- }
27
- done(e, vinyl);
28
- }
29
- });
30
- }
31
-
32
- export { removeCspMeta as default }