diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 7915977..18db7a6 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -25,10 +25,10 @@ jobs: run: npm ci - name: Build run: source emsdk/emsdk_env.sh && ./build.sh + - name: Bundle + run: npm run build - name: Test run: npm test - - name: Bundle - run: npm run build-bundle - name: Package run: npm pack - name: Publish to npm diff --git a/README.md b/README.md index c18a323..67505df 100644 --- a/README.md +++ b/README.md @@ -77,12 +77,12 @@ npm install argon2-browser Then add this script to your HTML or use your favorite bundler: ```html - + ``` Alternatively, you can use the bundled version, this way you can include just one script: ```html - + ``` Calculate the hash: diff --git a/build-wasm.sh b/build-wasm.sh index 270616c..e461fcd 100755 --- a/build-wasm.sh +++ b/build-wasm.sh @@ -30,8 +30,3 @@ cmake --build . shasum dist/argon2.js shasum dist/argon2.wasm - -perl -pi -e 's/"argon2.js.mem"/null/g' dist/argon2.js -perl -pi -e 's/$/if(typeof module!=="undefined")module.exports=Module;Module.unloadRuntime=function(){if(typeof self!=="undefined"){delete self.Module}Module=jsModule=wasmMemory=wasmTable=asm=buffer=HEAP8=HEAPU8=HEAP16=HEAPU16=HEAP32=HEAPU32=HEAPF32=HEAPF64=undefined;if(typeof module!=="undefined"){delete module.exports}};/' dist/argon2.js -perl -pi -e 's/typeof Module!=="undefined"\?Module:\{};/typeof self!=="undefined"&&typeof self.Module!=="undefined"?self.Module:{};var jsModule=Module;/g' dist/argon2.js -perl -pi -e 's/receiveInstantiatedSource\(output\)\{/receiveInstantiatedSource(output){Module=jsModule;if(typeof self!=="undefined")self.Module=Module;/g' dist/argon2.js diff --git a/examples/vanilla/index.html b/examples/vanilla/index.html index 1785a47..e9d7ebf 100644 --- a/examples/vanilla/index.html +++ b/examples/vanilla/index.html @@ -3,7 +3,7 @@ Argon2 Browser VanillaJS Demo - +

Argon2-Browser WebPack Demo

diff --git a/lib/argon2.js b/lib/argon2.js index 98d3fb0..18568b3 100644 --- a/lib/argon2.js +++ b/lib/argon2.js @@ -1,366 +1,336 @@ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof module === 'object' && module.exports) { - module.exports = factory(); - } else { - root.argon2 = factory(); - } -})(typeof self !== 'undefined' ? self : this, function () { - const global = typeof self !== 'undefined' ? self : this; +import genModule from '../dist/argon2'; +import wasmEncoded from '../dist/argon2.wasm'; - /** - * @enum - */ - const ArgonType = { - Argon2d: 0, - Argon2i: 1, - Argon2id: 2, - }; +/** + * @enum + */ +export const ArgonType = { + Argon2d: 0, + Argon2i: 1, + Argon2id: 2, +}; - function loadModule(mem) { - if (loadModule._promise) { - return loadModule._promise; - } - if (loadModule._module) { - return Promise.resolve(loadModule._module); - } - let promise; - if ( - global.process && - global.process.versions && - global.process.versions.node - ) { - promise = loadWasmModule().then( - (Module) => - new Promise((resolve) => { - Module.postRun = () => resolve(Module); - }) - ); - } else { - promise = loadWasmBinary().then((wasmBinary) => { - const wasmMemory = mem ? createWasmMemory(mem) : undefined; - return initWasm(wasmBinary, wasmMemory); - }); - } - loadModule._promise = promise; - return promise.then((Module) => { - loadModule._module = Module; - delete loadModule._promise; - return Module; - }); +function loadModule(mem) { + if (loadModule._promise) { + return loadModule._promise; } - - function initWasm(wasmBinary, wasmMemory) { - return new Promise((resolve) => { - global.Module = { - wasmBinary, - wasmMemory, - postRun() { - resolve(Module); - }, - }; - return loadWasmModule(); + if (loadModule._module) { + return Promise.resolve(loadModule._module); + } + let promise; + if ( + !IS_WASM_INLINED && + typeof process === 'object' && + process.versions && + process.versions.node + ) { + promise = initWasm(); + } else { + promise = loadWasmBinary().then((wasmBinary) => { + const wasmMemory = mem ? createWasmMemory(mem) : undefined; + return initWasm({ wasmBinary, wasmMemory }); }); } + loadModule._promise = promise; + return promise.then((Module) => { + loadModule._module = Module; + delete loadModule._promise; + return Module; + }); +} - function loadWasmModule() { - if (global.loadArgon2WasmModule) { - return global.loadArgon2WasmModule(); - } - if (typeof require === 'function') { - return Promise.resolve(require('../dist/argon2.js')); - } - return import('../dist/argon2.js'); - } +function initWasm(options) { + const module = genModule(options); + return new Promise(resolve => { + module.postRun = () => resolve(module); + }); +} - function loadWasmBinary() { - if (global.loadArgon2WasmBinary) { - return global.loadArgon2WasmBinary(); - } - if (typeof require === 'function') { - return Promise.resolve(require('../dist/argon2.wasm')).then( - (wasmModule) => { - return decodeWasmBinary(wasmModule); - } - ); - } - const wasmPath = - global.argon2WasmPath || - 'node_modules/argon2-browser/dist/argon2.wasm'; - return fetch(wasmPath) - .then((response) => response.arrayBuffer()) - .then((ab) => new Uint8Array(ab)); +function loadWasmBinary() { + if (typeof loadArgon2WasmBinary === 'function') { + return loadArgon2WasmBinary(); + } + const _wasmEncoded = IS_WASM_INLINED + ? wasmEncoded + : typeof __non_webpack_require__ === 'function' + && __non_webpack_require__('../dist/argon2.wasm'); + if (_wasmEncoded) { + return Promise.resolve(decodeWasmBinary(_wasmEncoded)); } + const wasmPath = typeof argon2WasmPath === 'string' + ? argon2WasmPath : 'node_modules/argon2-browser/dist/argon2.wasm'; + return fetch(wasmPath) + .then((response) => response.arrayBuffer()) + .then((ab) => new Uint8Array(ab)); +} - function decodeWasmBinary(base64) { - if (typeof Buffer === 'function') { - return new Uint8Array(Buffer.from(base64, 'base64')); - } - const text = atob(base64); - const binary = new Uint8Array(new ArrayBuffer(text.length)); - for (let i = 0; i < text.length; i++) { - binary[i] = text.charCodeAt(i); - } - return binary; +function decodeWasmBinary(base64) { + if (typeof Buffer === 'function') { + return new Uint8Array(Buffer.from(base64, 'base64')); } + const text = atob(base64); + const binary = new Uint8Array(new ArrayBuffer(text.length)); + for (let i = 0; i < text.length; i++) { + binary[i] = text.charCodeAt(i); + } + return binary; +} - function createWasmMemory(mem) { - const KB = 1024; - const MB = 1024 * KB; - const GB = 1024 * MB; - const WASM_PAGE_SIZE = 64 * KB; +function createWasmMemory(mem) { + const KB = 1024; + const MB = 1024 * KB; + const GB = 1024 * MB; + const WASM_PAGE_SIZE = 64 * KB; - const totalMemory = (2 * GB - 64 * KB) / WASM_PAGE_SIZE; - const initialMemory = Math.min( - Math.max(Math.ceil((mem * KB) / WASM_PAGE_SIZE), 256) + 256, - totalMemory - ); + const totalMemory = (2 * GB - 64 * KB) / WASM_PAGE_SIZE; + const initialMemory = Math.min( + Math.max(Math.ceil((mem * KB) / WASM_PAGE_SIZE), 256) + 256, + totalMemory + ); - return new WebAssembly.Memory({ - initial: initialMemory, - maximum: totalMemory, - }); - } + return new WebAssembly.Memory({ + initial: initialMemory, + maximum: totalMemory, + }); +} - function allocateArray(Module, arr) { - return Module.allocate(arr, 'i8', Module.ALLOC_NORMAL); - } +function allocateArray(Module, arr) { + return Module.allocate(arr, 'i8', Module.ALLOC_NORMAL); +} - function allocateArrayStr(Module, arr) { - const nullTerminatedArray = new Uint8Array([...arr, 0]); - return allocateArray(Module, nullTerminatedArray); - } +function allocateArrayStr(Module, arr) { + const nullTerminatedArray = new Uint8Array([...arr, 0]); + return allocateArray(Module, nullTerminatedArray); +} - function encodeUtf8(str) { - if (typeof str !== 'string') { - return str; - } - if (typeof TextEncoder === 'function') { - return new TextEncoder().encode(str); - } else if (typeof Buffer === 'function') { - return Buffer.from(str); - } else { - throw new Error("Don't know how to encode UTF8"); - } +function encodeUtf8(str) { + if (typeof str !== 'string') { + return str; + } + if (typeof TextEncoder === 'function') { + return new TextEncoder().encode(str); + } else if (typeof Buffer === 'function') { + return Buffer.from(str); + } else { + throw new Error("Don't know how to encode UTF8"); } +} - /** - * Argon2 hash - * @param {string|Uint8Array} params.pass - password string - * @param {string|Uint8Array} params.salt - salt string - * @param {number} [params.time=1] - the number of iterations - * @param {number} [params.mem=1024] - used memory, in KiB - * @param {number} [params.hashLen=24] - desired hash length - * @param {number} [params.parallelism=1] - desired parallelism - * @param {number} [params.type=argon2.ArgonType.Argon2d] - hash type: - * argon2.ArgonType.Argon2d - * argon2.ArgonType.Argon2i - * argon2.ArgonType.Argon2id - * - * @return Promise - * - * @example - * argon2.hash({ pass: 'password', salt: 'somesalt' }) - * .then(h => console.log(h.hash, h.hashHex, h.encoded)) - * .catch(e => console.error(e.message, e.code)) - */ - function argon2Hash(params) { - const mCost = params.mem || 1024; - return loadModule(mCost).then((Module) => { - const tCost = params.time || 1; - const parallelism = params.parallelism || 1; - const pwdEncoded = encodeUtf8(params.pass); - const pwd = allocateArrayStr(Module, pwdEncoded); - const pwdlen = pwdEncoded.length; - const saltEncoded = encodeUtf8(params.salt); - const salt = allocateArrayStr(Module, saltEncoded); - const saltlen = saltEncoded.length; - const argon2Type = params.type || ArgonType.Argon2d; - const hash = Module.allocate( - new Array(params.hashLen || 24), - 'i8', - Module.ALLOC_NORMAL - ); - const secret = params.secret - ? allocateArray(Module, params.secret) - : 0; - const secretlen = params.secret ? params.secret.byteLength : 0; - const ad = params.ad ? allocateArray(Module, params.ad) : 0; - const adlen = params.ad ? params.ad.byteLength : 0; - const hashlen = params.hashLen || 24; - const encodedlen = Module._argon2_encodedlen( +/** + * Argon2 hash + * @param {string|Uint8Array} params.pass - password string + * @param {string|Uint8Array} params.salt - salt string + * @param {number} [params.time=1] - the number of iterations + * @param {number} [params.mem=1024] - used memory, in KiB + * @param {number} [params.hashLen=24] - desired hash length + * @param {number} [params.parallelism=1] - desired parallelism + * @param {number} [params.type=argon2.ArgonType.Argon2d] - hash type: + * argon2.ArgonType.Argon2d + * argon2.ArgonType.Argon2i + * argon2.ArgonType.Argon2id + * + * @return Promise + * + * @example + * argon2.hash({ pass: 'password', salt: 'somesalt' }) + * .then(h => console.log(h.hash, h.hashHex, h.encoded)) + * .catch(e => console.error(e.message, e.code)) + */ +export function hash(params) { + const mCost = params.mem || 1024; + return loadModule(mCost).then((Module) => { + const tCost = params.time || 1; + const parallelism = params.parallelism || 1; + const pwdEncoded = encodeUtf8(params.pass); + const pwd = allocateArrayStr(Module, pwdEncoded); + const pwdlen = pwdEncoded.length; + const saltEncoded = encodeUtf8(params.salt); + const salt = allocateArrayStr(Module, saltEncoded); + const saltlen = saltEncoded.length; + const argon2Type = params.type || ArgonType.Argon2d; + const hash = Module.allocate( + new Array(params.hashLen || 24), + 'i8', + Module.ALLOC_NORMAL + ); + const secret = params.secret + ? allocateArray(Module, params.secret) + : 0; + const secretlen = params.secret ? params.secret.byteLength : 0; + const ad = params.ad ? allocateArray(Module, params.ad) : 0; + const adlen = params.ad ? params.ad.byteLength : 0; + const hashlen = params.hashLen || 24; + const encodedlen = Module._argon2_encodedlen( + tCost, + mCost, + parallelism, + saltlen, + hashlen, + argon2Type + ); + const encoded = Module.allocate( + new Array(encodedlen + 1), + 'i8', + Module.ALLOC_NORMAL + ); + const version = 0x13; + let err; + let res; + try { + res = Module._argon2_hash_ext( tCost, mCost, parallelism, + pwd, + pwdlen, + salt, saltlen, + hash, hashlen, - argon2Type - ); - const encoded = Module.allocate( - new Array(encodedlen + 1), - 'i8', - Module.ALLOC_NORMAL + encoded, + encodedlen, + argon2Type, + secret, + secretlen, + ad, + adlen, + version ); - const version = 0x13; - let err; - let res; - try { - res = Module._argon2_hash_ext( - tCost, - mCost, - parallelism, - pwd, - pwdlen, - salt, - saltlen, - hash, - hashlen, - encoded, - encodedlen, - argon2Type, - secret, - secretlen, - ad, - adlen, - version - ); - } catch (e) { - err = e; - } - let result; - if (res === 0 && !err) { - let hashStr = ''; - const hashArr = new Uint8Array(hashlen); - for (let i = 0; i < hashlen; i++) { - const byte = Module.HEAP8[hash + i]; - hashArr[i] = byte; - hashStr += ('0' + (0xff & byte).toString(16)).slice(-2); - } - const encodedStr = Module.UTF8ToString(encoded); - result = { - hash: hashArr, - hashHex: hashStr, - encoded: encodedStr, - }; - } else { - try { - if (!err) { - err = Module.UTF8ToString( - Module._argon2_error_message(res) - ); - } - } catch (e) {} - result = { message: err, code: res }; + } catch (e) { + err = e; + } + let result; + if (res === 0 && !err) { + let hashStr = ''; + const hashArr = new Uint8Array(hashlen); + for (let i = 0; i < hashlen; i++) { + const byte = Module.HEAP8[hash + i]; + hashArr[i] = byte; + hashStr += ('0' + (0xff & byte).toString(16)).slice(-2); } + const encodedStr = Module.UTF8ToString(encoded); + result = { + hash: hashArr, + hashHex: hashStr, + encoded: encodedStr, + }; + } else { try { - Module._free(pwd); - Module._free(salt); - Module._free(hash); - Module._free(encoded); - if (ad) { - Module._free(ad); - } - if (secret) { - Module._free(secret); + if (!err) { + err = Module.UTF8ToString( + Module._argon2_error_message(res) + ); } } catch (e) {} - if (err) { - throw result; - } else { - return result; - } - }); - } - - /** - * Argon2 verify function - * @param {string} params.pass - password string - * @param {string|Uint8Array} params.encoded - encoded hash - * @param {number} [params.type=argon2.ArgonType.Argon2d] - hash type: - * argon2.ArgonType.Argon2d - * argon2.ArgonType.Argon2i - * argon2.ArgonType.Argon2id - * - * @returns Promise - * - * @example - * argon2.verify({ pass: 'password', encoded: 'encoded-hash' }) - * .then(() => console.log('OK')) - * .catch(e => console.error(e.message, e.code)) - */ - function argon2Verify(params) { - return loadModule().then((Module) => { - const pwdEncoded = encodeUtf8(params.pass); - const pwd = allocateArrayStr(Module, pwdEncoded); - const pwdlen = pwdEncoded.length; - const secret = params.secret - ? allocateArray(Module, params.secret) - : 0; - const secretlen = params.secret ? params.secret.byteLength : 0; - const ad = params.ad ? allocateArray(Module, params.ad) : 0; - const adlen = params.ad ? params.ad.byteLength : 0; - const encEncoded = encodeUtf8(params.encoded); - const enc = allocateArrayStr(Module, encEncoded); - let argon2Type = params.type; - if (argon2Type === undefined) { - let typeStr = params.encoded.split('$')[1]; - if (typeStr) { - typeStr = typeStr.replace('a', 'A'); - argon2Type = ArgonType[typeStr] || ArgonType.Argon2d; - } + result = { message: err, code: res }; + } + try { + Module._free(pwd); + Module._free(salt); + Module._free(hash); + Module._free(encoded); + if (ad) { + Module._free(ad); } - let err; - let res; - try { - res = Module._argon2_verify_ext( - enc, - pwd, - pwdlen, - secret, - secretlen, - ad, - adlen, - argon2Type - ); - } catch (e) { - err = e; + if (secret) { + Module._free(secret); } - let result; - if (res || err) { - try { - if (!err) { - err = Module.UTF8ToString( - Module._argon2_error_message(res) - ); - } - } catch (e) {} - result = { message: err, code: res }; + } catch (e) {} + if (err) { + throw result; + } else { + return result; + } + }); +} + +/** + * Argon2 verify function + * @param {string} params.pass - password string + * @param {string|Uint8Array} params.encoded - encoded hash + * @param {number} [params.type=argon2.ArgonType.Argon2d] - hash type: + * argon2.ArgonType.Argon2d + * argon2.ArgonType.Argon2i + * argon2.ArgonType.Argon2id + * + * @returns Promise + * + * @example + * argon2.verify({ pass: 'password', encoded: 'encoded-hash' }) + * .then(() => console.log('OK')) + * .catch(e => console.error(e.message, e.code)) + */ +export function verify(params) { + return loadModule().then((Module) => { + const pwdEncoded = encodeUtf8(params.pass); + const pwd = allocateArrayStr(Module, pwdEncoded); + const pwdlen = pwdEncoded.length; + const secret = params.secret + ? allocateArray(Module, params.secret) + : 0; + const secretlen = params.secret ? params.secret.byteLength : 0; + const ad = params.ad ? allocateArray(Module, params.ad) : 0; + const adlen = params.ad ? params.ad.byteLength : 0; + const encEncoded = encodeUtf8(params.encoded); + const enc = allocateArrayStr(Module, encEncoded); + let argon2Type = params.type; + if (argon2Type === undefined) { + let typeStr = params.encoded.split('$')[1]; + if (typeStr) { + typeStr = typeStr.replace('a', 'A'); + argon2Type = ArgonType[typeStr] || ArgonType.Argon2d; } + } + let err; + let res; + try { + res = Module._argon2_verify_ext( + enc, + pwd, + pwdlen, + secret, + secretlen, + ad, + adlen, + argon2Type + ); + } catch (e) { + err = e; + } + let result; + if (res || err) { try { - Module._free(pwd); - Module._free(enc); + if (!err) { + err = Module.UTF8ToString( + Module._argon2_error_message(res) + ); + } } catch (e) {} - if (err) { - throw result; - } else { - return result; - } - }); - } - - function unloadRuntime() { - if (loadModule._module) { - loadModule._module.unloadRuntime(); - delete loadModule._promise; - delete loadModule._module; + result = { message: err, code: res }; + } + try { + Module._free(pwd); + Module._free(enc); + } catch (e) {} + if (err) { + throw result; + } else { + return result; } + }); +} + +export function unloadRuntime() { + if (loadModule._module) { + loadModule._module.unloadRuntime(); + delete loadModule._promise; + delete loadModule._module; } +} - return { - ArgonType, - hash: argon2Hash, - verify: argon2Verify, - unloadRuntime, - }; -}); +export default { + ArgonType, + hash, + verify, + unloadRuntime, +} diff --git a/package-lock.json b/package-lock.json index f1df357..dccb8a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "argon2-browser", "version": "1.18.0", "license": "MIT", "devDependencies": { @@ -12,6 +13,7 @@ "chai": "^4.3.4", "http-server": "^0.12.3", "mocha": "^8.4.0", + "null-loader": "^4.0.1", "prettier": "^2.3.0", "puppeteer": "^9.1.1", "webpack": "^5.37.1", @@ -435,6 +437,15 @@ "node": ">= 0.6" } }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -816,6 +827,15 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -1482,6 +1502,21 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -1500,6 +1535,20 @@ "node": ">=6.11.5" } }, + "node_modules/loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1762,6 +1811,26 @@ "node": ">=8" } }, + "node_modules/null-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz", + "integrity": "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3238,6 +3307,12 @@ "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", "dev": true }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -3545,6 +3620,12 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -4051,6 +4132,15 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -4063,6 +4153,17 @@ "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", "dev": true }, + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4262,6 +4363,16 @@ "path-key": "^3.0.0" } }, + "null-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz", + "integrity": "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", diff --git a/package.json b/package.json index 51ff9b4..2ead52f 100644 --- a/package.json +++ b/package.json @@ -2,14 +2,14 @@ "name": "argon2-browser", "version": "1.18.0", "description": "Argon2 library compiled for browser runtime", - "main": "lib/argon2.js", + "main": "dist/argon2.min.js", "directories": { "doc": "docs", "lib": "lib" }, "scripts": { "test": "mocha", - "build-bundle": "webpack" + "build": "webpack" }, "repository": { "type": "git", @@ -26,6 +26,7 @@ "chai": "^4.3.4", "http-server": "^0.12.3", "mocha": "^8.4.0", + "null-loader": "^4.0.1", "prettier": "^2.3.0", "puppeteer": "^9.1.1", "webpack": "^5.37.1", diff --git a/test/node-bundled.js b/test/node-bundled.js new file mode 100644 index 0000000..f8e082e --- /dev/null +++ b/test/node-bundled.js @@ -0,0 +1,12 @@ +describe('Node.js bundled', function () { + global.chai = require('chai'); + + before(() => { + global.argon2 = require('../dist/argon2-bundled.min'); + }); + + ['./suite/hash', './suite/verify'].forEach((name) => { + delete require.cache[require.resolve(name)]; + require(name); + }); +}); diff --git a/test/node.js b/test/node.js index 8e2d58d..caa9760 100644 --- a/test/node.js +++ b/test/node.js @@ -1,7 +1,12 @@ describe('Node.js', function() { global.chai = require('chai'); - global.argon2 = require('..'); - require('./suite/hash'); - require('./suite/verify'); + before(() => { + global.argon2 = require('..'); + }); + + ['./suite/hash', './suite/verify'].forEach((name) => { + delete require.cache[require.resolve(name)]; + require(name); + }); }); diff --git a/test/vanilla/index.html b/test/vanilla/index.html index d1fb12b..7319a86 100644 --- a/test/vanilla/index.html +++ b/test/vanilla/index.html @@ -13,7 +13,7 @@ - + diff --git a/webpack.config.js b/webpack.config.js index 1117441..9b2cc3b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,7 @@ const path = require('path'); +const webpack = require('webpack'); -module.exports = { +const getConfig = (inlineWasm) => ({ mode: 'production', entry: './lib/argon2.js', output: { @@ -11,22 +12,33 @@ module.exports = { globalObject: 'this', path: path.resolve(__dirname, 'dist'), publicPath: 'dist/', - filename: 'argon2-bundled.min.js', + filename: inlineWasm ? 'argon2-bundled.min.js' : 'argon2.min.js', }, module: { noParse: /\.wasm$/, - rules: [ - { - test: /\.wasm$/, - loader: 'base64-loader', - type: 'javascript/auto', - }, - ], - }, - externals: { - path: 'path', - fs: 'fs', + rules: [{ + test: /\.wasm$/, + loader: inlineWasm ? 'base64-loader' : 'null-loader', + type: 'javascript/auto', + }, { + test: /dist\/argon2\.js$/, + use: [{ + loader: path.resolve('wrap-em.js'), + }] + }], }, + plugins: [ + new webpack.DefinePlugin({ + IS_WASM_INLINED: JSON.stringify(inlineWasm), + ...inlineWasm && { process: 'undefined' }, + }), + ], + externals: inlineWasm + ? {} + : { + path: 'path', + fs: 'fs', + }, resolve: { fallback: { path: false, @@ -35,4 +47,7 @@ module.exports = { process: false, }, }, -}; + node: false, +}); + +module.exports = [getConfig(true), getConfig(false)]; diff --git a/wrap-em.js b/wrap-em.js new file mode 100644 index 0000000..08c76da --- /dev/null +++ b/wrap-em.js @@ -0,0 +1,16 @@ +module.exports = (em) => ` +module.exports = function (Module) { + Module = Module || {}; + const module = undefined; + +${em} + + Module.unloadRuntime = function() { + if (typeof self!=="undefined") delete self.Module; + Module = jsModule = wasmMemory = wasmTable = asm = buffer = HEAP8 = HEAPU8 = + HEAP16 = HEAPU16 = HEAP32 = HEAPU32 = HEAPF32 = HEAPF64 = undefined; + if (typeof module!=="undefined") delete module.exports; + }; + + return Module; +}`;