@volter/tabnode 0.2.14-volter.88
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/LICENSE +22 -0
- package/README.md +78 -0
- package/THIRD-PARTY-NOTICES.md +12 -0
- package/dist/__sw__.js +526 -0
- package/dist/assets/runtime-worker-4MKaHFVb.js +75221 -0
- package/dist/assets/runtime-worker-4MKaHFVb.js.map +1 -0
- package/dist/code-transforms.d.ts +21 -0
- package/dist/code-transforms.d.ts.map +1 -0
- package/dist/config/cdn.d.ts +12 -0
- package/dist/config/cdn.d.ts.map +1 -0
- package/dist/create-runtime.d.ts +22 -0
- package/dist/create-runtime.d.ts.map +1 -0
- package/dist/host-globals.d.ts +62 -0
- package/dist/host-globals.d.ts.map +1 -0
- package/dist/index.cjs +36021 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +36020 -0
- package/dist/index.mjs.map +1 -0
- package/dist/node-internals.d.ts +68 -0
- package/dist/node-internals.d.ts.map +1 -0
- package/dist/node-lib/binding/blob.d.ts +12 -0
- package/dist/node-lib/binding/blob.d.ts.map +1 -0
- package/dist/node-lib/binding/buffer.d.ts +144 -0
- package/dist/node-lib/binding/buffer.d.ts.map +1 -0
- package/dist/node-lib/binding/cares_wrap.d.ts +14 -0
- package/dist/node-lib/binding/cares_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/fds.d.ts +30 -0
- package/dist/node-lib/binding/fds.d.ts.map +1 -0
- package/dist/node-lib/binding/fs.d.ts +157 -0
- package/dist/node-lib/binding/fs.d.ts.map +1 -0
- package/dist/node-lib/binding/handles.d.ts +81 -0
- package/dist/node-lib/binding/handles.d.ts.map +1 -0
- package/dist/node-lib/binding/http_parser.d.ts +122 -0
- package/dist/node-lib/binding/http_parser.d.ts.map +1 -0
- package/dist/node-lib/binding/index.d.ts +3 -0
- package/dist/node-lib/binding/index.d.ts.map +1 -0
- package/dist/node-lib/binding/llhttp-wasm.d.ts +22 -0
- package/dist/node-lib/binding/llhttp-wasm.d.ts.map +1 -0
- package/dist/node-lib/binding/misc.d.ts +123 -0
- package/dist/node-lib/binding/misc.d.ts.map +1 -0
- package/dist/node-lib/binding/pipe_wrap.d.ts +84 -0
- package/dist/node-lib/binding/pipe_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/process_wrap.d.ts +173 -0
- package/dist/node-lib/binding/process_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/spawn_sync.d.ts +30 -0
- package/dist/node-lib/binding/spawn_sync.d.ts.map +1 -0
- package/dist/node-lib/binding/stream_wrap.d.ts +191 -0
- package/dist/node-lib/binding/stream_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/stubs.d.ts +23 -0
- package/dist/node-lib/binding/stubs.d.ts.map +1 -0
- package/dist/node-lib/binding/tcp_wrap.d.ts +98 -0
- package/dist/node-lib/binding/tcp_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/tty_wrap.d.ts +36 -0
- package/dist/node-lib/binding/tty_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/util.d.ts +126 -0
- package/dist/node-lib/binding/util.d.ts.map +1 -0
- package/dist/node-lib/binding/uv.d.ts +32 -0
- package/dist/node-lib/binding/uv.d.ts.map +1 -0
- package/dist/node-lib/binding/zlib-pako.d.ts +22 -0
- package/dist/node-lib/binding/zlib-pako.d.ts.map +1 -0
- package/dist/node-lib/binding/zlib.d.ts +38 -0
- package/dist/node-lib/binding/zlib.d.ts.map +1 -0
- package/dist/node-lib/buffer-module.d.ts +51 -0
- package/dist/node-lib/buffer-module.d.ts.map +1 -0
- package/dist/node-lib/child-process-module.d.ts +26 -0
- package/dist/node-lib/child-process-module.d.ts.map +1 -0
- package/dist/node-lib/events-module.d.ts +58 -0
- package/dist/node-lib/events-module.d.ts.map +1 -0
- package/dist/node-lib/fs-module.d.ts +5 -0
- package/dist/node-lib/fs-module.d.ts.map +1 -0
- package/dist/node-lib/http-bridge.d.ts +43 -0
- package/dist/node-lib/http-bridge.d.ts.map +1 -0
- package/dist/node-lib/http-module.d.ts +35 -0
- package/dist/node-lib/http-module.d.ts.map +1 -0
- package/dist/node-lib/internals/addresses.d.ts +40 -0
- package/dist/node-lib/internals/addresses.d.ts.map +1 -0
- package/dist/node-lib/internals/buffer-and-streams.d.ts +96 -0
- package/dist/node-lib/internals/buffer-and-streams.d.ts.map +1 -0
- package/dist/node-lib/internals/child-process.d.ts +27 -0
- package/dist/node-lib/internals/child-process.d.ts.map +1 -0
- package/dist/node-lib/internals/events-util.d.ts +83 -0
- package/dist/node-lib/internals/events-util.d.ts.map +1 -0
- package/dist/node-lib/internals/index.d.ts +2 -0
- package/dist/node-lib/internals/index.d.ts.map +1 -0
- package/dist/node-lib/internals/modules.d.ts +67 -0
- package/dist/node-lib/internals/modules.d.ts.map +1 -0
- package/dist/node-lib/internals/readline-access.d.ts +2 -0
- package/dist/node-lib/internals/readline-access.d.ts.map +1 -0
- package/dist/node-lib/internals/runtime.d.ts +150 -0
- package/dist/node-lib/internals/runtime.d.ts.map +1 -0
- package/dist/node-lib/internals/util.d.ts +33 -0
- package/dist/node-lib/internals/util.d.ts.map +1 -0
- package/dist/node-lib/lazy.d.ts +31 -0
- package/dist/node-lib/lazy.d.ts.map +1 -0
- package/dist/node-lib/load.d.ts +27 -0
- package/dist/node-lib/load.d.ts.map +1 -0
- package/dist/node-lib/module-hooks.d.ts +89 -0
- package/dist/node-lib/module-hooks.d.ts.map +1 -0
- package/dist/node-lib/net-module.d.ts +181 -0
- package/dist/node-lib/net-module.d.ts.map +1 -0
- package/dist/node-lib/node-versions.d.ts +27 -0
- package/dist/node-lib/node-versions.d.ts.map +1 -0
- package/dist/node-lib/public-modules.d.ts +2 -0
- package/dist/node-lib/public-modules.d.ts.map +1 -0
- package/dist/node-lib/require-hook.d.ts +15 -0
- package/dist/node-lib/require-hook.d.ts.map +1 -0
- package/dist/node-lib/small-modules.d.ts +16 -0
- package/dist/node-lib/small-modules.d.ts.map +1 -0
- package/dist/node-lib/sources.d.ts +4 -0
- package/dist/node-lib/sources.d.ts.map +1 -0
- package/dist/node-lib/stream-module.d.ts +77 -0
- package/dist/node-lib/stream-module.d.ts.map +1 -0
- package/dist/node-lib/timers.d.ts +19 -0
- package/dist/node-lib/timers.d.ts.map +1 -0
- package/dist/node-lib/util-module.d.ts +76 -0
- package/dist/node-lib/util-module.d.ts.map +1 -0
- package/dist/node-resolution.d.ts +50 -0
- package/dist/node-resolution.d.ts.map +1 -0
- package/dist/node-resolver.d.ts +7 -0
- package/dist/node-resolver.d.ts.map +1 -0
- package/dist/npm/index.d.ts +73 -0
- package/dist/npm/index.d.ts.map +1 -0
- package/dist/npm/registry.d.ts +111 -0
- package/dist/npm/registry.d.ts.map +1 -0
- package/dist/npm/resolver.d.ts +79 -0
- package/dist/npm/resolver.d.ts.map +1 -0
- package/dist/npm/tarball.d.ts +28 -0
- package/dist/npm/tarball.d.ts.map +1 -0
- package/dist/process-tokens.d.ts +77 -0
- package/dist/process-tokens.d.ts.map +1 -0
- package/dist/punycode-source.d.ts +3 -0
- package/dist/punycode-source.d.ts.map +1 -0
- package/dist/runtime-interface.d.ts +74 -0
- package/dist/runtime-interface.d.ts.map +1 -0
- package/dist/runtime.d.ts +144 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/server-bridge.d.ts +147 -0
- package/dist/server-bridge.d.ts.map +1 -0
- package/dist/shims/async_hooks.d.ts +50 -0
- package/dist/shims/async_hooks.d.ts.map +1 -0
- package/dist/shims/child_process.d.ts +104 -0
- package/dist/shims/child_process.d.ts.map +1 -0
- package/dist/shims/cluster.d.ts +52 -0
- package/dist/shims/cluster.d.ts.map +1 -0
- package/dist/shims/command-line.d.ts +43 -0
- package/dist/shims/command-line.d.ts.map +1 -0
- package/dist/shims/constants.d.ts +222 -0
- package/dist/shims/constants.d.ts.map +1 -0
- package/dist/shims/crypto-constants.d.ts +12 -0
- package/dist/shims/crypto-constants.d.ts.map +1 -0
- package/dist/shims/crypto.d.ts +144 -0
- package/dist/shims/crypto.d.ts.map +1 -0
- package/dist/shims/dgram.d.ts +34 -0
- package/dist/shims/dgram.d.ts.map +1 -0
- package/dist/shims/dns.d.ts +91 -0
- package/dist/shims/dns.d.ts.map +1 -0
- package/dist/shims/domain.d.ts +25 -0
- package/dist/shims/domain.d.ts.map +1 -0
- package/dist/shims/esbuild.d.ts +205 -0
- package/dist/shims/esbuild.d.ts.map +1 -0
- package/dist/shims/fs.d.ts +25 -0
- package/dist/shims/fs.d.ts.map +1 -0
- package/dist/shims/http2.d.ts +81 -0
- package/dist/shims/http2.d.ts.map +1 -0
- package/dist/shims/inspector.d.ts +25 -0
- package/dist/shims/inspector.d.ts.map +1 -0
- package/dist/shims/module.d.ts +22 -0
- package/dist/shims/module.d.ts.map +1 -0
- package/dist/shims/os.d.ts +159 -0
- package/dist/shims/os.d.ts.map +1 -0
- package/dist/shims/path.d.ts +52 -0
- package/dist/shims/path.d.ts.map +1 -0
- package/dist/shims/perf_hooks.d.ts +50 -0
- package/dist/shims/perf_hooks.d.ts.map +1 -0
- package/dist/shims/process.d.ts +226 -0
- package/dist/shims/process.d.ts.map +1 -0
- package/dist/shims/rollup.d.ts +71 -0
- package/dist/shims/rollup.d.ts.map +1 -0
- package/dist/shims/string_decoder.d.ts +41 -0
- package/dist/shims/string_decoder.d.ts.map +1 -0
- package/dist/shims/sync-child.d.ts +64 -0
- package/dist/shims/sync-child.d.ts.map +1 -0
- package/dist/shims/tls.d.ts +53 -0
- package/dist/shims/tls.d.ts.map +1 -0
- package/dist/shims/url.d.ts +84 -0
- package/dist/shims/url.d.ts.map +1 -0
- package/dist/shims/v8.d.ts +73 -0
- package/dist/shims/v8.d.ts.map +1 -0
- package/dist/shims/vfs-adapter.d.ts +126 -0
- package/dist/shims/vfs-adapter.d.ts.map +1 -0
- package/dist/shims/vm.d.ts +52 -0
- package/dist/shims/vm.d.ts.map +1 -0
- package/dist/shims/wasi.d.ts +78 -0
- package/dist/shims/wasi.d.ts.map +1 -0
- package/dist/shims/worker_threads.d.ts +66 -0
- package/dist/shims/worker_threads.d.ts.map +1 -0
- package/dist/shims/zlib-constants.d.ts +66 -0
- package/dist/shims/zlib-constants.d.ts.map +1 -0
- package/dist/shims/zlib.d.ts +102 -0
- package/dist/shims/zlib.d.ts.map +1 -0
- package/dist/transform.d.ts +24 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/types/package-json.d.ts +18 -0
- package/dist/types/package-json.d.ts.map +1 -0
- package/dist/utils/binary-encoding.d.ts +13 -0
- package/dist/utils/binary-encoding.d.ts.map +1 -0
- package/dist/utils/glob.d.ts +19 -0
- package/dist/utils/glob.d.ts.map +1 -0
- package/dist/utils/hash.d.ts +6 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/virtual-fs.d.ts +259 -0
- package/dist/virtual-fs.d.ts.map +1 -0
- package/dist/vite-plugin.cjs +50 -0
- package/dist/vite-plugin.cjs.map +1 -0
- package/dist/vite-plugin.d.ts +36 -0
- package/dist/vite-plugin.d.ts.map +1 -0
- package/dist/vite-plugin.mjs +31 -0
- package/dist/vite-plugin.mjs.map +1 -0
- package/dist/worker/runtime-worker.d.ts +8 -0
- package/dist/worker/runtime-worker.d.ts.map +1 -0
- package/dist/worker-runtime.d.ts +50 -0
- package/dist/worker-runtime.d.ts.map +1 -0
- package/package.json +88 -0
- package/src/code-transforms.ts +560 -0
- package/src/config/cdn.ts +13 -0
- package/src/create-runtime.ts +89 -0
- package/src/host-globals.ts +121 -0
- package/src/index.ts +235 -0
- package/src/node-internals.ts +283 -0
- package/src/node-lib/LICENSE +47 -0
- package/src/node-lib/_http_agent.js +547 -0
- package/src/node-lib/_http_client.js +996 -0
- package/src/node-lib/_http_common.js +269 -0
- package/src/node-lib/_http_incoming.js +453 -0
- package/src/node-lib/_http_outgoing.js +1262 -0
- package/src/node-lib/_http_server.js +1230 -0
- package/src/node-lib/assert/strict.js +3 -0
- package/src/node-lib/assert.js +844 -0
- package/src/node-lib/binding/blob.ts +35 -0
- package/src/node-lib/binding/buffer.ts +465 -0
- package/src/node-lib/binding/cares_wrap.ts +57 -0
- package/src/node-lib/binding/fds.ts +80 -0
- package/src/node-lib/binding/fs.ts +857 -0
- package/src/node-lib/binding/handles.ts +187 -0
- package/src/node-lib/binding/http_parser.ts +536 -0
- package/src/node-lib/binding/index.ts +77 -0
- package/src/node-lib/binding/llhttp-wasm.ts +670 -0
- package/src/node-lib/binding/misc.ts +252 -0
- package/src/node-lib/binding/pipe_wrap.ts +166 -0
- package/src/node-lib/binding/process_wrap.ts +371 -0
- package/src/node-lib/binding/spawn_sync.ts +141 -0
- package/src/node-lib/binding/stream_wrap.ts +413 -0
- package/src/node-lib/binding/stubs.ts +19 -0
- package/src/node-lib/binding/tcp_wrap.ts +254 -0
- package/src/node-lib/binding/tty_wrap.ts +56 -0
- package/src/node-lib/binding/util.ts +274 -0
- package/src/node-lib/binding/uv.ts +102 -0
- package/src/node-lib/binding/zlib-pako.ts +50 -0
- package/src/node-lib/binding/zlib.ts +259 -0
- package/src/node-lib/buffer-module.ts +70 -0
- package/src/node-lib/buffer.js +1373 -0
- package/src/node-lib/child-process-module.ts +58 -0
- package/src/node-lib/child_process.js +1046 -0
- package/src/node-lib/constants.js +41 -0
- package/src/node-lib/diagnostics_channel.js +438 -0
- package/src/node-lib/events-module.ts +80 -0
- package/src/node-lib/events.js +1223 -0
- package/src/node-lib/fs-module.ts +43 -0
- package/src/node-lib/fs.js +3377 -0
- package/src/node-lib/http-bridge.ts +299 -0
- package/src/node-lib/http-module.ts +53 -0
- package/src/node-lib/http.js +198 -0
- package/src/node-lib/https.js +429 -0
- package/src/node-lib/internal/assert/assertion_error.js +417 -0
- package/src/node-lib/internal/assert/calltracker.js +153 -0
- package/src/node-lib/internal/assert/myers_diff.js +177 -0
- package/src/node-lib/internal/assert/utils.js +278 -0
- package/src/node-lib/internal/buffer.js +1120 -0
- package/src/node-lib/internal/child_process/serialization.js +169 -0
- package/src/node-lib/internal/child_process.js +1135 -0
- package/src/node-lib/internal/constants.js +56 -0
- package/src/node-lib/internal/deps/minimatch/index.js +1628 -0
- package/src/node-lib/internal/errors.js +1912 -0
- package/src/node-lib/internal/events/abort_listener.js +54 -0
- package/src/node-lib/internal/events/symbols.js +11 -0
- package/src/node-lib/internal/fixed_queue.js +119 -0
- package/src/node-lib/internal/freelist.js +30 -0
- package/src/node-lib/internal/fs/cp/cp-sync.js +242 -0
- package/src/node-lib/internal/fs/cp/cp.js +382 -0
- package/src/node-lib/internal/fs/dir.js +369 -0
- package/src/node-lib/internal/fs/glob.js +763 -0
- package/src/node-lib/internal/fs/promises.js +1312 -0
- package/src/node-lib/internal/fs/read/context.js +129 -0
- package/src/node-lib/internal/fs/recursive_watch.js +275 -0
- package/src/node-lib/internal/fs/rimraf.js +311 -0
- package/src/node-lib/internal/fs/streams.js +571 -0
- package/src/node-lib/internal/fs/sync_write_stream.js +49 -0
- package/src/node-lib/internal/fs/utils.js +987 -0
- package/src/node-lib/internal/fs/watchers.js +418 -0
- package/src/node-lib/internal/http.js +62 -0
- package/src/node-lib/internal/mime.js +389 -0
- package/src/node-lib/internal/modules/customization_hooks.js +406 -0
- package/src/node-lib/internal/net.js +95 -0
- package/src/node-lib/internal/querystring.js +119 -0
- package/src/node-lib/internal/readline/callbacks.js +132 -0
- package/src/node-lib/internal/readline/emitKeypressEvents.js +99 -0
- package/src/node-lib/internal/readline/interface.js +1418 -0
- package/src/node-lib/internal/readline/promises.js +144 -0
- package/src/node-lib/internal/readline/utils.js +405 -0
- package/src/node-lib/internal/socket_list.js +108 -0
- package/src/node-lib/internal/stream_base_commons.js +280 -0
- package/src/node-lib/internal/streams/add-abort-signal.js +60 -0
- package/src/node-lib/internal/streams/compose.js +257 -0
- package/src/node-lib/internal/streams/destroy.js +361 -0
- package/src/node-lib/internal/streams/duplex.js +203 -0
- package/src/node-lib/internal/streams/duplexify.js +379 -0
- package/src/node-lib/internal/streams/duplexpair.js +62 -0
- package/src/node-lib/internal/streams/end-of-stream.js +331 -0
- package/src/node-lib/internal/streams/from.js +208 -0
- package/src/node-lib/internal/streams/lazy_transform.js +57 -0
- package/src/node-lib/internal/streams/legacy.js +125 -0
- package/src/node-lib/internal/streams/operators.js +436 -0
- package/src/node-lib/internal/streams/passthrough.js +47 -0
- package/src/node-lib/internal/streams/pipeline.js +465 -0
- package/src/node-lib/internal/streams/readable.js +1762 -0
- package/src/node-lib/internal/streams/state.js +51 -0
- package/src/node-lib/internal/streams/transform.js +204 -0
- package/src/node-lib/internal/streams/utils.js +363 -0
- package/src/node-lib/internal/streams/writable.js +1163 -0
- package/src/node-lib/internal/tty.js +260 -0
- package/src/node-lib/internal/util/colors.js +40 -0
- package/src/node-lib/internal/util/comparisons.js +1028 -0
- package/src/node-lib/internal/util/debuglog.js +524 -0
- package/src/node-lib/internal/util/inspect.js +2535 -0
- package/src/node-lib/internal/util/parse_args/parse_args.js +412 -0
- package/src/node-lib/internal/util/parse_args/utils.js +197 -0
- package/src/node-lib/internal/util.js +1003 -0
- package/src/node-lib/internal/validators.js +654 -0
- package/src/node-lib/internals/addresses.ts +159 -0
- package/src/node-lib/internals/buffer-and-streams.ts +224 -0
- package/src/node-lib/internals/child-process.ts +64 -0
- package/src/node-lib/internals/events-util.ts +105 -0
- package/src/node-lib/internals/index.ts +66 -0
- package/src/node-lib/internals/modules.ts +117 -0
- package/src/node-lib/internals/readline-access.ts +16 -0
- package/src/node-lib/internals/runtime.ts +277 -0
- package/src/node-lib/internals/util.ts +98 -0
- package/src/node-lib/lazy.ts +158 -0
- package/src/node-lib/load.ts +390 -0
- package/src/node-lib/module-hooks.ts +281 -0
- package/src/node-lib/net-module.ts +248 -0
- package/src/node-lib/net.js +2540 -0
- package/src/node-lib/node-versions.ts +34 -0
- package/src/node-lib/os.js +356 -0
- package/src/node-lib/path.js +1694 -0
- package/src/node-lib/primordials.js +743 -0
- package/src/node-lib/public-modules.ts +109 -0
- package/src/node-lib/punycode.js +455 -0
- package/src/node-lib/querystring.js +484 -0
- package/src/node-lib/readline/promises.js +73 -0
- package/src/node-lib/readline.js +523 -0
- package/src/node-lib/require-hook.ts +27 -0
- package/src/node-lib/small-modules.ts +35 -0
- package/src/node-lib/sources.ts +200 -0
- package/src/node-lib/stream/promises.js +44 -0
- package/src/node-lib/stream-module.ts +101 -0
- package/src/node-lib/stream.js +152 -0
- package/src/node-lib/timers.ts +33 -0
- package/src/node-lib/tty.js +168 -0
- package/src/node-lib/util-module.ts +104 -0
- package/src/node-lib/util.js +689 -0
- package/src/node-lib/wasi.js +179 -0
- package/src/node-lib/zlib.js +1036 -0
- package/src/node-resolution.ts +241 -0
- package/src/node-resolver.ts +33 -0
- package/src/npm/index.ts +425 -0
- package/src/npm/registry.ts +235 -0
- package/src/npm/resolver.ts +589 -0
- package/src/npm/tarball.ts +246 -0
- package/src/process-tokens.ts +156 -0
- package/src/punycode-source.ts +6 -0
- package/src/runtime-interface.ts +85 -0
- package/src/runtime.ts +3073 -0
- package/src/server-bridge.ts +971 -0
- package/src/shims/async_hooks.ts +181 -0
- package/src/shims/child_process.ts +1591 -0
- package/src/shims/cluster.ts +79 -0
- package/src/shims/command-line.ts +79 -0
- package/src/shims/constants.ts +68 -0
- package/src/shims/crypto-constants.ts +11 -0
- package/src/shims/crypto.ts +1061 -0
- package/src/shims/dgram.ts +47 -0
- package/src/shims/dns.ts +185 -0
- package/src/shims/domain.ts +58 -0
- package/src/shims/esbuild.ts +1638 -0
- package/src/shims/fs.ts +82 -0
- package/src/shims/http2.ts +96 -0
- package/src/shims/inspector.ts +30 -0
- package/src/shims/module.ts +86 -0
- package/src/shims/os.ts +195 -0
- package/src/shims/path.ts +246 -0
- package/src/shims/perf_hooks.ts +92 -0
- package/src/shims/process.ts +804 -0
- package/src/shims/rollup.ts +149 -0
- package/src/shims/string_decoder.ts +396 -0
- package/src/shims/sync-child.ts +469 -0
- package/src/shims/tls.ts +94 -0
- package/src/shims/url.ts +217 -0
- package/src/shims/v8.ts +113 -0
- package/src/shims/vfs-adapter.ts +408 -0
- package/src/shims/vm.ts +132 -0
- package/src/shims/wasi.ts +1440 -0
- package/src/shims/worker_threads.ts +114 -0
- package/src/shims/zlib-constants.ts +65 -0
- package/src/shims/zlib.ts +228 -0
- package/src/transform.ts +324 -0
- package/src/types/external.d.ts +55 -0
- package/src/types/package-json.ts +17 -0
- package/src/types/pako-zlib.d.ts +30 -0
- package/src/types/sha.js.d.ts +14 -0
- package/src/utils/binary-encoding.ts +43 -0
- package/src/utils/glob.ts +54 -0
- package/src/utils/hash.ts +12 -0
- package/src/virtual-fs.ts +1048 -0
- package/src/vite-plugin.ts +76 -0
- package/src/worker/runtime-worker.ts +128 -0
- package/src/worker-runtime.ts +145 -0
|
@@ -0,0 +1,1061 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js crypto module shim
|
|
3
|
+
*
|
|
4
|
+
* Digests, HMAC and PBKDF2 are the real algorithms over pure-JS primitives,
|
|
5
|
+
* because a guest calls them synchronously and WebCrypto is async-only.
|
|
6
|
+
* Random values and asymmetric signing use WebCrypto, which does have them.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import SHA from 'sha.js';
|
|
10
|
+
import { md5 } from '@noble/hashes/legacy.js';
|
|
11
|
+
// The `buffer` package, not the guest polyfill: the byte-level encodings
|
|
12
|
+
// (utf16le, latin1, offset views) crypto inputs arrive in are its own.
|
|
13
|
+
import { Buffer as HostBuffer } from 'buffer/index.js';
|
|
14
|
+
import { Buffer } from '../node-lib/buffer-module';
|
|
15
|
+
/** Node's own `buffer` limit, read at use rather than at load: see `node-lib/lazy.ts`. */
|
|
16
|
+
import { bufferModule } from '../node-lib/buffer-module';
|
|
17
|
+
import { EventEmitter } from '../node-lib/events-module';
|
|
18
|
+
import {
|
|
19
|
+
ERR_INVALID_ARG_TYPE,
|
|
20
|
+
ERR_OUT_OF_RANGE,
|
|
21
|
+
validateFunction,
|
|
22
|
+
validateNumber,
|
|
23
|
+
} from '../node-internals';
|
|
24
|
+
import { cryptoConstants as constants } from './crypto-constants';
|
|
25
|
+
export { constants };
|
|
26
|
+
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Random functions
|
|
29
|
+
// ============================================================================
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Node's `lib/internal/crypto/random.js` bounds. VS Code's extension host calls
|
|
33
|
+
* `crypto.randomBytes(size, cb)` and waits on the callback; the engine ignored
|
|
34
|
+
* the callback, returned the buffer, and the host waited forever. `randomFill`
|
|
35
|
+
* was not here at all. Node decides every error these raise in `assertOffset`
|
|
36
|
+
* and `assertSize`, so both are transcribed rather than approximated.
|
|
37
|
+
*/
|
|
38
|
+
function kMaxPossibleLengthOf(): number { return Math.min(bufferModule.kMaxLength, 2 ** 31 - 1); }
|
|
39
|
+
/** WebCrypto refuses more than this many bytes in one call. */
|
|
40
|
+
const kRandomChunk = 65536;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Random bytes into any view. WebCrypto has a per-call limit and refuses a
|
|
44
|
+
* view over a SharedArrayBuffer, both of which Node's own `randomFillSync`
|
|
45
|
+
* accepts, so the bytes are drawn into a plain array and copied.
|
|
46
|
+
*/
|
|
47
|
+
function __fillRandomBytes(target: Uint8Array): void {
|
|
48
|
+
if (target.length === 0) return;
|
|
49
|
+
const chunk = new Uint8Array(Math.min(target.length, kRandomChunk));
|
|
50
|
+
for (let offset = 0; offset < target.length; offset += kRandomChunk) {
|
|
51
|
+
const span = Math.min(kRandomChunk, target.length - offset);
|
|
52
|
+
const source = span === chunk.length ? chunk : chunk.subarray(0, span);
|
|
53
|
+
crypto.getRandomValues(source);
|
|
54
|
+
target.set(source, offset);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Node: a fill target is an ArrayBuffer, a SharedArrayBuffer or any view. */
|
|
59
|
+
function __randomFillTarget(buffer: unknown): Uint8Array {
|
|
60
|
+
if (ArrayBuffer.isView(buffer)) {
|
|
61
|
+
const view = buffer as ArrayBufferView;
|
|
62
|
+
return new Uint8Array(view.buffer as ArrayBuffer, view.byteOffset, view.byteLength);
|
|
63
|
+
}
|
|
64
|
+
if (buffer instanceof ArrayBuffer) return new Uint8Array(buffer);
|
|
65
|
+
if (typeof SharedArrayBuffer !== 'undefined' && buffer instanceof SharedArrayBuffer) {
|
|
66
|
+
return new Uint8Array(buffer as unknown as ArrayBuffer);
|
|
67
|
+
}
|
|
68
|
+
throw new ERR_INVALID_ARG_TYPE('buf', ['ArrayBuffer', 'ArrayBufferView'], buffer);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** lib/internal/crypto/random.js assertOffset, in element units as Node takes it. */
|
|
72
|
+
function __assertOffset(offset: unknown, elementSize: number, length: number): number {
|
|
73
|
+
validateNumber(offset, 'offset');
|
|
74
|
+
const bytes = (offset as number) * elementSize;
|
|
75
|
+
const maxLength = Math.min(length, kMaxPossibleLengthOf());
|
|
76
|
+
if (Number.isNaN(bytes) || bytes > maxLength || bytes < 0) {
|
|
77
|
+
throw new ERR_OUT_OF_RANGE('offset', `>= 0 && <= ${maxLength}`, bytes);
|
|
78
|
+
}
|
|
79
|
+
return bytes >>> 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** lib/internal/crypto/random.js assertSize. */
|
|
83
|
+
function __assertSize(size: unknown, elementSize: number, offset: number, length: number): number {
|
|
84
|
+
validateNumber(size, 'size');
|
|
85
|
+
const bytes = (size as number) * elementSize;
|
|
86
|
+
if (Number.isNaN(bytes) || bytes > kMaxPossibleLengthOf() || bytes < 0) {
|
|
87
|
+
throw new ERR_OUT_OF_RANGE('size', `>= 0 && <= ${kMaxPossibleLengthOf()}`, bytes);
|
|
88
|
+
}
|
|
89
|
+
if (bytes + offset > length) {
|
|
90
|
+
throw new ERR_OUT_OF_RANGE('size + offset', `<= ${length}`, bytes + offset);
|
|
91
|
+
}
|
|
92
|
+
return bytes >>> 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function randomBytes(size: number): Buffer;
|
|
96
|
+
export function randomBytes(size: number, callback: (error: Error | null, buffer: Buffer) => void): void;
|
|
97
|
+
/**
|
|
98
|
+
* Node: with a callback, `randomBytes` answers through it and returns nothing;
|
|
99
|
+
* without one it returns the buffer. The engine always returned the buffer and
|
|
100
|
+
* dropped the callback, so a program that only waits on the callback hung.
|
|
101
|
+
*/
|
|
102
|
+
export function randomBytes(
|
|
103
|
+
size: number,
|
|
104
|
+
callback?: (error: Error | null, buffer: Buffer) => void
|
|
105
|
+
): Buffer | void {
|
|
106
|
+
const length = __assertSize(size, 1, 0, Infinity);
|
|
107
|
+
if (callback !== undefined) validateFunction(callback, 'callback');
|
|
108
|
+
if (callback === undefined) {
|
|
109
|
+
const array = new Uint8Array(length);
|
|
110
|
+
__fillRandomBytes(array);
|
|
111
|
+
return Buffer.from(array);
|
|
112
|
+
}
|
|
113
|
+
queueMicrotask(() => {
|
|
114
|
+
const array = new Uint8Array(length);
|
|
115
|
+
__fillRandomBytes(array);
|
|
116
|
+
callback(null, Buffer.from(array));
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function randomFillSync<T extends ArrayBufferView | ArrayBufferLike>(
|
|
121
|
+
buffer: T,
|
|
122
|
+
offset?: number,
|
|
123
|
+
size?: number
|
|
124
|
+
): T {
|
|
125
|
+
const target = __randomFillTarget(buffer);
|
|
126
|
+
const elementSize = (buffer as { BYTES_PER_ELEMENT?: number }).BYTES_PER_ELEMENT || 1;
|
|
127
|
+
const start = __assertOffset(offset === undefined ? 0 : offset, elementSize, target.byteLength);
|
|
128
|
+
const length = size === undefined
|
|
129
|
+
? target.byteLength - start
|
|
130
|
+
: __assertSize(size, elementSize, start, target.byteLength);
|
|
131
|
+
if (length !== 0) __fillRandomBytes(target.subarray(start, start + length));
|
|
132
|
+
return buffer;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Node's asynchronous fill. The overloads are Node's: `(buf, cb)`,
|
|
137
|
+
* `(buf, offset, cb)`, `(buf, offset, size, cb)`, with the same argument
|
|
138
|
+
* checks `randomFillSync` makes.
|
|
139
|
+
*/
|
|
140
|
+
export function randomFill<T extends ArrayBufferView | ArrayBufferLike>(
|
|
141
|
+
buffer: T,
|
|
142
|
+
callback: (error: Error | null, buffer: T) => void
|
|
143
|
+
): void;
|
|
144
|
+
export function randomFill<T extends ArrayBufferView | ArrayBufferLike>(
|
|
145
|
+
buffer: T,
|
|
146
|
+
offset: number,
|
|
147
|
+
callback: (error: Error | null, buffer: T) => void
|
|
148
|
+
): void;
|
|
149
|
+
export function randomFill<T extends ArrayBufferView | ArrayBufferLike>(
|
|
150
|
+
buffer: T,
|
|
151
|
+
offset: number,
|
|
152
|
+
size: number,
|
|
153
|
+
callback: (error: Error | null, buffer: T) => void
|
|
154
|
+
): void;
|
|
155
|
+
export function randomFill(
|
|
156
|
+
buffer: unknown,
|
|
157
|
+
offsetOrCallback?: unknown,
|
|
158
|
+
sizeOrCallback?: unknown,
|
|
159
|
+
maybeCallback?: unknown
|
|
160
|
+
): void {
|
|
161
|
+
const target = __randomFillTarget(buffer);
|
|
162
|
+
const elementSize = (buffer as { BYTES_PER_ELEMENT?: number }).BYTES_PER_ELEMENT || 1;
|
|
163
|
+
|
|
164
|
+
let offset: unknown = offsetOrCallback;
|
|
165
|
+
let size: unknown = sizeOrCallback;
|
|
166
|
+
let callback: unknown = maybeCallback;
|
|
167
|
+
|
|
168
|
+
if (typeof offsetOrCallback === 'function') {
|
|
169
|
+
callback = offsetOrCallback;
|
|
170
|
+
offset = 0;
|
|
171
|
+
// Node: a length in elements here, which assertSize turns into bytes. A
|
|
172
|
+
// DataView and a raw ArrayBuffer have no `length`, and the whole byte
|
|
173
|
+
// length is taken instead.
|
|
174
|
+
size = (buffer as { length?: number }).length;
|
|
175
|
+
} else if (typeof sizeOrCallback === 'function') {
|
|
176
|
+
callback = sizeOrCallback;
|
|
177
|
+
size = ((buffer as { length?: number }).length ?? target.byteLength) - (offset as number);
|
|
178
|
+
} else {
|
|
179
|
+
validateFunction(callback, 'callback');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const start = __assertOffset(offset, elementSize, target.byteLength);
|
|
183
|
+
const length = size === undefined
|
|
184
|
+
? target.byteLength - start
|
|
185
|
+
: __assertSize(size, elementSize, start, target.byteLength);
|
|
186
|
+
|
|
187
|
+
const done = callback as (error: Error | null, buffer: unknown) => void;
|
|
188
|
+
queueMicrotask(() => {
|
|
189
|
+
if (length !== 0) __fillRandomBytes(target.subarray(start, start + length));
|
|
190
|
+
done(null, buffer);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function randomUUID(): string {
|
|
195
|
+
return crypto.randomUUID();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Node's `randomInt` draws from six bytes, so this is its largest range. */
|
|
199
|
+
const kRandMax = 281474976710655;
|
|
200
|
+
|
|
201
|
+
export function randomInt(max: number): number;
|
|
202
|
+
export function randomInt(min: number, max: number): number;
|
|
203
|
+
export function randomInt(max: number, callback: (error: undefined, value: number) => void): void;
|
|
204
|
+
export function randomInt(min: number, max: number, callback: (error: undefined, value: number) => void): void;
|
|
205
|
+
/**
|
|
206
|
+
* Node's `randomInt`, transcribed: an unbiased draw by rejection, Node's
|
|
207
|
+
* argument checks, and the callback form. The engine had neither the callback
|
|
208
|
+
* form nor the checks, so `randomInt(3, cb)` read the callback as the maximum
|
|
209
|
+
* and answered NaN, and `randomInt(1, 1)` divided by a zero range.
|
|
210
|
+
*/
|
|
211
|
+
export function randomInt(
|
|
212
|
+
min: number,
|
|
213
|
+
max?: number | ((error: undefined, value: number) => void),
|
|
214
|
+
callback?: (error: undefined, value: number) => void
|
|
215
|
+
): number | void {
|
|
216
|
+
const minNotSpecified = max === undefined || typeof max === 'function';
|
|
217
|
+
let low = min;
|
|
218
|
+
let high = max as number;
|
|
219
|
+
if (minNotSpecified) {
|
|
220
|
+
callback = max as ((error: undefined, value: number) => void) | undefined;
|
|
221
|
+
high = min;
|
|
222
|
+
low = 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const isSync = callback === undefined;
|
|
226
|
+
if (!isSync) validateFunction(callback, 'callback');
|
|
227
|
+
if (!Number.isSafeInteger(low)) throw new ERR_INVALID_ARG_TYPE('min', 'a safe integer', low);
|
|
228
|
+
if (!Number.isSafeInteger(high)) throw new ERR_INVALID_ARG_TYPE('max', 'a safe integer', high);
|
|
229
|
+
if (high <= low) {
|
|
230
|
+
throw new ERR_OUT_OF_RANGE('max', `greater than the value of "min" (${low})`, high);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const range = high - low;
|
|
234
|
+
if (!(range <= kRandMax)) {
|
|
235
|
+
throw new ERR_OUT_OF_RANGE(`max${minNotSpecified ? '' : ' - min'}`, `<= ${kRandMax}`, range);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// For (x % range) to be unbiased, x must come from [0, randLimit).
|
|
239
|
+
const randLimit = kRandMax - (kRandMax % range);
|
|
240
|
+
const bytes = new Uint8Array(6);
|
|
241
|
+
for (;;) {
|
|
242
|
+
__fillRandomBytes(bytes);
|
|
243
|
+
let x = 0;
|
|
244
|
+
for (let index = 0; index < 6; index++) x = x * 256 + bytes[index];
|
|
245
|
+
if (x >= randLimit) continue;
|
|
246
|
+
const value = (x % range) + low;
|
|
247
|
+
if (isSync) return value;
|
|
248
|
+
queueMicrotask(() => (callback as (error: undefined, value: number) => void)(undefined, value));
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export function getRandomValues<T extends ArrayBufferView>(array: T): T {
|
|
254
|
+
return crypto.getRandomValues(array);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ============================================================================
|
|
258
|
+
// Hash, HMAC and PBKDF2
|
|
259
|
+
// ============================================================================
|
|
260
|
+
//
|
|
261
|
+
// These are the real algorithms, computed synchronously in JS. What stood
|
|
262
|
+
// here before was `syncHash`, an integer mixer that returned digest-shaped
|
|
263
|
+
// bytes which were not the digest, and a `syncHmac` that hashed key||data:
|
|
264
|
+
// a config loader keyed its cache by md5 and collided, `ws` computed a
|
|
265
|
+
// Sec-WebSocket-Accept no server accepts, and every guest that compares a
|
|
266
|
+
// digest to a known constant disagreed with Node. WebCrypto cannot stand in:
|
|
267
|
+
// it is async-only, so `createHash(...).digest()` cannot wait for it, and it
|
|
268
|
+
// has no MD5 at all. sha.js carries the SHA family and @noble/hashes carries
|
|
269
|
+
// MD5; both are pure JS and byte-for-byte Node's.
|
|
270
|
+
|
|
271
|
+
/** A hash engine: sha.js's Hash, or @noble/hashes' MD5. */
|
|
272
|
+
interface DigestState {
|
|
273
|
+
update(data: Uint8Array): DigestState;
|
|
274
|
+
digest(): Uint8Array;
|
|
275
|
+
clone?(): DigestState;
|
|
276
|
+
[field: string]: unknown;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const HASH_ALGORITHMS = ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512'];
|
|
280
|
+
|
|
281
|
+
function cryptoError(code: string, message: string): Error {
|
|
282
|
+
return Object.assign(new Error(message), { code });
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function finalized(): Error {
|
|
286
|
+
return cryptoError('ERR_CRYPTO_HASH_FINALIZED', 'Digest already called');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Node throws ERR_CRYPTO_UNSUPPORTED_OPERATION rather than returning
|
|
291
|
+
* something that only looks like a result; so does this shim.
|
|
292
|
+
*/
|
|
293
|
+
export function unsupported(operation: string): never {
|
|
294
|
+
throw cryptoError(
|
|
295
|
+
'ERR_CRYPTO_UNSUPPORTED_OPERATION',
|
|
296
|
+
`${operation} is not supported by the browser crypto adapter.`
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function hashAlgorithm(value: unknown): string {
|
|
301
|
+
if (typeof value !== 'string') throw new TypeError('Digest algorithm must be a string.');
|
|
302
|
+
// Node accepts OpenSSL's spellings; `sha-256` and `sha256` are one digest.
|
|
303
|
+
const name = value.toLowerCase().replace(/^sha-(1|224|256|384|512)$/, 'sha$1');
|
|
304
|
+
if (!HASH_ALGORITHMS.includes(name)) {
|
|
305
|
+
throw cryptoError('ERR_CRYPTO_INVALID_DIGEST', `Unsupported digest: ${value}`);
|
|
306
|
+
}
|
|
307
|
+
return name;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function digestEngine(algorithm: string): DigestState {
|
|
311
|
+
// Neither library declares the open field set the copy path below reads.
|
|
312
|
+
return algorithm === 'md5'
|
|
313
|
+
? (md5.create() as unknown as DigestState)
|
|
314
|
+
: (SHA(algorithm) as unknown as DigestState);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
type HostBytes = InstanceType<typeof HostBuffer>;
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Crypto input as bytes, in the `buffer` package's memory: it carries the
|
|
321
|
+
* encodings the guest Buffer polyfill does not (utf16le, latin1) and views a
|
|
322
|
+
* caller's ArrayBuffer at its offset instead of copying the whole store.
|
|
323
|
+
*/
|
|
324
|
+
function cryptoBytes(value: unknown, encoding?: string, allowArrayBuffer = false): HostBytes {
|
|
325
|
+
if (typeof value === 'string') {
|
|
326
|
+
// `buffer` 6.0.3 predates base64url; the alphabet is a superset of base64's.
|
|
327
|
+
if (encoding?.toLowerCase() === 'base64url') return HostBuffer.from(value, 'base64');
|
|
328
|
+
if (encoding !== undefined && !HostBuffer.isEncoding(encoding)) {
|
|
329
|
+
throw new TypeError(`Unknown encoding: ${encoding}`);
|
|
330
|
+
}
|
|
331
|
+
return HostBuffer.from(value, encoding);
|
|
332
|
+
}
|
|
333
|
+
if (ArrayBuffer.isView(value)) {
|
|
334
|
+
// A view over shared memory hashes like any other; only the types of
|
|
335
|
+
// `buffer`'s from() overload stop at ArrayBuffer.
|
|
336
|
+
return HostBuffer.from(value.buffer as ArrayBuffer, value.byteOffset, value.byteLength);
|
|
337
|
+
}
|
|
338
|
+
if (allowArrayBuffer && value instanceof ArrayBuffer) return HostBuffer.from(value);
|
|
339
|
+
throw new TypeError('Crypto input must be a string or an ArrayBuffer view.');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** Digests leave as guest Buffers, so a guest's `Buffer.isBuffer` holds. */
|
|
343
|
+
function digestResult(value: Uint8Array, encoding?: string): Buffer | string {
|
|
344
|
+
if (!encoding || encoding === 'buffer') return Buffer.from(value);
|
|
345
|
+
const name = encoding.toLowerCase();
|
|
346
|
+
if (name === 'base64url') {
|
|
347
|
+
return HostBuffer.from(value)
|
|
348
|
+
.toString('base64')
|
|
349
|
+
.replace(/\+/g, '-')
|
|
350
|
+
.replace(/\//g, '_')
|
|
351
|
+
.replace(/=+$/, '');
|
|
352
|
+
}
|
|
353
|
+
if (!HostBuffer.isEncoding(name)) throw new TypeError(`Unknown encoding: ${encoding}`);
|
|
354
|
+
return HostBuffer.from(value).toString(name);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
class Hash {
|
|
358
|
+
private state: DigestState;
|
|
359
|
+
private done = false;
|
|
360
|
+
readonly algorithm: string;
|
|
361
|
+
|
|
362
|
+
constructor(algorithm: string) {
|
|
363
|
+
this.algorithm = algorithm;
|
|
364
|
+
this.state = digestEngine(algorithm);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
update(data: unknown, inputEncoding?: string): this {
|
|
368
|
+
if (this.done) throw finalized();
|
|
369
|
+
// Consume the bytes now: Node's update copies, and a caller may reuse
|
|
370
|
+
// the array it handed us before digest().
|
|
371
|
+
this.state.update(cryptoBytes(data, inputEncoding));
|
|
372
|
+
return this;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
digest(outputEncoding?: string): Buffer | string {
|
|
376
|
+
if (this.done) throw finalized();
|
|
377
|
+
this.done = true;
|
|
378
|
+
return digestResult(this.state.digest(), outputEncoding);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async digestAsync(outputEncoding?: string): Promise<Buffer | string> {
|
|
382
|
+
return this.digest(outputEncoding);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
copy(): Hash {
|
|
386
|
+
if (this.done) throw finalized();
|
|
387
|
+
const copy = new Hash(this.algorithm);
|
|
388
|
+
if (this.state.clone) {
|
|
389
|
+
copy.state = this.state.clone();
|
|
390
|
+
return copy;
|
|
391
|
+
}
|
|
392
|
+
// sha.js 2.4.12 keeps its chaining words, length and current block in own
|
|
393
|
+
// fields and offers no clone. Copy buffers and scratch arrays by value;
|
|
394
|
+
// everything else is a number.
|
|
395
|
+
for (const [field, value] of Object.entries(this.state)) {
|
|
396
|
+
copy.state[field] = ArrayBuffer.isView(value)
|
|
397
|
+
? HostBuffer.from(cryptoBytes(value))
|
|
398
|
+
: Array.isArray(value)
|
|
399
|
+
? value.slice()
|
|
400
|
+
: value;
|
|
401
|
+
}
|
|
402
|
+
return copy;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
class Hmac {
|
|
407
|
+
private inner: DigestState;
|
|
408
|
+
private outer: DigestState;
|
|
409
|
+
private done = false;
|
|
410
|
+
|
|
411
|
+
constructor(algorithm: string, key: HostBytes) {
|
|
412
|
+
const blockSize = algorithm === 'sha384' || algorithm === 'sha512' ? 128 : 64;
|
|
413
|
+
// RFC 2104: a key longer than the block is hashed first, a shorter one
|
|
414
|
+
// is zero-padded to the block.
|
|
415
|
+
const material = key.length > blockSize ? digestEngine(algorithm).update(key).digest() : key;
|
|
416
|
+
const innerPad = HostBuffer.alloc(blockSize);
|
|
417
|
+
const outerPad = HostBuffer.alloc(blockSize);
|
|
418
|
+
for (let index = 0; index < blockSize; index++) {
|
|
419
|
+
const byte = index < material.length ? material[index] : 0;
|
|
420
|
+
innerPad[index] = byte ^ 0x36;
|
|
421
|
+
outerPad[index] = byte ^ 0x5c;
|
|
422
|
+
}
|
|
423
|
+
this.inner = digestEngine(algorithm).update(innerPad);
|
|
424
|
+
this.outer = digestEngine(algorithm).update(outerPad);
|
|
425
|
+
innerPad.fill(0);
|
|
426
|
+
outerPad.fill(0);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
update(data: unknown, inputEncoding?: string): this {
|
|
430
|
+
if (this.done) throw finalized();
|
|
431
|
+
this.inner.update(cryptoBytes(data, inputEncoding));
|
|
432
|
+
return this;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
digest(outputEncoding?: string): Buffer | string {
|
|
436
|
+
// Node's Hmac yields an empty result from a second digest(), not an error.
|
|
437
|
+
if (this.done) return digestResult(HostBuffer.alloc(0), outputEncoding);
|
|
438
|
+
this.done = true;
|
|
439
|
+
return digestResult(this.outer.update(this.inner.digest()).digest(), outputEncoding);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async digestAsync(outputEncoding?: string): Promise<Buffer | string> {
|
|
443
|
+
return this.digest(outputEncoding);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
export function createHash(algorithm: string, options?: { outputLength?: number }): Hash {
|
|
448
|
+
if (options?.outputLength !== undefined) unsupported('Variable-length digests');
|
|
449
|
+
return new Hash(hashAlgorithm(algorithm));
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export function createHmac(
|
|
453
|
+
algorithm: string,
|
|
454
|
+
key: unknown,
|
|
455
|
+
options?: { encoding?: string }
|
|
456
|
+
): Hmac {
|
|
457
|
+
const name = hashAlgorithm(algorithm);
|
|
458
|
+
let material = key;
|
|
459
|
+
if (material !== null && typeof material === 'object' && 'type' in material && 'export' in material) {
|
|
460
|
+
const secret = material as { type: unknown; export?: unknown };
|
|
461
|
+
if (secret.type !== 'secret' || typeof secret.export !== 'function') {
|
|
462
|
+
throw new TypeError('HMAC requires a secret key.');
|
|
463
|
+
}
|
|
464
|
+
material = (secret.export as () => unknown)();
|
|
465
|
+
}
|
|
466
|
+
return new Hmac(name, cryptoBytes(material, options?.encoding, true));
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/** The one-shot digest, `crypto.hash`, added in Node 21. */
|
|
470
|
+
export function hash(algorithm: string, data: unknown, outputEncoding = 'hex'): Buffer | string {
|
|
471
|
+
return createHash(algorithm).update(data).digest(outputEncoding);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// ============================================================================
|
|
475
|
+
// PBKDF2 (Password-Based Key Derivation Function 2)
|
|
476
|
+
// ============================================================================
|
|
477
|
+
|
|
478
|
+
type BinaryLike = string | Buffer | Uint8Array;
|
|
479
|
+
|
|
480
|
+
interface Pbkdf2Parameters {
|
|
481
|
+
algorithm: string;
|
|
482
|
+
password: HostBytes;
|
|
483
|
+
salt: HostBytes;
|
|
484
|
+
iterations: number;
|
|
485
|
+
keylen: number;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function pbkdf2Parameters(
|
|
489
|
+
password: unknown,
|
|
490
|
+
salt: unknown,
|
|
491
|
+
iterations: number,
|
|
492
|
+
keylen: number,
|
|
493
|
+
digest: string
|
|
494
|
+
): Pbkdf2Parameters {
|
|
495
|
+
const algorithm = hashAlgorithm(digest);
|
|
496
|
+
for (const [name, value] of [['iterations', iterations], ['keylen', keylen]] as const) {
|
|
497
|
+
if (typeof value !== 'number') throw new TypeError(`${name} must be a number.`);
|
|
498
|
+
if (!Number.isInteger(value) || value < 1 || value > 0x7fffffff) {
|
|
499
|
+
throw new RangeError(`${name} is out of range.`);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
// Copy before the callback form yields: a caller that reuses its password
|
|
503
|
+
// array must not change the key we derive.
|
|
504
|
+
return {
|
|
505
|
+
algorithm,
|
|
506
|
+
password: HostBuffer.from(cryptoBytes(password, undefined, true)),
|
|
507
|
+
salt: HostBuffer.from(cryptoBytes(salt, undefined, true)),
|
|
508
|
+
iterations,
|
|
509
|
+
keylen,
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function derive(parameters: Pbkdf2Parameters): Buffer {
|
|
514
|
+
const { algorithm, password, salt, iterations, keylen } = parameters;
|
|
515
|
+
const length = { md5: 16, sha1: 20, sha224: 28, sha256: 32, sha384: 48, sha512: 64 }[algorithm]!;
|
|
516
|
+
const derived = HostBuffer.alloc(keylen);
|
|
517
|
+
const suffix = HostBuffer.alloc(4);
|
|
518
|
+
try {
|
|
519
|
+
for (let block = 1, offset = 0; offset < keylen; block++, offset += length) {
|
|
520
|
+
suffix[0] = block >>> 24;
|
|
521
|
+
suffix[1] = block >>> 16;
|
|
522
|
+
suffix[2] = block >>> 8;
|
|
523
|
+
suffix[3] = block;
|
|
524
|
+
let u = new Hmac(algorithm, password).update(salt).update(suffix).digest() as Buffer;
|
|
525
|
+
const accumulated = HostBuffer.from(u);
|
|
526
|
+
for (let round = 1; round < iterations; round++) {
|
|
527
|
+
const next = new Hmac(algorithm, password).update(u).digest() as Buffer;
|
|
528
|
+
u.fill(0);
|
|
529
|
+
u = next;
|
|
530
|
+
for (let index = 0; index < length; index++) accumulated[index] ^= u[index];
|
|
531
|
+
}
|
|
532
|
+
derived.set(accumulated.subarray(0, Math.min(length, keylen - offset)), offset);
|
|
533
|
+
u.fill(0);
|
|
534
|
+
accumulated.fill(0);
|
|
535
|
+
}
|
|
536
|
+
return Buffer.from(derived);
|
|
537
|
+
} finally {
|
|
538
|
+
password.fill(0);
|
|
539
|
+
salt.fill(0);
|
|
540
|
+
derived.fill(0);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
export function pbkdf2Sync(
|
|
545
|
+
password: BinaryLike,
|
|
546
|
+
salt: BinaryLike,
|
|
547
|
+
iterations: number,
|
|
548
|
+
keylen: number,
|
|
549
|
+
digest: string
|
|
550
|
+
): Buffer {
|
|
551
|
+
return derive(pbkdf2Parameters(password, salt, iterations, keylen, digest));
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
export function pbkdf2(
|
|
555
|
+
password: BinaryLike,
|
|
556
|
+
salt: BinaryLike,
|
|
557
|
+
iterations: number,
|
|
558
|
+
keylen: number,
|
|
559
|
+
digest: string,
|
|
560
|
+
callback: (err: Error | null, derivedKey?: Buffer) => void
|
|
561
|
+
): void {
|
|
562
|
+
if (typeof callback !== 'function') throw new TypeError('PBKDF2 callback must be a function.');
|
|
563
|
+
// Node validates its arguments synchronously and calls back later.
|
|
564
|
+
const parameters = pbkdf2Parameters(password, salt, iterations, keylen, digest);
|
|
565
|
+
setTimeout(() => {
|
|
566
|
+
let key: Buffer;
|
|
567
|
+
try {
|
|
568
|
+
key = derive(parameters);
|
|
569
|
+
} catch (error) {
|
|
570
|
+
callback(error as Error);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
callback(null, key);
|
|
574
|
+
}, 0);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
// ============================================================================
|
|
579
|
+
// Sign and Verify (main functions jose uses)
|
|
580
|
+
// ============================================================================
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Calculates and returns a signature for data using the given private key
|
|
584
|
+
* This is the one-shot API that jose uses
|
|
585
|
+
*/
|
|
586
|
+
export function sign(
|
|
587
|
+
algorithm: string | null | undefined,
|
|
588
|
+
data: Buffer | Uint8Array,
|
|
589
|
+
key: KeyLike,
|
|
590
|
+
callback?: (error: Error | null, signature: Buffer) => void
|
|
591
|
+
): Buffer | void {
|
|
592
|
+
// Get the actual key material and algorithm
|
|
593
|
+
const keyInfo = extractKeyInfo(key);
|
|
594
|
+
const alg = algorithm || keyInfo.algorithm;
|
|
595
|
+
|
|
596
|
+
if (!alg) {
|
|
597
|
+
const error = new Error('Algorithm must be specified');
|
|
598
|
+
if (callback) {
|
|
599
|
+
callback(error, null as unknown as Buffer);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
throw error;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// For async operation with callback
|
|
606
|
+
if (callback) {
|
|
607
|
+
signAsync(alg, data, keyInfo)
|
|
608
|
+
.then(sig => callback(null, sig))
|
|
609
|
+
.catch(err => callback(err, null as unknown as Buffer));
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Synchronous operation - we need to use a workaround
|
|
614
|
+
// Store the promise result for later retrieval
|
|
615
|
+
const result = signSync(alg, data, keyInfo);
|
|
616
|
+
return result;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Verifies the given signature for data using the given key
|
|
621
|
+
*/
|
|
622
|
+
export function verify(
|
|
623
|
+
algorithm: string | null | undefined,
|
|
624
|
+
data: Buffer | Uint8Array,
|
|
625
|
+
key: KeyLike,
|
|
626
|
+
signature: Buffer | Uint8Array,
|
|
627
|
+
callback?: (error: Error | null, result: boolean) => void
|
|
628
|
+
): boolean | void {
|
|
629
|
+
const keyInfo = extractKeyInfo(key);
|
|
630
|
+
const alg = algorithm || keyInfo.algorithm;
|
|
631
|
+
|
|
632
|
+
if (!alg) {
|
|
633
|
+
const error = new Error('Algorithm must be specified');
|
|
634
|
+
if (callback) {
|
|
635
|
+
callback(error, false);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
throw error;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
if (callback) {
|
|
642
|
+
verifyAsync(alg, data, keyInfo, signature)
|
|
643
|
+
.then(result => callback(null, result))
|
|
644
|
+
.catch(err => callback(err, false));
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
return verifySync(alg, data, keyInfo, signature);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// ============================================================================
|
|
652
|
+
// createSign / createVerify (streaming API)
|
|
653
|
+
// ============================================================================
|
|
654
|
+
|
|
655
|
+
export function createSign(algorithm: string): Sign {
|
|
656
|
+
return new Sign(algorithm);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
export function createVerify(algorithm: string): Verify {
|
|
660
|
+
return new Verify(algorithm);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
class Sign extends EventEmitter {
|
|
664
|
+
private algorithm: string;
|
|
665
|
+
private data: Uint8Array[] = [];
|
|
666
|
+
|
|
667
|
+
constructor(algorithm: string) {
|
|
668
|
+
super();
|
|
669
|
+
this.algorithm = algorithm;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
update(data: string | Buffer | Uint8Array, encoding?: string): this {
|
|
673
|
+
const buffer = typeof data === 'string' ? Buffer.from(data) : data;
|
|
674
|
+
this.data.push(buffer);
|
|
675
|
+
return this;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
sign(privateKey: KeyLike, outputEncoding?: string): Buffer | string {
|
|
679
|
+
const combined = concatBuffers(this.data);
|
|
680
|
+
const keyInfo = extractKeyInfo(privateKey);
|
|
681
|
+
const signature = signSync(this.algorithm, combined, keyInfo);
|
|
682
|
+
|
|
683
|
+
if (outputEncoding === 'base64') {
|
|
684
|
+
return btoa(String.fromCharCode(...signature));
|
|
685
|
+
}
|
|
686
|
+
if (outputEncoding === 'hex') {
|
|
687
|
+
return Array.from(signature).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
688
|
+
}
|
|
689
|
+
return signature;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
class Verify extends EventEmitter {
|
|
694
|
+
private algorithm: string;
|
|
695
|
+
private data: Uint8Array[] = [];
|
|
696
|
+
|
|
697
|
+
constructor(algorithm: string) {
|
|
698
|
+
super();
|
|
699
|
+
this.algorithm = algorithm;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
update(data: string | Buffer | Uint8Array, encoding?: string): this {
|
|
703
|
+
const buffer = typeof data === 'string' ? Buffer.from(data) : data;
|
|
704
|
+
this.data.push(buffer);
|
|
705
|
+
return this;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
verify(publicKey: KeyLike, signature: Buffer | string, signatureEncoding?: string): boolean {
|
|
709
|
+
const combined = concatBuffers(this.data);
|
|
710
|
+
const keyInfo = extractKeyInfo(publicKey);
|
|
711
|
+
|
|
712
|
+
let sig: Buffer;
|
|
713
|
+
if (typeof signature === 'string') {
|
|
714
|
+
if (signatureEncoding === 'base64') {
|
|
715
|
+
sig = Buffer.from(atob(signature));
|
|
716
|
+
} else if (signatureEncoding === 'hex') {
|
|
717
|
+
sig = Buffer.from(signature.match(/.{2}/g)!.map(byte => parseInt(byte, 16)));
|
|
718
|
+
} else {
|
|
719
|
+
sig = Buffer.from(signature);
|
|
720
|
+
}
|
|
721
|
+
} else {
|
|
722
|
+
sig = signature;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
return verifySync(this.algorithm, combined, keyInfo, sig);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// ============================================================================
|
|
730
|
+
// KeyObject class (for key management)
|
|
731
|
+
// ============================================================================
|
|
732
|
+
|
|
733
|
+
export class KeyObject {
|
|
734
|
+
private _keyData: CryptoKey | Uint8Array;
|
|
735
|
+
private _type: 'public' | 'private' | 'secret';
|
|
736
|
+
private _algorithm?: string;
|
|
737
|
+
|
|
738
|
+
constructor(type: 'public' | 'private' | 'secret', keyData: CryptoKey | Uint8Array, algorithm?: string) {
|
|
739
|
+
this._type = type;
|
|
740
|
+
this._keyData = keyData;
|
|
741
|
+
this._algorithm = algorithm;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
get type(): string {
|
|
745
|
+
return this._type;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
get asymmetricKeyType(): string | undefined {
|
|
749
|
+
if (this._type === 'secret') return undefined;
|
|
750
|
+
// Infer from algorithm
|
|
751
|
+
if (this._algorithm?.includes('RSA')) return 'rsa';
|
|
752
|
+
if (this._algorithm?.includes('EC') || this._algorithm?.includes('ES')) return 'ec';
|
|
753
|
+
if (this._algorithm?.includes('Ed')) return 'ed25519';
|
|
754
|
+
return undefined;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
get symmetricKeySize(): number | undefined {
|
|
758
|
+
if (this._type !== 'secret') return undefined;
|
|
759
|
+
if (this._keyData instanceof Uint8Array) {
|
|
760
|
+
return this._keyData.length * 8;
|
|
761
|
+
}
|
|
762
|
+
return undefined;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
export(options?: { type?: string; format?: string }): Buffer | string {
|
|
766
|
+
// Simplified export - returns the key data
|
|
767
|
+
if (this._keyData instanceof Uint8Array) {
|
|
768
|
+
return Buffer.from(this._keyData);
|
|
769
|
+
}
|
|
770
|
+
throw new Error('Cannot export CryptoKey synchronously');
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
export function createSecretKey(key: BinaryLike | ArrayBufferView, encoding?: string): KeyObject {
|
|
775
|
+
// Node copies the key material, so a caller that reuses or zeroes its array
|
|
776
|
+
// does not change the key this object holds.
|
|
777
|
+
return new KeyObject('secret', Buffer.from(cryptoBytes(key, encoding, true)));
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
export function createPublicKey(key: KeyLike): KeyObject {
|
|
781
|
+
const keyInfo = extractKeyInfo(key);
|
|
782
|
+
return new KeyObject('public', keyInfo.keyData as Uint8Array, keyInfo.algorithm);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
export function createPrivateKey(key: KeyLike): KeyObject {
|
|
786
|
+
const keyInfo = extractKeyInfo(key);
|
|
787
|
+
return new KeyObject('private', keyInfo.keyData as Uint8Array, keyInfo.algorithm);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// ============================================================================
|
|
791
|
+
// Utility functions
|
|
792
|
+
// ============================================================================
|
|
793
|
+
|
|
794
|
+
export function timingSafeEqual(a: Buffer | Uint8Array, b: Buffer | Uint8Array): boolean {
|
|
795
|
+
if (a.length !== b.length) {
|
|
796
|
+
return false;
|
|
797
|
+
}
|
|
798
|
+
let result = 0;
|
|
799
|
+
for (let i = 0; i < a.length; i++) {
|
|
800
|
+
result |= a[i] ^ b[i];
|
|
801
|
+
}
|
|
802
|
+
return result === 0;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
export function getCiphers(): string[] {
|
|
806
|
+
return ['aes-128-cbc', 'aes-256-cbc', 'aes-128-gcm', 'aes-256-gcm'];
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
export function getHashes(): string[] {
|
|
810
|
+
// What createHash accepts, no more: a name here that createHash rejects
|
|
811
|
+
// sends a guest down a branch that then throws.
|
|
812
|
+
return HASH_ALGORITHMS.slice();
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// ============================================================================
|
|
816
|
+
// Internal helpers
|
|
817
|
+
// ============================================================================
|
|
818
|
+
|
|
819
|
+
type KeyLike = string | Buffer | KeyObject | { key: string | Buffer; passphrase?: string };
|
|
820
|
+
|
|
821
|
+
interface KeyInfo {
|
|
822
|
+
keyData: Uint8Array | CryptoKey;
|
|
823
|
+
algorithm?: string;
|
|
824
|
+
type: 'public' | 'private' | 'secret';
|
|
825
|
+
format: 'pem' | 'der' | 'jwk' | 'raw';
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
function getWebCryptoAlgorithm(nodeAlgorithm: string): { name: string; hash?: string } {
|
|
829
|
+
const alg = nodeAlgorithm.toUpperCase().replace(/[^A-Z0-9]/g, '');
|
|
830
|
+
|
|
831
|
+
// RSA algorithms
|
|
832
|
+
if (alg.includes('RSA')) {
|
|
833
|
+
if (alg.includes('PSS')) {
|
|
834
|
+
const hash = alg.match(/SHA(\d+)/)?.[0] || 'SHA-256';
|
|
835
|
+
return { name: 'RSA-PSS', hash: `SHA-${hash.replace('SHA', '')}` };
|
|
836
|
+
}
|
|
837
|
+
const hash = alg.match(/SHA(\d+)/)?.[0] || 'SHA-256';
|
|
838
|
+
return { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${hash.replace('SHA', '')}` };
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// ECDSA algorithms (ES256, ES384, ES512)
|
|
842
|
+
if (alg.startsWith('ES') || alg.includes('ECDSA')) {
|
|
843
|
+
const bits = alg.match(/\d+/)?.[0] || '256';
|
|
844
|
+
const hash = bits === '512' ? 'SHA-512' : bits === '384' ? 'SHA-384' : 'SHA-256';
|
|
845
|
+
return { name: 'ECDSA', hash };
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// EdDSA (Ed25519)
|
|
849
|
+
if (alg.includes('ED25519') || alg === 'EDDSA') {
|
|
850
|
+
return { name: 'Ed25519' };
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// HMAC
|
|
854
|
+
if (alg.includes('HS') || alg.includes('HMAC')) {
|
|
855
|
+
const bits = alg.match(/\d+/)?.[0] || '256';
|
|
856
|
+
return { name: 'HMAC', hash: `SHA-${bits}` };
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// Default to RSA with SHA-256
|
|
860
|
+
return { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' };
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
function extractKeyInfo(key: KeyLike): KeyInfo {
|
|
864
|
+
if (key instanceof KeyObject) {
|
|
865
|
+
return {
|
|
866
|
+
keyData: (key as any)._keyData,
|
|
867
|
+
algorithm: (key as any)._algorithm,
|
|
868
|
+
type: (key as any)._type,
|
|
869
|
+
format: 'raw',
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
if (typeof key === 'object' && 'key' in key) {
|
|
874
|
+
return extractKeyInfo(key.key);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
const keyStr = typeof key === 'string' ? key : key.toString();
|
|
878
|
+
|
|
879
|
+
// Detect PEM format
|
|
880
|
+
if (keyStr.includes('-----BEGIN')) {
|
|
881
|
+
const isPrivate = keyStr.includes('PRIVATE');
|
|
882
|
+
const isPublic = keyStr.includes('PUBLIC');
|
|
883
|
+
|
|
884
|
+
// Extract the base64 content
|
|
885
|
+
const base64 = keyStr
|
|
886
|
+
.replace(/-----BEGIN [^-]+-----/, '')
|
|
887
|
+
.replace(/-----END [^-]+-----/, '')
|
|
888
|
+
.replace(/\s/g, '');
|
|
889
|
+
|
|
890
|
+
const keyData = Buffer.from(atob(base64));
|
|
891
|
+
|
|
892
|
+
// Try to detect algorithm from key header
|
|
893
|
+
let algorithm: string | undefined;
|
|
894
|
+
if (keyStr.includes('RSA')) algorithm = 'RSA-SHA256';
|
|
895
|
+
else if (keyStr.includes('EC')) algorithm = 'ES256';
|
|
896
|
+
else if (keyStr.includes('ED25519')) algorithm = 'Ed25519';
|
|
897
|
+
|
|
898
|
+
return {
|
|
899
|
+
keyData,
|
|
900
|
+
algorithm,
|
|
901
|
+
type: isPrivate ? 'private' : isPublic ? 'public' : 'secret',
|
|
902
|
+
format: 'pem',
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// Raw key data
|
|
907
|
+
const keyData = typeof key === 'string' ? Buffer.from(key) : key;
|
|
908
|
+
return {
|
|
909
|
+
keyData,
|
|
910
|
+
type: 'secret',
|
|
911
|
+
format: 'raw',
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
function concatBuffers(buffers: Uint8Array[]): Uint8Array {
|
|
916
|
+
const totalLength = buffers.reduce((acc, arr) => acc + arr.length, 0);
|
|
917
|
+
const result = new Uint8Array(totalLength);
|
|
918
|
+
let offset = 0;
|
|
919
|
+
for (const buf of buffers) {
|
|
920
|
+
result.set(buf, offset);
|
|
921
|
+
offset += buf.length;
|
|
922
|
+
}
|
|
923
|
+
return result;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Async implementations using WebCrypto
|
|
927
|
+
async function signAsync(algorithm: string, data: Uint8Array, keyInfo: KeyInfo): Promise<Buffer> {
|
|
928
|
+
const webCryptoAlg = getWebCryptoAlgorithm(algorithm);
|
|
929
|
+
|
|
930
|
+
// WebCrypto's own failure is the answer and reaches the caller's callback.
|
|
931
|
+
// This used to be caught and answered with a hash of key||data called a
|
|
932
|
+
// signature: every real verifier rejected it and no caller could tell it
|
|
933
|
+
// from a signature that had been produced.
|
|
934
|
+
const cryptoKey = await importKey(keyInfo, webCryptoAlg, ['sign']);
|
|
935
|
+
|
|
936
|
+
// Sign the data - convert to ArrayBuffer for WebCrypto compatibility
|
|
937
|
+
const signatureAlg = webCryptoAlg.hash
|
|
938
|
+
? { name: webCryptoAlg.name, hash: webCryptoAlg.hash }
|
|
939
|
+
: { name: webCryptoAlg.name };
|
|
940
|
+
|
|
941
|
+
const dataBuffer = new Uint8Array(data).buffer as ArrayBuffer;
|
|
942
|
+
const signature = await crypto.subtle.sign(signatureAlg, cryptoKey, dataBuffer);
|
|
943
|
+
return Buffer.from(signature);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
async function verifyAsync(
|
|
947
|
+
algorithm: string,
|
|
948
|
+
data: Uint8Array,
|
|
949
|
+
keyInfo: KeyInfo,
|
|
950
|
+
signature: Uint8Array
|
|
951
|
+
): Promise<boolean> {
|
|
952
|
+
const webCryptoAlg = getWebCryptoAlgorithm(algorithm);
|
|
953
|
+
|
|
954
|
+
// As in signAsync: a failure to verify is reported, never answered with a
|
|
955
|
+
// comparison against a fabricated signature.
|
|
956
|
+
const cryptoKey = await importKey(keyInfo, webCryptoAlg, ['verify']);
|
|
957
|
+
|
|
958
|
+
const verifyAlg = webCryptoAlg.hash
|
|
959
|
+
? { name: webCryptoAlg.name, hash: webCryptoAlg.hash }
|
|
960
|
+
: { name: webCryptoAlg.name };
|
|
961
|
+
|
|
962
|
+
// Convert to ArrayBuffer for WebCrypto compatibility
|
|
963
|
+
const sigBuffer = new Uint8Array(signature).buffer as ArrayBuffer;
|
|
964
|
+
const dataBuffer = new Uint8Array(data).buffer as ArrayBuffer;
|
|
965
|
+
return await crypto.subtle.verify(verifyAlg, cryptoKey, sigBuffer, dataBuffer);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// Synchronous asymmetric signing has no browser primitive: WebCrypto's
|
|
969
|
+
// subtle.sign is async and there is no other. Node throws
|
|
970
|
+
// ERR_CRYPTO_UNSUPPORTED_OPERATION for an operation it cannot do, and so does
|
|
971
|
+
// this; what stood here returned syncHash(key || data) as a "signature".
|
|
972
|
+
function signSync(_algorithm: string, _data: Uint8Array, _keyInfo: KeyInfo): Buffer {
|
|
973
|
+
return unsupported('Synchronous signing');
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
function verifySync(
|
|
977
|
+
_algorithm: string,
|
|
978
|
+
_data: Uint8Array,
|
|
979
|
+
_keyInfo: KeyInfo,
|
|
980
|
+
_signature: Uint8Array
|
|
981
|
+
): boolean {
|
|
982
|
+
return unsupported('Synchronous verification');
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
async function importKey(
|
|
986
|
+
keyInfo: KeyInfo,
|
|
987
|
+
algorithm: { name: string; hash?: string },
|
|
988
|
+
usages: KeyUsage[]
|
|
989
|
+
): Promise<CryptoKey> {
|
|
990
|
+
if (keyInfo.keyData instanceof CryptoKey) {
|
|
991
|
+
return keyInfo.keyData;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const keyData = keyInfo.keyData;
|
|
995
|
+
// Convert Uint8Array to ArrayBuffer for WebCrypto compatibility
|
|
996
|
+
const keyBuffer = new Uint8Array(keyData).buffer as ArrayBuffer;
|
|
997
|
+
|
|
998
|
+
// Determine import format
|
|
999
|
+
if (keyInfo.format === 'pem') {
|
|
1000
|
+
// For PEM, we need to use SPKI (public) or PKCS8 (private)
|
|
1001
|
+
const format = keyInfo.type === 'private' ? 'pkcs8' : 'spki';
|
|
1002
|
+
|
|
1003
|
+
const importAlg: RsaHashedImportParams | EcKeyImportParams | Algorithm =
|
|
1004
|
+
algorithm.name === 'ECDSA'
|
|
1005
|
+
? { name: 'ECDSA', namedCurve: 'P-256' }
|
|
1006
|
+
: algorithm.name === 'Ed25519'
|
|
1007
|
+
? { name: 'Ed25519' }
|
|
1008
|
+
: { name: algorithm.name, hash: algorithm.hash || 'SHA-256' };
|
|
1009
|
+
|
|
1010
|
+
return await crypto.subtle.importKey(
|
|
1011
|
+
format,
|
|
1012
|
+
keyBuffer,
|
|
1013
|
+
importAlg,
|
|
1014
|
+
true,
|
|
1015
|
+
usages
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// For raw/secret keys, use raw import
|
|
1020
|
+
if (keyInfo.type === 'secret') {
|
|
1021
|
+
return await crypto.subtle.importKey(
|
|
1022
|
+
'raw',
|
|
1023
|
+
keyBuffer,
|
|
1024
|
+
{ name: algorithm.name, hash: algorithm.hash },
|
|
1025
|
+
true,
|
|
1026
|
+
usages
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
throw new Error(`Unsupported key format: ${keyInfo.format}`);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// ============================================================================
|
|
1034
|
+
// Exports
|
|
1035
|
+
// ============================================================================
|
|
1036
|
+
|
|
1037
|
+
export default {
|
|
1038
|
+
randomBytes,
|
|
1039
|
+
randomFill,
|
|
1040
|
+
randomFillSync,
|
|
1041
|
+
randomUUID,
|
|
1042
|
+
randomInt,
|
|
1043
|
+
getRandomValues,
|
|
1044
|
+
hash,
|
|
1045
|
+
createHash,
|
|
1046
|
+
createHmac,
|
|
1047
|
+
createSign,
|
|
1048
|
+
createVerify,
|
|
1049
|
+
sign,
|
|
1050
|
+
verify,
|
|
1051
|
+
pbkdf2,
|
|
1052
|
+
pbkdf2Sync,
|
|
1053
|
+
timingSafeEqual,
|
|
1054
|
+
getCiphers,
|
|
1055
|
+
getHashes,
|
|
1056
|
+
constants,
|
|
1057
|
+
KeyObject,
|
|
1058
|
+
createSecretKey,
|
|
1059
|
+
createPublicKey,
|
|
1060
|
+
createPrivateKey,
|
|
1061
|
+
};
|