From 1069f61284a571614ee4acdde6e6087174be118a Mon Sep 17 00:00:00 2001 From: Alexander Akait <4567934+alexander-akait@users.noreply.github.com> Date: Fri, 29 Oct 2021 16:46:26 +0300 Subject: [PATCH 1/8] fix: md4 support on Node.js v17 (#193) --- .github/workflows/nodejs.yml | 82 ++++++++++++++ .travis.yml | 36 ------ appveyor.yml | 31 ------ lib/getHashDigest.js | 20 +++- lib/hash/md4.js | 20 ++++ lib/hash/wasm-hash.js | 208 +++++++++++++++++++++++++++++++++++ 6 files changed, 329 insertions(+), 68 deletions(-) create mode 100644 .github/workflows/nodejs.yml delete mode 100644 .travis.yml delete mode 100644 appveyor.yml create mode 100644 lib/hash/md4.js create mode 100644 lib/hash/wasm-hash.js diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..1a06253 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,82 @@ +name: loader-utils + +on: + push: + branches: + - master + - next + pull_request: + branches: + - master + - next + +jobs: + lint: + name: Lint - ${{ matrix.os }} - Node v${{ matrix.node-version }} + + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + strategy: + matrix: + os: [ubuntu-latest] + node-version: [12.x] + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: 'yarn' + + - name: Install dependencies + run: yarn + + - name: Lint + run: yarn lint + + - name: Security audit + run: yarn audit + + - name: Check commit message + uses: wagoid/commitlint-github-action@v4 + + test: + name: Test - ${{ matrix.os }} - Node v${{ matrix.node-version }} + + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + node-version: [8.x, 10.x, 12.x, 14.x, 16.x, 17.x] + + runs-on: ${{ matrix.os }} + + steps: + - name: Setup Git + if: matrix.os == 'windows-latest' + run: git config --global core.autocrlf input + + - uses: actions/checkout@v2 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: 'yarn' + + - name: Install dependencies + run: yarn + + - name: Run tests + run: yarn test + + - name: Submit coverage data to codecov + uses: codecov/codecov-action@v2 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8154afb..0000000 --- a/.travis.yml +++ /dev/null @@ -1,36 +0,0 @@ -sudo: false - -git: - depth: 10 - -branches: - only: - - master - -language: node_js - -cache: yarn - -matrix: - include: - - node_js: '12' - script: yarn pretest - env: CI=pretest - - node_js: '8' - script: yarn test:ci - env: CI=tests 8 - - node_js: '10' - script: yarn test:ci - env: CI=tests 10 - - node_js: '12' - script: yarn test:ci - env: CI=coverage 12 - - node_js: '13' - script: yarn test:ci - env: CI=coverage 13 - -before_install: - - yarn install --ignore-engines - -after_success: - - if [ "$CI" = "coverage" ]; then cat ./.coverage/lcov.info | ./node_modules/.bin/coveralls --verbose && rm -rf ./coverage; fi diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 64bef56..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,31 +0,0 @@ -# https://www.appveyor.com/docs/appveyor-yml - -environment: - matrix: - - nodejs_version: 8 - - nodejs_version: 10 - - nodejs_version: 12 - - nodejs_version: 13 - -clone_depth: 10 - -version: '{build}' -build: off -deploy: off - -branches: - only: - - master - -install: - - ps: Install-Product node $env:nodejs_version - - yarn install --ignore-engines - -cache: - - node_modules -> appveyor.yml,package.json,yarn.lock - - '%LOCALAPPDATA%\Yarn -> appveyor.yml,package.json,yarn.lock' - -test_script: - - node --version - - npm --version - - cmd: 'yarn test:ci' diff --git a/lib/getHashDigest.js b/lib/getHashDigest.js index 45e340e..820ae1d 100644 --- a/lib/getHashDigest.js +++ b/lib/getHashDigest.js @@ -39,11 +39,29 @@ function encodeBufferToBase(buffer, base) { return output; } +let createMd4 = undefined; + function getHashDigest(buffer, hashType, digestType, maxLength) { hashType = hashType || 'md4'; maxLength = maxLength || 9999; - const hash = require('crypto').createHash(hashType); + let hash; + + try { + hash = require('crypto').createHash(hashType); + } catch (error) { + if (error.code === 'ERR_OSSL_EVP_UNSUPPORTED' && hashType === 'md4') { + if (createMd4 === undefined) { + createMd4 = require('./hash/md4'); + } + + hash = createMd4(); + } + + if (!hash) { + throw error; + } + } hash.update(buffer); diff --git a/lib/hash/md4.js b/lib/hash/md4.js new file mode 100644 index 0000000..d4b0b55 --- /dev/null +++ b/lib/hash/md4.js @@ -0,0 +1,20 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +'use strict'; + +const create = require('./wasm-hash'); + +//#region wasm code: md4 (../../../assembly/hash/md4.asm.ts) --initialMemory 1 +const md4 = new WebAssembly.Module( + Buffer.from( + // 2150 bytes + 'AGFzbQEAAAABCAJgAX8AYAAAAwUEAQAAAAUDAQABBhoFfwFBAAt/AUEAC38BQQALfwFBAAt/AUEACwciBARpbml0AAAGdXBkYXRlAAIFZmluYWwAAwZtZW1vcnkCAAqFEAQmAEGBxpS6BiQBQYnXtv5+JAJB/rnrxXkkA0H2qMmBASQEQQAkAAvMCgEYfyMBIQojAiEGIwMhByMEIQgDQCAAIAVLBEAgBSgCCCINIAcgBiAFKAIEIgsgCCAHIAUoAgAiDCAKIAggBiAHIAhzcXNqakEDdyIDIAYgB3Nxc2pqQQd3IgEgAyAGc3FzampBC3chAiAFKAIUIg8gASACIAUoAhAiCSADIAEgBSgCDCIOIAYgAyACIAEgA3Nxc2pqQRN3IgQgASACc3FzampBA3ciAyACIARzcXNqakEHdyEBIAUoAiAiEiADIAEgBSgCHCIRIAQgAyAFKAIYIhAgAiAEIAEgAyAEc3FzampBC3ciAiABIANzcXNqakETdyIEIAEgAnNxc2pqQQN3IQMgBSgCLCIVIAQgAyAFKAIoIhQgAiAEIAUoAiQiEyABIAIgAyACIARzcXNqakEHdyIBIAMgBHNxc2pqQQt3IgIgASADc3FzampBE3chBCAPIBAgCSAVIBQgEyAFKAI4IhYgAiAEIAUoAjQiFyABIAIgBSgCMCIYIAMgASAEIAEgAnNxc2pqQQN3IgEgAiAEc3FzampBB3ciAiABIARzcXNqakELdyIDIAkgAiAMIAEgBSgCPCIJIAQgASADIAEgAnNxc2pqQRN3IgEgAiADcnEgAiADcXJqakGZ84nUBWpBA3ciAiABIANycSABIANxcmpqQZnzidQFakEFdyIEIAEgAnJxIAEgAnFyaiASakGZ84nUBWpBCXciAyAPIAQgCyACIBggASADIAIgBHJxIAIgBHFyampBmfOJ1AVqQQ13IgEgAyAEcnEgAyAEcXJqakGZ84nUBWpBA3ciAiABIANycSABIANxcmpqQZnzidQFakEFdyIEIAEgAnJxIAEgAnFyampBmfOJ1AVqQQl3IgMgECAEIAIgFyABIAMgAiAEcnEgAiAEcXJqakGZ84nUBWpBDXciASADIARycSADIARxcmogDWpBmfOJ1AVqQQN3IgIgASADcnEgASADcXJqakGZ84nUBWpBBXciBCABIAJycSABIAJxcmpqQZnzidQFakEJdyIDIBEgBCAOIAIgFiABIAMgAiAEcnEgAiAEcXJqakGZ84nUBWpBDXciASADIARycSADIARxcmpqQZnzidQFakEDdyICIAEgA3JxIAEgA3FyampBmfOJ1AVqQQV3IgQgASACcnEgASACcXJqakGZ84nUBWpBCXciAyAMIAIgAyAJIAEgAyACIARycSACIARxcmpqQZnzidQFakENdyIBcyAEc2pqQaHX5/YGakEDdyICIAQgASACcyADc2ogEmpBodfn9gZqQQl3IgRzIAFzampBodfn9gZqQQt3IgMgAiADIBggASADIARzIAJzampBodfn9gZqQQ93IgFzIARzaiANakGh1+f2BmpBA3ciAiAUIAQgASACcyADc2pqQaHX5/YGakEJdyIEcyABc2pqQaHX5/YGakELdyIDIAsgAiADIBYgASADIARzIAJzampBodfn9gZqQQ93IgFzIARzampBodfn9gZqQQN3IgIgEyAEIAEgAnMgA3NqakGh1+f2BmpBCXciBHMgAXNqakGh1+f2BmpBC3chAyAKIA4gAiADIBcgASADIARzIAJzampBodfn9gZqQQ93IgFzIARzampBodfn9gZqQQN3IgJqIQogBiAJIAEgESADIAIgFSAEIAEgAnMgA3NqakGh1+f2BmpBCXciBHMgAXNqakGh1+f2BmpBC3ciAyAEcyACc2pqQaHX5/YGakEPd2ohBiADIAdqIQcgBCAIaiEIIAVBQGshBQwBCwsgCiQBIAYkAiAHJAMgCCQECw0AIAAQASMAIABqJAAL/wQCA38BfiMAIABqrUIDhiEEIABByABqQUBxIgJBCGshAyAAIgFBAWohACABQYABOgAAA0AgACACSUEAIABBB3EbBEAgAEEAOgAAIABBAWohAAwBCwsDQCAAIAJJBEAgAEIANwMAIABBCGohAAwBCwsgAyAENwMAIAIQAUEAIwGtIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAEEIIwKtIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAEEQIwOtIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAEEYIwStIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAAs=', + 'base64' + ) +); +//#endregion + +module.exports = create.bind(null, md4, [], 64, 32); diff --git a/lib/hash/wasm-hash.js b/lib/hash/wasm-hash.js new file mode 100644 index 0000000..c2c2bd6 --- /dev/null +++ b/lib/hash/wasm-hash.js @@ -0,0 +1,208 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +'use strict'; + +// 65536 is the size of a wasm memory page +// 64 is the maximum chunk size for every possible wasm hash implementation +// 4 is the maximum number of bytes per char for string encoding (max is utf-8) +// ~3 makes sure that it's always a block of 4 chars, so avoid partially encoded bytes for base64 +const MAX_SHORT_STRING = Math.floor((65536 - 64) / 4) & ~3; + +class WasmHash { + /** + * @param {WebAssembly.Instance} instance wasm instance + * @param {WebAssembly.Instance[]} instancesPool pool of instances + * @param {number} chunkSize size of data chunks passed to wasm + * @param {number} digestSize size of digest returned by wasm + */ + constructor(instance, instancesPool, chunkSize, digestSize) { + const exports = /** @type {any} */ (instance.exports); + + exports.init(); + + this.exports = exports; + this.mem = Buffer.from(exports.memory.buffer, 0, 65536); + this.buffered = 0; + this.instancesPool = instancesPool; + this.chunkSize = chunkSize; + this.digestSize = digestSize; + } + + reset() { + this.buffered = 0; + this.exports.init(); + } + + /** + * @param {Buffer | string} data data + * @param {BufferEncoding=} encoding encoding + * @returns {this} itself + */ + update(data, encoding) { + if (typeof data === 'string') { + while (data.length > MAX_SHORT_STRING) { + this._updateWithShortString(data.slice(0, MAX_SHORT_STRING), encoding); + data = data.slice(MAX_SHORT_STRING); + } + + this._updateWithShortString(data, encoding); + + return this; + } + + this._updateWithBuffer(data); + + return this; + } + + /** + * @param {string} data data + * @param {BufferEncoding=} encoding encoding + * @returns {void} + */ + _updateWithShortString(data, encoding) { + const { exports, buffered, mem, chunkSize } = this; + + let endPos; + + if (data.length < 70) { + if (!encoding || encoding === 'utf-8' || encoding === 'utf8') { + endPos = buffered; + for (let i = 0; i < data.length; i++) { + const cc = data.charCodeAt(i); + + if (cc < 0x80) { + mem[endPos++] = cc; + } else if (cc < 0x800) { + mem[endPos] = (cc >> 6) | 0xc0; + mem[endPos + 1] = (cc & 0x3f) | 0x80; + endPos += 2; + } else { + // bail-out for weird chars + endPos += mem.write(data.slice(endPos), endPos, encoding); + break; + } + } + } else if (encoding === 'latin1') { + endPos = buffered; + + for (let i = 0; i < data.length; i++) { + const cc = data.charCodeAt(i); + + mem[endPos++] = cc; + } + } else { + endPos = buffered + mem.write(data, buffered, encoding); + } + } else { + endPos = buffered + mem.write(data, buffered, encoding); + } + + if (endPos < chunkSize) { + this.buffered = endPos; + } else { + const l = endPos & ~(this.chunkSize - 1); + + exports.update(l); + + const newBuffered = endPos - l; + + this.buffered = newBuffered; + + if (newBuffered > 0) { + mem.copyWithin(0, l, endPos); + } + } + } + + /** + * @param {Buffer} data data + * @returns {void} + */ + _updateWithBuffer(data) { + const { exports, buffered, mem } = this; + const length = data.length; + + if (buffered + length < this.chunkSize) { + data.copy(mem, buffered, 0, length); + + this.buffered += length; + } else { + const l = (buffered + length) & ~(this.chunkSize - 1); + + if (l > 65536) { + let i = 65536 - buffered; + + data.copy(mem, buffered, 0, i); + exports.update(65536); + + const stop = l - buffered - 65536; + + while (i < stop) { + data.copy(mem, 0, i, i + 65536); + exports.update(65536); + i += 65536; + } + + data.copy(mem, 0, i, l - buffered); + + exports.update(l - buffered - i); + } else { + data.copy(mem, buffered, 0, l - buffered); + + exports.update(l); + } + + const newBuffered = length + buffered - l; + + this.buffered = newBuffered; + + if (newBuffered > 0) { + data.copy(mem, 0, length - newBuffered, length); + } + } + } + + digest(type) { + const { exports, buffered, mem, digestSize } = this; + + exports.final(buffered); + + this.instancesPool.push(this); + + const hex = mem.toString('latin1', 0, digestSize); + + if (type === 'hex') { + return hex; + } + + if (type === 'binary' || !type) { + return Buffer.from(hex, 'hex'); + } + + return Buffer.from(hex, 'hex').toString(type); + } +} + +const create = (wasmModule, instancesPool, chunkSize, digestSize) => { + if (instancesPool.length > 0) { + const old = instancesPool.pop(); + + old.reset(); + + return old; + } else { + return new WasmHash( + new WebAssembly.Instance(wasmModule), + instancesPool, + chunkSize, + digestSize + ); + } +}; + +module.exports = create; +module.exports.MAX_SHORT_STRING = MAX_SHORT_STRING; From 5fb556208426d281a18dfbf6f45dca24bfb24e96 Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Fri, 29 Oct 2021 16:46:53 +0300 Subject: [PATCH 2/8] chore(release): 2.0.1 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ccf892..14b41a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [2.0.1](https://github.com/webpack/loader-utils/compare/v2.0.0...v2.0.1) (2021-10-29) + + +### Bug Fixes + +* md4 support on Node.js v17 ([#193](https://github.com/webpack/loader-utils/issues/193)) ([1069f61](https://github.com/webpack/loader-utils/commit/1069f61284a571614ee4acdde6e6087174be118a)) + ## [2.0.0](https://github.com/webpack/loader-utils/compare/v1.4.0...v2.0.0) (2020-03-17) diff --git a/package.json b/package.json index 01eb90e..7648bee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loader-utils", - "version": "2.0.0", + "version": "2.0.1", "author": "Tobias Koppers @sokra", "description": "utils for webpack loaders", "dependencies": { From 8c2d24ee400bc4567335e97ee6004c3baa6ef66f Mon Sep 17 00:00:00 2001 From: Alexander Akait <4567934+alexander-akait@users.noreply.github.com> Date: Thu, 4 Nov 2021 18:05:31 +0300 Subject: [PATCH 3/8] fix: base64 generation and unicode characters (#197) --- lib/getHashDigest.js | 10 ++++-- lib/hash/BatchedHash.js | 64 ++++++++++++++++++++++++++++++++++++ lib/hash/wasm-hash.js | 2 +- test/getHashDigest.test.js | 4 +-- test/interpolateName.test.js | 10 +++--- 5 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 lib/hash/BatchedHash.js diff --git a/lib/getHashDigest.js b/lib/getHashDigest.js index 820ae1d..7098f06 100644 --- a/lib/getHashDigest.js +++ b/lib/getHashDigest.js @@ -40,6 +40,7 @@ function encodeBufferToBase(buffer, base) { } let createMd4 = undefined; +let BatchedHash = undefined; function getHashDigest(buffer, hashType, digestType, maxLength) { hashType = hashType || 'md4'; @@ -53,9 +54,13 @@ function getHashDigest(buffer, hashType, digestType, maxLength) { if (error.code === 'ERR_OSSL_EVP_UNSUPPORTED' && hashType === 'md4') { if (createMd4 === undefined) { createMd4 = require('./hash/md4'); + + if (BatchedHash === undefined) { + BatchedHash = require('./hash/BatchedHash'); + } } - hash = createMd4(); + hash = new BatchedHash(createMd4()); } if (!hash) { @@ -72,8 +77,7 @@ function getHashDigest(buffer, hashType, digestType, maxLength) { digestType === 'base49' || digestType === 'base52' || digestType === 'base58' || - digestType === 'base62' || - digestType === 'base64' + digestType === 'base62' ) { return encodeBufferToBase(hash.digest(), digestType.substr(4)).substr( 0, diff --git a/lib/hash/BatchedHash.js b/lib/hash/BatchedHash.js new file mode 100644 index 0000000..6ec6a44 --- /dev/null +++ b/lib/hash/BatchedHash.js @@ -0,0 +1,64 @@ +const MAX_SHORT_STRING = require('./wasm-hash').MAX_SHORT_STRING; + +class BatchedHash { + constructor(hash) { + this.string = undefined; + this.encoding = undefined; + this.hash = hash; + } + + /** + * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding} + * @param {string|Buffer} data data + * @param {string=} inputEncoding data encoding + * @returns {this} updated hash + */ + update(data, inputEncoding) { + if (this.string !== undefined) { + if ( + typeof data === 'string' && + inputEncoding === this.encoding && + this.string.length + data.length < MAX_SHORT_STRING + ) { + this.string += data; + + return this; + } + + this.hash.update(this.string, this.encoding); + this.string = undefined; + } + + if (typeof data === 'string') { + if ( + data.length < MAX_SHORT_STRING && + // base64 encoding is not valid since it may contain padding chars + (!inputEncoding || !inputEncoding.startsWith('ba')) + ) { + this.string = data; + this.encoding = inputEncoding; + } else { + this.hash.update(data, inputEncoding); + } + } else { + this.hash.update(data); + } + + return this; + } + + /** + * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding} + * @param {string=} encoding encoding of the return value + * @returns {string|Buffer} digest + */ + digest(encoding) { + if (this.string !== undefined) { + this.hash.update(this.string, this.encoding); + } + + return this.hash.digest(encoding); + } +} + +module.exports = BatchedHash; diff --git a/lib/hash/wasm-hash.js b/lib/hash/wasm-hash.js index c2c2bd6..d8f2817 100644 --- a/lib/hash/wasm-hash.js +++ b/lib/hash/wasm-hash.js @@ -82,7 +82,7 @@ class WasmHash { endPos += 2; } else { // bail-out for weird chars - endPos += mem.write(data.slice(endPos), endPos, encoding); + endPos += mem.write(data.slice(i), endPos, encoding); break; } } diff --git a/test/getHashDigest.test.js b/test/getHashDigest.test.js index 28f2fc3..9fa1355 100644 --- a/test/getHashDigest.test.js +++ b/test/getHashDigest.test.js @@ -12,7 +12,7 @@ describe('getHashDigest()', () => { '6f8db599de986fab7a21625b7916589c', ], ['test string', 'md5', 'hex', 4, '6f8d'], - ['test string', 'md5', 'base64', undefined, '2sm1pVmS8xuGJLCdWpJoRL'], + ['test string', 'md5', 'base64', undefined, 'b421md6Yb6t6IWJbeRZYnA=='], ['test string', 'md5', 'base52', undefined, 'dJnldHSAutqUacjgfBQGLQx'], ['test string', 'md5', 'base26', 6, 'bhtsgu'], [ @@ -20,7 +20,7 @@ describe('getHashDigest()', () => { 'sha512', 'base64', undefined, - '2IS-kbfIPnVflXb9CzgoNESGCkvkb0urMmucPD9z8q6HuYz8RShY1-tzSUpm5-Ivx_u4H1MEzPgAhyhaZ7RKog', + 'EObWR69EYkRC84jCwUp4f/ixfmFluD12fsBHdo2MvLcaGjIm58x4Frx5wEJ9lKnaaIxBo5kse/Xk18w+C+XbrA==', ], [ 'test string', diff --git a/test/interpolateName.test.js b/test/interpolateName.test.js index c56e298..4ed7c5b 100644 --- a/test/interpolateName.test.js +++ b/test/interpolateName.test.js @@ -62,13 +62,13 @@ describe('interpolateName()', () => { '/app/img/image.png', '[sha512:hash:base64:7].[ext]', 'test content', - '2BKDTjl.png', + 'DL9MrvO.png', ], [ '/app/img/image.png', '[sha512:contenthash:base64:7].[ext]', 'test content', - '2BKDTjl.png', + 'DL9MrvO.png', ], [ '/app/dir/file.png', @@ -116,13 +116,13 @@ describe('interpolateName()', () => { '/lib/components/modal/modal.css', '[name].[md5:hash:base64:20].[ext]', 'test content', - 'modal.1n8osQznuT8jOAwdzg_n.css', + 'modal.lHP90NiApDwht3eNNIch.css', ], [ '/lib/components/modal/modal.css', '[name].[md5:contenthash:base64:20].[ext]', 'test content', - 'modal.1n8osQznuT8jOAwdzg_n.css', + 'modal.lHP90NiApDwht3eNNIch.css', ], // Should not interpret without `hash` or `contenthash` [ @@ -265,7 +265,7 @@ describe('interpolateName()', () => { ], [ [{}, '[hash:base64]', { content: 'test string' }], - '2LIG3oc1uBNmwOoL7kXgoK', + 'Lgbt1PFiMmjFpRcw2KCyrw==', 'should interpolate [hash] token with options', ], [ From 90c7c4be17e3e0b2f6091a69c67db7a6df9fd044 Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Thu, 4 Nov 2021 18:06:58 +0300 Subject: [PATCH 4/8] chore(release): 2.0.2 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14b41a4..60f15e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [2.0.2](https://github.com/webpack/loader-utils/compare/v2.0.1...v2.0.2) (2021-11-04) + + +### Bug Fixes + +* base64 generation and unicode characters ([#197](https://github.com/webpack/loader-utils/issues/197)) ([8c2d24e](https://github.com/webpack/loader-utils/commit/8c2d24ee400bc4567335e97ee6004c3baa6ef66f)) + ### [2.0.1](https://github.com/webpack/loader-utils/compare/v2.0.0...v2.0.1) (2021-10-29) diff --git a/package.json b/package.json index 7648bee..7c357c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loader-utils", - "version": "2.0.1", + "version": "2.0.2", "author": "Tobias Koppers @sokra", "description": "utils for webpack loaders", "dependencies": { From a93cf6f4702012030f6b5ee8340d5c95ec1c7d4c Mon Sep 17 00:00:00 2001 From: Mike Cebrian Date: Thu, 20 Oct 2022 15:54:33 -0400 Subject: [PATCH 5/8] fix(security): prototype polution exploit (#217) --- lib/parseQuery.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/parseQuery.js b/lib/parseQuery.js index fdca007..4a201a2 100644 --- a/lib/parseQuery.js +++ b/lib/parseQuery.js @@ -26,7 +26,7 @@ function parseQuery(query) { } const queryArgs = query.split(/[,&]/g); - const result = {}; + const result = Object.create(null); queryArgs.forEach((arg) => { const idx = arg.indexOf('='); From 7162619fb982c394ed75098a0a0ed7e7f3177c70 Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Thu, 20 Oct 2022 22:58:39 +0300 Subject: [PATCH 6/8] chore(release): 2.0.3 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60f15e7..ae27c68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [2.0.3](https://github.com/webpack/loader-utils/compare/v2.0.1...v2.0.3) (2022-10-20) + + +### Bug Fixes + +* **security:** prototype pollution exploit ([#217](https://github.com/webpack/loader-utils/issues/217)) ([a93cf6f](https://github.com/webpack/loader-utils/commit/a93cf6f4702012030f6b5ee8340d5c95ec1c7d4c)) + ### [2.0.2](https://github.com/webpack/loader-utils/compare/v2.0.1...v2.0.2) (2021-11-04) diff --git a/package.json b/package.json index 7c357c9..7c597b7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loader-utils", - "version": "2.0.2", + "version": "2.0.3", "author": "Tobias Koppers @sokra", "description": "utils for webpack loaders", "dependencies": { From ac09944dfacd7c4497ef692894b09e63e09a5eeb Mon Sep 17 00:00:00 2001 From: Alexander Akait <4567934+alexander-akait@users.noreply.github.com> Date: Fri, 11 Nov 2022 03:28:59 +0300 Subject: [PATCH 7/8] fix: ReDoS problem (#225) --- lib/interpolateName.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/interpolateName.js b/lib/interpolateName.js index 6a13a36..0cd3932 100644 --- a/lib/interpolateName.js +++ b/lib/interpolateName.js @@ -108,7 +108,7 @@ function interpolateName(loaderContext, name, options) { // `hash` and `contenthash` are same in `loader-utils` context // let's keep `hash` for backward compatibility .replace( - /\[(?:([^:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*))?(?::(\d+))?\]/gi, + /\[(?:([^[:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*))?(?::(\d+))?\]/gi, (all, hashType, digestType, maxLength) => getHashDigest(content, hashType, digestType, parseInt(maxLength, 10)) ) From 6688b5028106f144ee9f543bebc8e6a87b57829f Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Fri, 11 Nov 2022 03:29:35 +0300 Subject: [PATCH 8/8] chore(release): 2.0.4 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae27c68..4465ab5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [2.0.4](https://github.com/webpack/loader-utils/compare/v2.0.3...v2.0.4) (2022-11-11) + + +### Bug Fixes + +* ReDoS problem ([#225](https://github.com/webpack/loader-utils/issues/225)) ([ac09944](https://github.com/webpack/loader-utils/commit/ac09944dfacd7c4497ef692894b09e63e09a5eeb)) + ### [2.0.3](https://github.com/webpack/loader-utils/compare/v2.0.1...v2.0.3) (2022-10-20) diff --git a/package.json b/package.json index 7c597b7..b2c7b48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loader-utils", - "version": "2.0.3", + "version": "2.0.4", "author": "Tobias Koppers @sokra", "description": "utils for webpack loaders", "dependencies": {