-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add minimal polyfills for node.js modules
- Loading branch information
Showing
10 changed files
with
281 additions
and
3 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
* | ||
!/target/** | ||
!/polyfills/** | ||
!/package.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { Buffer } from "buffer" | ||
|
||
// limit of Crypto.getRandomValues() | ||
// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues | ||
const MAX_BYTES = 65536; | ||
|
||
// Node supports requesting up to this number of bytes | ||
// https://github.com/nodejs/node/blob/master/lib/internal/crypto/random.js#L48 | ||
const MAX_UINT32 = 4294967295; | ||
|
||
const JavaCrypto = Java.type("io.gatling.js.polyfills.Crypto"); | ||
|
||
export const randomBytes = (size, cb) => { | ||
// Node supports requesting up to this number of bytes | ||
// https://github.com/nodejs/node/blob/master/lib/internal/crypto/random.js#L48 | ||
if (size > MAX_UINT32) { | ||
throw new RangeError('requested too many random bytes'); | ||
} | ||
const bytes = Buffer.from(JavaCrypto.randomBytes(size)); | ||
if (typeof cb === 'function') { | ||
return process.nextTick(function () { | ||
cb(null, bytes); | ||
}) | ||
} | ||
return bytes; | ||
}; | ||
export const rng = randomBytes; | ||
export const pseudoRandomBytes = randomBytes; | ||
export const prng = randomBytes; | ||
export const getRandomValues = (values) => { | ||
const byteView = new Uint8Array(values.buffer, values.byteOffset, values.byteLength); | ||
const bytes = randomBytes(byteView.length); | ||
for (let i = 0; i < byteView.length; i++) { | ||
// The range of Math.random() is [0, 1) and the ToUint8 abstract operation rounds down | ||
byteView[i] = bytes[i]; | ||
} | ||
return values; | ||
}; | ||
export const randomUUID = () => JavaCrypto.randomUUID(); | ||
|
||
// export const Cipher = crypto.Cipher; | ||
// export const Cipheriv = crypto.Cipheriv; | ||
// export const Decipher = crypto.Decipher; | ||
// export const Decipheriv = crypto.Decipheriv; | ||
// export const DiffieHellman = crypto.DiffieHellman; | ||
// export const DiffieHellmanGroup = crypto.DiffieHellmanGroup; | ||
// export const Hash = crypto.Hash; | ||
// export const Hmac = crypto.Hmac; | ||
// export const Sign = crypto.Sign; | ||
// export const Verify = crypto.Verify; | ||
// export const constants = crypto.constants; | ||
// export const createCipher = crypto.createCipher; | ||
// export const createCipheriv = crypto.createCipheriv; | ||
// export const createCredentials = crypto.createCredentials; | ||
// export const createDecipher = crypto.createDecipher; | ||
// export const createDecipheriv = crypto.createDecipheriv; | ||
// export const createDiffieHellman = crypto.createDiffieHellman; | ||
// export const createDiffieHellmanGroup = crypto.createDiffieHellmanGroup; | ||
// export const createECDH = crypto.createECDH; | ||
// export const createHash = crypto.createHash; | ||
// export const createHmac = crypto.createHmac; | ||
// export const createSign = crypto.createSign; | ||
// export const createVerify = crypto.createVerify; | ||
// export const getCiphers = crypto.getCiphers; | ||
// export const getDiffieHellman = crypto.getDiffieHellman; | ||
// export const getHashes = crypto.getHashes; | ||
// export const listCiphers = crypto.listCiphers; | ||
// export const pbkdf2 = crypto.pbkdf2; | ||
// export const pbkdf2Sync = crypto.pbkdf2Sync; | ||
// export const privateDecrypt = crypto.privateDecrypt; | ||
// export const privateEncrypt = crypto.privateEncrypt; | ||
// export const publicDecrypt = crypto.publicDecrypt; | ||
// export const publicEncrypt = crypto.publicEncrypt; | ||
// export const randomFill = crypto.randomFill; | ||
// export const randomFillSync = crypto.randomFillSync; | ||
|
||
const crypto = { | ||
randomBytes, | ||
rng, | ||
pseudoRandomBytes, | ||
prng, | ||
getRandomValues, | ||
randomUUID, | ||
}; | ||
crypto.webcrypto = crypto; | ||
globalThis.crypto = crypto; | ||
export default crypto; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
const global = globalThis; | ||
export { global }; | ||
|
||
export { Buffer } from "buffer"; | ||
|
||
// These values are used by some of the JSPM polyfills | ||
export const navigator = { | ||
deviceMemory: 8, // Highest allowed value | ||
hardwareConcurrency: 8, // Fairly common default | ||
language: "en-US", // Most common default | ||
}; | ||
|
||
export * as crypto from "crypto" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import type { Plugin } from "esbuild"; | ||
import { fileURLToPath, pathToFileURL } from "url"; | ||
import { resolve, dirname } from "path"; | ||
|
||
// This is largely inspired by https://github.com/cyco130/esbuild-plugin-polyfill-node | ||
|
||
export const polyfill = (): Plugin => ({ | ||
name: "gatling-js-polyfill", | ||
setup: async (build) => { | ||
// modules | ||
const jspmResolved = await resolveImport(`@jspm/core/nodelibs/fs`); | ||
build.onResolve({ filter: polyfillsFilter }, async ({ path }) => { | ||
const [, , moduleName] = path.match(polyfillsFilter)!; | ||
const resolved = customPolyfills.find((name) => name === moduleName) | ||
? resolve(dirname(__filename), `../../polyfills/${moduleName}.js`) | ||
: resolve(jspmResolved, `../../browser/${moduleName}.js`); | ||
return { path: resolved }; | ||
}); | ||
|
||
// Globals | ||
build.initialOptions.inject = build.initialOptions.inject || []; | ||
const injectGlobal = (name: string) => | ||
(build.initialOptions.inject as string[]).push(resolve(dirname(__filename), `../../polyfills/${name}.js`)); | ||
injectGlobal("global"); | ||
} | ||
}); | ||
|
||
const customPolyfills = ["crypto"]; | ||
|
||
const jspmPolyfills = ["buffer", "path", "string_decoder"]; | ||
|
||
// Other available jspm-core modules: | ||
// "_stream_duplex" | ||
// "_stream_passthrough" | ||
// "_stream_readable" | ||
// "_stream_transform" | ||
// "_stream_writable" | ||
// "assert" | ||
// "assert/strict" | ||
// "async_hooks" | ||
// "child_process" | ||
// "cluster" | ||
// "console" | ||
// "constants" | ||
// "crypto" | ||
// "dgram" | ||
// "diagnostics_channel" | ||
// "dns" | ||
// "domain" | ||
// "events" | ||
// "fs" | ||
// "fs/promises" | ||
// "http" | ||
// "http2" | ||
// "https" | ||
// "module" | ||
// "net" | ||
// "os" | ||
// "perf_hooks" | ||
// "process" | ||
// "punycode" | ||
// "querystring" | ||
// "readline" | ||
// "repl" | ||
// "stream" | ||
// "sys" | ||
// "timers" | ||
// "timers/promises" | ||
// "tls" | ||
// "tty" | ||
// "url" | ||
// "util" | ||
// "v8" | ||
// "vm" | ||
// "wasi" | ||
// "worker_threads" | ||
// "zlib" | ||
|
||
const polyfillsFilter = new RegExp(`^(node:)?(${jspmPolyfills.concat(customPolyfills).join("|")})$`); | ||
|
||
let importMetaResolve: (specifier: string, parent: string) => string; | ||
|
||
const importMetaUrl = pathToFileURL(__filename).href; | ||
|
||
const resolveImport = async (specifier: string) => { | ||
if (!importMetaResolve) { | ||
importMetaResolve = (await import("import-meta-resolve")).resolve; | ||
} | ||
const resolved = importMetaResolve(specifier, importMetaUrl); | ||
return fileURLToPath(resolved); | ||
}; |
Oops, something went wrong.