@contrast/agent-bundle 5.40.0 → 5.41.0
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/node_modules/@contrast/agent/package.json +11 -11
- package/node_modules/@contrast/agent-swc-plugin/index.js +9 -3
- package/node_modules/@contrast/agent-swc-plugin/methods.js +15 -1
- package/node_modules/@contrast/agent-swc-plugin/package.json +5 -8
- package/node_modules/@contrast/agent-swc-plugin/rewriter.wasm +0 -0
- package/node_modules/@contrast/agentify/lib/index.js +2 -2
- package/node_modules/@contrast/agentify/package.json +15 -14
- package/node_modules/@contrast/architecture-components/package.json +5 -5
- package/node_modules/@contrast/assess/lib/dataflow/propagation/install/util-format.js +44 -21
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/body-parser.js +1 -1
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/koa/koa-bodyparsers.js +3 -1
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/qs6.js +5 -5
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/querystring.js +2 -1
- package/node_modules/@contrast/assess/lib/index.d.ts +0 -1
- package/node_modules/@contrast/assess/lib/make-source-context.js +7 -37
- package/node_modules/@contrast/assess/lib/sampler/common.js +7 -11
- package/node_modules/@contrast/assess/package.json +12 -11
- package/node_modules/@contrast/common/lib/types.d.ts +7 -1
- package/node_modules/@contrast/common/package.json +1 -1
- package/node_modules/@contrast/config/lib/common.js +1 -1
- package/node_modules/@contrast/config/lib/config.js +49 -27
- package/node_modules/@contrast/config/lib/index.d.ts +2 -2
- package/node_modules/@contrast/config/lib/options.js +4 -4
- package/node_modules/@contrast/config/package.json +4 -3
- package/node_modules/@contrast/core/lib/sensitive-data-masking/protect-listener.js +15 -15
- package/node_modules/@contrast/core/package.json +6 -6
- package/node_modules/@contrast/deadzones/package.json +5 -5
- package/node_modules/@contrast/dep-hooks/package.json +3 -3
- package/node_modules/@contrast/esm-hooks/package.json +6 -6
- package/node_modules/@contrast/instrumentation/lib/index.js +0 -1
- package/node_modules/@contrast/instrumentation/package.json +5 -5
- package/node_modules/@contrast/library-analysis/lib/install/library-reporting/dep.json +298 -148
- package/node_modules/@contrast/library-analysis/package.json +4 -4
- package/node_modules/@contrast/logger/lib/serializers.js +2 -2
- package/node_modules/@contrast/logger/package.json +3 -3
- package/node_modules/@contrast/metrics/package.json +6 -6
- package/node_modules/@contrast/patcher/package.json +2 -2
- package/node_modules/@contrast/protect/lib/get-source-context.js +3 -1
- package/node_modules/@contrast/protect/lib/index.js +6 -1
- package/node_modules/@contrast/protect/lib/input-analysis/handlers.js +7 -9
- package/node_modules/@contrast/protect/lib/input-analysis/install/http.js +18 -19
- package/node_modules/@contrast/protect/lib/input-analysis/install/qs6.js +18 -17
- package/node_modules/@contrast/protect/lib/input-analysis/install/universal-cookie4.js +2 -3
- package/node_modules/@contrast/protect/lib/make-source-context.js +22 -66
- package/node_modules/@contrast/protect/lib/semantic-analysis/handlers.js +73 -72
- package/node_modules/@contrast/protect/package.json +11 -11
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/application-activity/index.js +7 -7
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/application-activity/translations.d.ts +3 -3
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/application-activity/translations.js +24 -21
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/traces/index.js +1 -1
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/traces/translations.d.ts +1 -2
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/traces/translations.js +8 -2
- package/node_modules/@contrast/reporter/lib/reporters/security-logger/index.d.ts +2 -2
- package/node_modules/@contrast/reporter/lib/reporters/security-logger/index.js +22 -20
- package/node_modules/@contrast/reporter/package.json +7 -7
- package/node_modules/@contrast/rewriter/lib/index.js +2 -2
- package/node_modules/@contrast/rewriter/package.json +6 -6
- package/node_modules/@contrast/route-coverage/lib/index.js +1 -9
- package/node_modules/@contrast/route-coverage/lib/install/express/express5.js +17 -19
- package/node_modules/@contrast/route-coverage/package.json +8 -8
- package/node_modules/@contrast/scopes/package.json +5 -5
- package/node_modules/@contrast/sec-obs/lib/traces/http.js +2 -2
- package/node_modules/@contrast/sec-obs/lib/traces/http.test.js +17 -0
- package/node_modules/@contrast/sec-obs/lib/traces/outbound-service-call.js +2 -2
- package/node_modules/@contrast/sec-obs/lib/traces/outbound-service-call.test.js +17 -0
- package/node_modules/@contrast/sec-obs/package.json +9 -9
- package/node_modules/@contrast/sources/lib/index.js +109 -0
- package/node_modules/@contrast/sources/lib/index.test.js +120 -0
- package/node_modules/@contrast/{route-coverage/lib/normalized-url-mapper.js → sources/lib/normalized-uri-mapper.js} +10 -3
- package/node_modules/@contrast/sources/lib/normalized-uri-mapper.test.js +59 -0
- package/node_modules/@contrast/{sec-obs/node_modules/@contrast/core/lib/sensitive-data-masking/constants.js → sources/lib/req-data.js} +0 -6
- package/node_modules/@contrast/sources/lib/source-info.js +183 -0
- package/node_modules/@contrast/sources/lib/source-info.test.js +68 -0
- package/node_modules/@contrast/sources/package.json +16 -0
- package/node_modules/@contrast/telemetry/package.json +6 -6
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/experimental_attributes.d.ts +2831 -77
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/experimental_attributes.js +2831 -77
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/experimental_attributes.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/experimental_metrics.d.ts +415 -98
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/experimental_metrics.js +415 -98
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/experimental_metrics.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/stable_attributes.d.ts +106 -0
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/stable_attributes.js +106 -0
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/stable_attributes.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/version.d.ts +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/version.js +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/esm/version.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/experimental_attributes.d.ts +2831 -77
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/experimental_attributes.js +2831 -77
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/experimental_attributes.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/experimental_metrics.d.ts +415 -98
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/experimental_metrics.js +415 -98
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/experimental_metrics.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/stable_attributes.d.ts +106 -0
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/stable_attributes.js +106 -0
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/stable_attributes.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/version.d.ts +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/version.js +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/esnext/version.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/src/experimental_attributes.d.ts +2831 -77
- package/node_modules/@opentelemetry/semantic-conventions/build/src/experimental_attributes.js +2858 -103
- package/node_modules/@opentelemetry/semantic-conventions/build/src/experimental_attributes.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/src/experimental_metrics.d.ts +415 -98
- package/node_modules/@opentelemetry/semantic-conventions/build/src/experimental_metrics.js +420 -102
- package/node_modules/@opentelemetry/semantic-conventions/build/src/experimental_metrics.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/src/stable_attributes.d.ts +106 -0
- package/node_modules/@opentelemetry/semantic-conventions/build/src/stable_attributes.js +106 -0
- package/node_modules/@opentelemetry/semantic-conventions/build/src/stable_attributes.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/src/version.d.ts +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/src/version.js +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/build/src/version.js.map +1 -1
- package/node_modules/@opentelemetry/semantic-conventions/package.json +3 -3
- package/node_modules/@types/node/README.md +2 -2
- package/node_modules/@types/node/fs.d.ts +13 -1
- package/node_modules/@types/node/http.d.ts +4 -19
- package/node_modules/@types/node/inspector.d.ts +53 -0
- package/node_modules/@types/node/package.json +2 -82
- package/node_modules/axios/CHANGELOG.md +17 -0
- package/node_modules/axios/README.md +1 -4
- package/node_modules/axios/dist/axios.js +39 -5
- package/node_modules/axios/dist/axios.js.map +1 -1
- package/node_modules/axios/dist/axios.min.js +2 -2
- package/node_modules/axios/dist/axios.min.js.map +1 -1
- package/node_modules/axios/dist/browser/axios.cjs +46 -9
- package/node_modules/axios/dist/browser/axios.cjs.map +1 -1
- package/node_modules/axios/dist/esm/axios.js +46 -9
- package/node_modules/axios/dist/esm/axios.js.map +1 -1
- package/node_modules/axios/dist/esm/axios.min.js +2 -2
- package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
- package/node_modules/axios/dist/node/axios.cjs +46 -9
- package/node_modules/axios/dist/node/axios.cjs.map +1 -1
- package/node_modules/axios/index.d.cts +13 -2
- package/node_modules/axios/lib/core/Axios.js +2 -2
- package/node_modules/axios/lib/core/mergeConfig.js +1 -1
- package/node_modules/axios/lib/env/data.js +1 -1
- package/node_modules/axios/lib/helpers/throttle.js +1 -1
- package/node_modules/axios/lib/helpers/toURLEncodedForm.js +4 -3
- package/node_modules/axios/lib/utils.js +36 -0
- package/node_modules/axios/package.json +5 -5
- package/node_modules/deepmerge/.editorconfig +7 -0
- package/node_modules/deepmerge/.eslintcache +1 -0
- package/node_modules/deepmerge/changelog.md +167 -0
- package/node_modules/deepmerge/dist/cjs.js +133 -0
- package/node_modules/deepmerge/dist/umd.js +139 -0
- package/node_modules/deepmerge/index.d.ts +20 -0
- package/node_modules/deepmerge/index.js +106 -0
- package/node_modules/deepmerge/license.txt +21 -0
- package/node_modules/deepmerge/package.json +42 -0
- package/node_modules/deepmerge/readme.md +264 -0
- package/node_modules/deepmerge/rollup.config.js +22 -0
- package/node_modules/follow-redirects/package.json +1 -1
- package/node_modules/form-data/CHANGELOG.md +601 -0
- package/node_modules/form-data/{Readme.md → README.md} +4 -4
- package/node_modules/form-data/lib/form_data.js +2 -6
- package/node_modules/form-data/package.json +22 -6
- package/node_modules/nan/.github/workflows/ci.yml +8 -10
- package/node_modules/nan/.pre-commit-config.yaml +8 -0
- package/node_modules/nan/CHANGELOG.md +5 -1
- package/node_modules/nan/README.md +4 -4
- package/node_modules/nan/nan.h +16 -12
- package/node_modules/nan/nan_callbacks.h +13 -0
- package/node_modules/nan/nan_callbacks_12_inl.h +16 -2
- package/node_modules/nan/nan_callbacks_pre_12_inl.h +6 -2
- package/node_modules/nan/nan_maybe_43_inl.h +1 -1
- package/node_modules/nan/nan_maybe_pre_43_inl.h +1 -1
- package/node_modules/nan/nan_scriptorigin.h +11 -9
- package/node_modules/nan/nan_typedarray_contents.h +1 -1
- package/node_modules/nan/package.json +2 -2
- package/package.json +2 -2
- package/node_modules/@contrast/agentify/lib/sources.js +0 -95
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/common/LICENSE +0 -12
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/common/lib/constants.d.ts +0 -385
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/common/lib/constants.js +0 -270
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/common/lib/index.d.ts +0 -40
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/common/lib/index.js +0 -228
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/common/lib/primordials.d.ts +0 -65
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/common/lib/primordials.js +0 -66
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/common/lib/types.d.ts +0 -383
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/common/lib/types.js +0 -30
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/common/package.json +0 -23
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/config/LICENSE +0 -12
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/config/README.md +0 -44
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/config/lib/common.js +0 -131
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/config/lib/config.js +0 -290
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/config/lib/index.d.ts +0 -328
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/config/lib/index.js +0 -29
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/config/lib/options.js +0 -836
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/config/lib/validators.js +0 -23
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/config/package.json +0 -27
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/LICENSE +0 -12
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/README.md +0 -98
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/agent-info.js +0 -36
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/app-info.js +0 -233
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/build-id.js +0 -51
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/capture-stacktrace.js +0 -256
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/contrast-methods.js +0 -155
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/index.d.ts +0 -52
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/ioc/core.js +0 -95
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/is-agent-path.js +0 -37
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/messages.js +0 -28
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/sensitive-data-masking/index.js +0 -63
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/sensitive-data-masking/protect-listener.js +0 -111
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/sensitive-data-masking/server-settings-listener.js +0 -44
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/system-info/cloud-provider-metadata.js +0 -146
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/system-info/index.js +0 -225
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/system-info/linux-os-info.js +0 -137
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/lib/system-info/utils.js +0 -35
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/core/package.json +0 -33
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/LICENSE +0 -12
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/README.md +0 -94
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/export-handler-registry.d.ts +0 -121
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/export-handler-registry.js +0 -206
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/export-hook-descriptor.d.ts +0 -72
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/export-hook-descriptor.js +0 -88
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/handler-invoker.d.ts +0 -46
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/handler-invoker.js +0 -106
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/helpers.d.ts +0 -28
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/helpers.js +0 -66
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/index.d.ts +0 -115
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/index.js +0 -208
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/package-finder.d.ts +0 -43
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/lib/package-finder.js +0 -79
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/dep-hooks/package.json +0 -29
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/logger/LICENSE +0 -12
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/logger/README.md +0 -270
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/logger/lib/index.d.ts +0 -16
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/logger/lib/index.js +0 -132
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/logger/lib/serializers.d.ts +0 -33
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/logger/lib/serializers.js +0 -75
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/logger/lib/utils.d.ts +0 -15
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/logger/lib/utils.js +0 -34
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/logger/package.json +0 -28
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/patcher/LICENSE +0 -12
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/patcher/README.md +0 -51
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/patcher/lib/index.d.ts +0 -101
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/patcher/lib/index.js +0 -544
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/patcher/package.json +0 -25
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/rewriter/LICENSE +0 -12
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/rewriter/README.md +0 -6
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/rewriter/lib/cache.js +0 -318
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/rewriter/lib/index.js +0 -216
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/rewriter/lib/rewrite-is-deadzoned.js +0 -143
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/rewriter/package.json +0 -30
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/LICENSE +0 -12
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/constants.js +0 -26
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/index.d.ts +0 -46
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/index.js +0 -70
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/install/bluebird.js +0 -128
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/install/index.js +0 -34
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/install/mongodb-core.js +0 -83
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/install/mongodb3.js +0 -89
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/install/mongodb4.js +0 -80
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/install/mongodb6.js +0 -46
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/install/mysql.js +0 -151
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/install/redis.js +0 -79
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/lib/utils.js +0 -35
- package/node_modules/@contrast/sec-obs/node_modules/@contrast/scopes/package.json +0 -28
- package/node_modules/form-data/README.md.bak +0 -355
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# `@contrast/patcher`
|
|
2
|
-
|
|
3
|
-
Monkey patching.
|
|
4
|
-
|
|
5
|
-
# Notes on v5 Parity
|
|
6
|
-
|
|
7
|
-
This was ported directly from the `node-agent` but code with every dependency commented out. As a result there are differences in parity.
|
|
8
|
-
|
|
9
|
-
1. Removed dependency on `AsyncStorage`.
|
|
10
|
-
|
|
11
|
-
**Old Behavior**
|
|
12
|
-
|
|
13
|
-
Pre and post hooks only run when async storage context indicates an active request scope.
|
|
14
|
-
|
|
15
|
-
**New Behavior**
|
|
16
|
-
|
|
17
|
-
Hooks always run, independent of request scope.
|
|
18
|
-
|
|
19
|
-
1. Removed dependency on `agent` and `perf-logger`.
|
|
20
|
-
|
|
21
|
-
**Old Behavior**
|
|
22
|
-
|
|
23
|
-
A configuration setting would allow for logging of perf data of hooks and original function calls.
|
|
24
|
-
|
|
25
|
-
**New Behavior**
|
|
26
|
-
|
|
27
|
-
Performance logging of hooks is non-funcitonal.
|
|
28
|
-
|
|
29
|
-
1. Removed the dependency on `scopes`.
|
|
30
|
-
|
|
31
|
-
**Old Behavior**
|
|
32
|
-
|
|
33
|
-
One could specify a `scope` in the hook options and the original function would be run in that scope. This allowed control over when to run instrumentaion based on current scope value.
|
|
34
|
-
|
|
35
|
-
Also, the `alwaysRun` option forced hooks to run independent of scope state.
|
|
36
|
-
|
|
37
|
-
**New Behavior**
|
|
38
|
-
|
|
39
|
-
There are no notions of scopes yet in v5. Patcher instrumentation always runs.
|
|
40
|
-
|
|
41
|
-
The `scope` and `alwaysRun` options are effectively ignored.
|
|
42
|
-
|
|
43
|
-
1. Removed the dependency on `tracker`.
|
|
44
|
-
|
|
45
|
-
**Old Behavior**
|
|
46
|
-
|
|
47
|
-
We used to short-circuit `__add` function if tracker showed all arguments to be untracked.
|
|
48
|
-
|
|
49
|
-
**New Behavior**
|
|
50
|
-
|
|
51
|
-
We do not make this check; no short-circuiting.
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright: 2025 Contrast Security, Inc
|
|
3
|
-
* Contact: support@contrastsecurity.com
|
|
4
|
-
* License: Commercial
|
|
5
|
-
|
|
6
|
-
* NOTICE: This Software and the patented inventions embodied within may only be
|
|
7
|
-
* used as part of Contrast Security’s commercial offerings. Even though it is
|
|
8
|
-
* made available through public repositories, use of this Software is subject to
|
|
9
|
-
* the applicable End User Licensing Agreement found at
|
|
10
|
-
* https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
|
|
11
|
-
* between Contrast Security and the End User. The Software may not be reverse
|
|
12
|
-
* engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
|
-
* way not consistent with the End User License Agreement.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { Logger } from '@contrast/logger';
|
|
17
|
-
|
|
18
|
-
export interface Core {
|
|
19
|
-
logger: Logger;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface HookData<T, P extends readonly any[] = any[], R = any> {
|
|
23
|
-
hooked(...args: P): R;
|
|
24
|
-
orig(...args: P): R;
|
|
25
|
-
funcKey: string;
|
|
26
|
-
obj: T;
|
|
27
|
-
name: string;
|
|
28
|
-
args: P;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface ResultHookData<T, P extends readonly any[] = any[], R = any>
|
|
32
|
-
extends HookData<T, P, R> {
|
|
33
|
-
result: R;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface PreHook<T, P extends readonly any[] = any[], R = any> {
|
|
37
|
-
(data: HookData<T, P, R>): void;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface AroundHook<T, P extends readonly any[] = any[], R = any> {
|
|
41
|
-
(next: () => R, data: HookData<T, P, R>): void;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface PostHook<T, P extends readonly any[] = any[], R = any> {
|
|
45
|
-
(data: ResultHookData<T, P, R>): void
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export type Hook<T, P extends readonly any[] = any[], R = any> =
|
|
49
|
-
PreHook<T, P, R> | AroundHook<T, P, R> | PostHook<T, P, R>;
|
|
50
|
-
|
|
51
|
-
export interface PatchOptions<T, P extends readonly any[] = any[], R = any> {
|
|
52
|
-
name: string;
|
|
53
|
-
patchType: string;
|
|
54
|
-
pre?: PreHook<T, P, R>;
|
|
55
|
-
around?: AroundHook<T, P, R>;
|
|
56
|
-
post?: PostHook<T, P, R>;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export type HookedFunctionsMap = WeakMap<(...args: any[]) => any, {
|
|
60
|
-
fn: (...args: any[]) => any;
|
|
61
|
-
}>;
|
|
62
|
-
|
|
63
|
-
export type HooksMap = WeakMap<(...args: any[]) => any, {
|
|
64
|
-
pre: Map<string, PreHook<any>>,
|
|
65
|
-
around: Map<string, AroundHook<any>>,
|
|
66
|
-
post: Map<string, PostHook<any>>,
|
|
67
|
-
funcKeys: Set<string>,
|
|
68
|
-
}>;
|
|
69
|
-
|
|
70
|
-
export interface Patcher {
|
|
71
|
-
patch<F extends (...args: any[]) => any>(
|
|
72
|
-
fn: F,
|
|
73
|
-
options: PatchOptions<F, Parameters<F>, ReturnType<F>>,
|
|
74
|
-
): F | null;
|
|
75
|
-
|
|
76
|
-
patch<T, K extends keyof T>(
|
|
77
|
-
obj: T,
|
|
78
|
-
method: K,
|
|
79
|
-
options: T[K] extends abstract new (...args: infer P) => infer R
|
|
80
|
-
? PatchOptions<T, P, R>
|
|
81
|
-
: T[K] extends (...args: infer P) => infer R
|
|
82
|
-
? PatchOptions<T, P, R>
|
|
83
|
-
: PatchOptions<T>,
|
|
84
|
-
): T | null;
|
|
85
|
-
|
|
86
|
-
resetInstrumentation(): void;
|
|
87
|
-
unpatch<T extends (...args: any[]) => any>(
|
|
88
|
-
fn: T,
|
|
89
|
-
funcName: string,
|
|
90
|
-
patchType: string,
|
|
91
|
-
): void;
|
|
92
|
-
unwrap<T extends (...args: any[]) => any>(fn: T): T;
|
|
93
|
-
isContrastHooked<T extends (...args: any[]) => any>(fn: T): boolean;
|
|
94
|
-
hookedFunctionToString<T extends (...args: any[]) => any>(fn: T): string;
|
|
95
|
-
hookedFunctions: HookedFunctionsMap;
|
|
96
|
-
hooks: HooksMap;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
declare function init(core: Core): Patcher;
|
|
100
|
-
|
|
101
|
-
export = init;
|
|
@@ -1,544 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright: 2025 Contrast Security, Inc
|
|
3
|
-
* Contact: support@contrastsecurity.com
|
|
4
|
-
* License: Commercial
|
|
5
|
-
|
|
6
|
-
* NOTICE: This Software and the patented inventions embodied within may only be
|
|
7
|
-
* used as part of Contrast Security’s commercial offerings. Even though it is
|
|
8
|
-
* made available through public repositories, use of this Software is subject to
|
|
9
|
-
* the applicable End User Licensing Agreement found at
|
|
10
|
-
* https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
|
|
11
|
-
* between Contrast Security and the End User. The Software may not be reverse
|
|
12
|
-
* engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
|
-
* way not consistent with the End User License Agreement.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
'use strict';
|
|
17
|
-
|
|
18
|
-
const { threadId } = require('worker_threads');
|
|
19
|
-
const { hrtime } = require('process');
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Disable the prefer-rest-params rule, which disallows use of `arguments`.
|
|
23
|
-
* With the way we're monkey patching, it's more semantically correct to use
|
|
24
|
-
* the arguments keyword instead of providing a `...args` rest param.
|
|
25
|
-
*/
|
|
26
|
-
/* eslint-disable prefer-rest-params */
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Checks if the argument is a function
|
|
30
|
-
*/
|
|
31
|
-
function isFunction(fn) {
|
|
32
|
-
// why do both need to be checked?
|
|
33
|
-
return fn instanceof Function || typeof fn === 'function';
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Attempts to find a descriptor for a property on an object or its parents
|
|
38
|
-
*
|
|
39
|
-
* @param {Object} obj the object containing the property we want to get the descriptor of
|
|
40
|
-
* @param {string} prop the property of which we want the get the descriptor of
|
|
41
|
-
* @return {Object|undefined} the descriptor, or undefined if it couldn't get one
|
|
42
|
-
*/
|
|
43
|
-
function getDescriptor(obj, prop) {
|
|
44
|
-
// if it isn't its own property, but a parent's, return writability for the parent
|
|
45
|
-
if (obj && obj[prop] && !Object.getOwnPropertyDescriptor(obj, prop)) {
|
|
46
|
-
const proto = Object.getPrototypeOf(obj);
|
|
47
|
-
return getDescriptor(proto, prop);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return Object.getOwnPropertyDescriptor(obj, prop);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
module.exports = function init(core) {
|
|
54
|
-
const logger = core.logger.child({ name: 'contrast:patcher', tid: threadId });
|
|
55
|
-
const promisifyCustom = Symbol.for('nodejs.util.promisify.custom');
|
|
56
|
-
const perf = new core.Perf('patcher');
|
|
57
|
-
const perfIsEnabled = core.Perf.isEnabled;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @type {WeakMap<Function, { fn: Function }>}
|
|
61
|
-
* allows us to check if a function is hooked without pinning random properties
|
|
62
|
-
* to the function, and lets us reference the original function any time we want
|
|
63
|
-
*/
|
|
64
|
-
const hookedFunctions = new WeakMap();
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* @type {WeakMap<Function, {
|
|
68
|
-
* pre: Map<string, Function>,
|
|
69
|
-
* post: Map<string, Function>,
|
|
70
|
-
* around: Map<string, Function>,
|
|
71
|
-
* funcKeys: Set<string>,
|
|
72
|
-
* }>}
|
|
73
|
-
* mapping of hooked func -> maps of pre/post/around funcs
|
|
74
|
-
*/
|
|
75
|
-
let hooks = new WeakMap();
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* clears instrumentation for all patched functions
|
|
79
|
-
* used in testing for better isolation between tests
|
|
80
|
-
*/
|
|
81
|
-
function resetInstrumentation() {
|
|
82
|
-
hooks = new WeakMap();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Invoke the original function in the current context with the
|
|
87
|
-
* passed-in arguments and store its result
|
|
88
|
-
*
|
|
89
|
-
* @param {Function} fn the function we want to execute
|
|
90
|
-
* @param {Object} data object with the arguments and name of the function
|
|
91
|
-
* @param {any} data.args the arguments for the function execution
|
|
92
|
-
* @param {String} data.name the name of the function
|
|
93
|
-
* @param {any} target the constructor being called (if called with new)
|
|
94
|
-
*/
|
|
95
|
-
function runOriginalFunction(fn, { args, name }, target) {
|
|
96
|
-
if (target) {
|
|
97
|
-
// NODE-818 need to unwrap Object because it does not
|
|
98
|
-
// properly reflect
|
|
99
|
-
if (name === 'Object') {
|
|
100
|
-
target = unwrap(target);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return Reflect.construct(fn, args, target);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return fn.apply(this, args);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Hook the provided function by adding hook calls where appropriate
|
|
111
|
-
*
|
|
112
|
-
* @param {Function} fn original function being hooked
|
|
113
|
-
* @param {Object} options
|
|
114
|
-
* @param {string} options.name - name of the function (usually signature)
|
|
115
|
-
* @returns {Function} the hooked function
|
|
116
|
-
*/
|
|
117
|
-
function hookFunction(fn, options) {
|
|
118
|
-
if (hookedFunctions.has(fn)) {
|
|
119
|
-
// fn has already been hooked
|
|
120
|
-
return fn;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// get the hooked function. it will be either the hooked function with perf
|
|
124
|
-
// or without.
|
|
125
|
-
const hooked = perfIsEnabled && options.usePerf === 'sync' ?
|
|
126
|
-
makePerfHookedFunction(fn, options) :
|
|
127
|
-
makeHookedFunction(fn, options);
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* copy over all properties if there are properties on the original function.
|
|
131
|
-
* an example of this is the version of buffer you get from require('buffer')
|
|
132
|
-
* see NODE-335 for further background.
|
|
133
|
-
*/
|
|
134
|
-
const descriptors = Object.getOwnPropertyDescriptors(fn);
|
|
135
|
-
|
|
136
|
-
for (const key of Object.getOwnPropertyNames(descriptors)) {
|
|
137
|
-
Object.defineProperty(hooked, key, descriptors[key]);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
let descriptor;
|
|
141
|
-
|
|
142
|
-
for (const key of Object.getOwnPropertySymbols(descriptors)) {
|
|
143
|
-
// promisify custom might be the same as the original function. make the property
|
|
144
|
-
// writable and save the descriptor so it can be modified outside of this loop.
|
|
145
|
-
// doing so in the loop causes infinite recursion.
|
|
146
|
-
if (key === promisifyCustom && typeof descriptors[key].value === 'function') {
|
|
147
|
-
descriptors[key].writable = true;
|
|
148
|
-
descriptor = descriptors[key];
|
|
149
|
-
}
|
|
150
|
-
// set the property to a writable copy of the descriptor.
|
|
151
|
-
Object.defineProperty(hooked, key, descriptors[key]);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (descriptor) {
|
|
155
|
-
if (descriptor.value === fn) {
|
|
156
|
-
// promisifyCustom was a circular reference pointing to the original function.
|
|
157
|
-
// change it to point to the hooked function.
|
|
158
|
-
descriptor.value = hooked;
|
|
159
|
-
} else {
|
|
160
|
-
// promisify custom was a function, but it's not the original function. so it
|
|
161
|
-
// must be hooked.
|
|
162
|
-
descriptor.value = hookFunction(descriptor.value, options);
|
|
163
|
-
}
|
|
164
|
-
// for both cases above, we make the property unwritable again.
|
|
165
|
-
descriptor.writable = false;
|
|
166
|
-
Object.defineProperty(hooked, promisifyCustom, descriptor);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (!fn.prototype) hooked.prototype = undefined;
|
|
170
|
-
hookedFunctions.set(hooked, { fn });
|
|
171
|
-
|
|
172
|
-
return hooked;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Attempt to hook a given function or object's property/method
|
|
177
|
-
*
|
|
178
|
-
* @param {Object} obj the object that contains the property/method we want to hook
|
|
179
|
-
* @param {string} prop the property/method of the object that we want to hook
|
|
180
|
-
* @param {Object} opts options for hooking
|
|
181
|
-
* @returns {Function} the hooked function/method
|
|
182
|
-
*/
|
|
183
|
-
function hook(obj, prop, opts) {
|
|
184
|
-
const desc = getDescriptor(obj, prop);
|
|
185
|
-
if (desc.writable || desc.set) {
|
|
186
|
-
obj[prop] = hookFunction(obj[prop], opts);
|
|
187
|
-
return obj[prop];
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const { name, funcKey } = opts;
|
|
191
|
-
|
|
192
|
-
try {
|
|
193
|
-
logger.debug(
|
|
194
|
-
{ funcKey },
|
|
195
|
-
'%s may be unwritable. hooking by defineProperty',
|
|
196
|
-
name,
|
|
197
|
-
);
|
|
198
|
-
if (desc.configurable) {
|
|
199
|
-
if (desc.get) {
|
|
200
|
-
const f = hookFunction(obj[prop], opts);
|
|
201
|
-
Object.defineProperty(obj, prop, {
|
|
202
|
-
get() {
|
|
203
|
-
return f;
|
|
204
|
-
},
|
|
205
|
-
set: desc.set,
|
|
206
|
-
});
|
|
207
|
-
} else if (desc.value) {
|
|
208
|
-
Object.defineProperty(obj, prop, {
|
|
209
|
-
enumerable: desc.enumerable,
|
|
210
|
-
writable: desc.writable,
|
|
211
|
-
configurable: desc.configurable,
|
|
212
|
-
value: hookFunction(obj[prop], opts),
|
|
213
|
-
});
|
|
214
|
-
} else {
|
|
215
|
-
throw new Error('unknown object descriptor setup');
|
|
216
|
-
}
|
|
217
|
-
} else {
|
|
218
|
-
logger.debug(
|
|
219
|
-
{ funcKey },
|
|
220
|
-
'unable to patch unconfigurable property %s',
|
|
221
|
-
name,
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
} catch (err) {
|
|
225
|
-
logger.debug(
|
|
226
|
-
{ err, funcKey },
|
|
227
|
-
'unable to patch unconfigurable property %s',
|
|
228
|
-
name,
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return obj[prop];
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* factory to make a hooked function either with or without perf data. the
|
|
237
|
-
* arguments are exactly the same as `hookFunction`. it exists to create a
|
|
238
|
-
* closure around the `fn` and `options` arguments and to isolate the
|
|
239
|
-
* logic differences in the hooked function to a single place.
|
|
240
|
-
*
|
|
241
|
-
* @param {Function} fn original function being hooked
|
|
242
|
-
* @param {Object} options
|
|
243
|
-
* @param {string} options.name - name of the function (usually signature)
|
|
244
|
-
* @param {'sync'|'async'|undefined} options.usePerf - collect perf data for this hooked function
|
|
245
|
-
* @returns {Function} the hooked function
|
|
246
|
-
*
|
|
247
|
-
*/
|
|
248
|
-
function makeHookedFunction(fn, options) {
|
|
249
|
-
//
|
|
250
|
-
// the hooked function that does not capture perf data. this is very close
|
|
251
|
-
// to the original hooked function. the primary difference is that it does
|
|
252
|
-
// the pre/post hooks in a loop rather than calling a function.
|
|
253
|
-
//
|
|
254
|
-
function hooked(...args) {
|
|
255
|
-
const target = new.target;
|
|
256
|
-
|
|
257
|
-
const data = {
|
|
258
|
-
hooked,
|
|
259
|
-
orig: fn,
|
|
260
|
-
funcKey: options.funcKey,
|
|
261
|
-
obj: new.target || this,
|
|
262
|
-
name: options.name,
|
|
263
|
-
args,
|
|
264
|
-
result: undefined,
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
const fnHooks = hooks.get(hooked);
|
|
268
|
-
if (!fnHooks) {
|
|
269
|
-
return (data.result = runOriginalFunction.call(this, fn, data, target));
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Run pre hooks
|
|
273
|
-
if (fnHooks.pre.size) {
|
|
274
|
-
for (const pre of fnHooks.pre.values()) {
|
|
275
|
-
pre.call(this, data);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (fnHooks.around.size === 0) {
|
|
280
|
-
data.result = runOriginalFunction.call(this, fn, data, target);
|
|
281
|
-
} else {
|
|
282
|
-
// chain around hooks, from last to first to original, via recursion
|
|
283
|
-
const self = this;
|
|
284
|
-
const arounds = Array.from(fnHooks.around.values()).reverse();
|
|
285
|
-
|
|
286
|
-
const pipe = arounds.reduce(
|
|
287
|
-
(innerNext, around) =>
|
|
288
|
-
function next() {
|
|
289
|
-
return around(innerNext, data);
|
|
290
|
-
},
|
|
291
|
-
function next() {
|
|
292
|
-
return runOriginalFunction.call(self, fn, data, target);
|
|
293
|
-
}
|
|
294
|
-
);
|
|
295
|
-
|
|
296
|
-
data.result = pipe();
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Run post hooks
|
|
300
|
-
if (fnHooks.post.size) {
|
|
301
|
-
for (const post of fnHooks.post.values()) {
|
|
302
|
-
post.call(this, data);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return data.result;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return hooked;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
function makePerfHookedFunction(fn, options) {
|
|
313
|
-
//
|
|
314
|
-
// a functional duplicate of hooked, but has perf measurement of the hooked
|
|
315
|
-
// and original functions.
|
|
316
|
-
//
|
|
317
|
-
function perfHooked(...args) {
|
|
318
|
-
// do perf work before getting the start time
|
|
319
|
-
const outerTag = `patcher:${options.name}:wrapper`;
|
|
320
|
-
const innerTag = `${options.name}:native`; // name is patcher:original-function-name
|
|
321
|
-
const start = hrtime.bigint();
|
|
322
|
-
|
|
323
|
-
const target = new.target;
|
|
324
|
-
|
|
325
|
-
const data = {
|
|
326
|
-
hooked: perfHooked,
|
|
327
|
-
orig: fn,
|
|
328
|
-
funcKey: options.funcKey,
|
|
329
|
-
obj: new.target || this,
|
|
330
|
-
name: options.name, //String.prototype.substring
|
|
331
|
-
args,
|
|
332
|
-
result: undefined,
|
|
333
|
-
};
|
|
334
|
-
// create functions to run the original function. this replaces the original
|
|
335
|
-
// `runOriginalFunction()` with one that doesn't require passing arguments. my
|
|
336
|
-
// thinking is that minimizes wrapping overhead.
|
|
337
|
-
let runOriginalFunction;
|
|
338
|
-
if (target) {
|
|
339
|
-
runOriginalFunction = () => Reflect.construct(fn, args, options.name !== 'Object' ? target : unwrap(target));
|
|
340
|
-
} else {
|
|
341
|
-
runOriginalFunction = () => fn.apply(this, args);
|
|
342
|
-
}
|
|
343
|
-
runOriginalFunction = perf.wrapSync(runOriginalFunction, innerTag);
|
|
344
|
-
|
|
345
|
-
// if the function isn't hooked, just run the original function and records the
|
|
346
|
-
// time with a modified tag indicating that it wasn't hooked. i don't think this
|
|
347
|
-
// should happen (why are we in the hooked function if there are no hooks?), but
|
|
348
|
-
// it's here just in case.
|
|
349
|
-
const fnHooks = hooks.get(perfHooked);
|
|
350
|
-
if (!fnHooks) {
|
|
351
|
-
const result = (data.result = runOriginalFunction());
|
|
352
|
-
perf.record(`${outerTag}:unhooked`, start);
|
|
353
|
-
return result;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// Run any pre hooks
|
|
357
|
-
if (fnHooks.pre.size) {
|
|
358
|
-
for (const pre of fnHooks.pre.values()) {
|
|
359
|
-
pre.call(this, data);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// if there are no around hooks, then no need to do the work to chain them.
|
|
364
|
-
if (fnHooks.around.size === 0) {
|
|
365
|
-
data.result = runOriginalFunction();
|
|
366
|
-
} else {
|
|
367
|
-
// chain around hooks, from last to first to original, via recursion
|
|
368
|
-
const arounds = Array.from(fnHooks.around.values()).reverse();
|
|
369
|
-
|
|
370
|
-
const pipe = arounds.reduce(
|
|
371
|
-
(innerNext, around) =>
|
|
372
|
-
function next() {
|
|
373
|
-
return around(innerNext, data);
|
|
374
|
-
},
|
|
375
|
-
function next() {
|
|
376
|
-
return runOriginalFunction();
|
|
377
|
-
}
|
|
378
|
-
);
|
|
379
|
-
|
|
380
|
-
// execute the chained hooks then the original function
|
|
381
|
-
data.result = pipe();
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// Run any post hooks
|
|
385
|
-
if (fnHooks.post.size) {
|
|
386
|
-
for (const post of fnHooks.post.values()) {
|
|
387
|
-
post.call(this, data);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
perf.record(outerTag, start);
|
|
392
|
-
return data.result;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
return perfHooked;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* Patch a given function or object's property with 'pre', 'post',
|
|
400
|
-
* and/or 'around' hooks
|
|
401
|
-
*
|
|
402
|
-
* @param {Function|Object} obj the function we want to patch or the object that contains the said function/method
|
|
403
|
-
* @param {string} prop the object's property/method we want to patch
|
|
404
|
-
* @param {Object} options object containing the different hooks and identifiers for them
|
|
405
|
-
* @returns {Function|Object} the patched function or the object with the patched property/method
|
|
406
|
-
*/
|
|
407
|
-
function patch(obj, prop, options) {
|
|
408
|
-
// If the prop argument was omitted, shift the arguments.
|
|
409
|
-
if (options == null) {
|
|
410
|
-
options = prop;
|
|
411
|
-
prop = null;
|
|
412
|
-
}
|
|
413
|
-
const { patchType, name, pre, post, around } = options;
|
|
414
|
-
|
|
415
|
-
if (!patchType || !name) {
|
|
416
|
-
const err = new Error('patchType and name are required options');
|
|
417
|
-
logger.error({ err, options });
|
|
418
|
-
return null;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
const funcKey = `${patchType}:${name}`;
|
|
422
|
-
options.funcKey = funcKey;
|
|
423
|
-
|
|
424
|
-
if (obj === undefined) {
|
|
425
|
-
logger.error(
|
|
426
|
-
{ funcKey },
|
|
427
|
-
prop ? 'attempted to hook property %s in nonexistent object' : 'attempted to hook nonexistent function',
|
|
428
|
-
prop,
|
|
429
|
-
);
|
|
430
|
-
return null;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
if (!isFunction(obj) && !isFunction(obj[prop])) {
|
|
434
|
-
logger.error(
|
|
435
|
-
{ funcKey, obj },
|
|
436
|
-
prop ? 'attempted to hook property %s that is not a method or does not exist' : 'attempted to hook an object that is not a function',
|
|
437
|
-
prop,
|
|
438
|
-
);
|
|
439
|
-
return null;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// hmmm. if we wrap the fn then hooks.get(fn) won't work if it's patched again.
|
|
443
|
-
// should we hook the wrapped function?
|
|
444
|
-
|
|
445
|
-
// if no property, hook a function directly.
|
|
446
|
-
const fn = prop ? hook(obj, prop, options) : hookFunction(obj, options);
|
|
447
|
-
const fnHooks = hooks.get(fn) || {
|
|
448
|
-
pre: new Map(),
|
|
449
|
-
post: new Map(),
|
|
450
|
-
around: new Map(),
|
|
451
|
-
funcKeys: new Set(),
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
if (fnHooks.funcKeys.has(funcKey)) {
|
|
455
|
-
logger.debug({ funcKey }, '%s already patched. ignoring', funcKey);
|
|
456
|
-
} else {
|
|
457
|
-
if (pre) fnHooks.pre.set(funcKey, pre);
|
|
458
|
-
if (post) fnHooks.post.set(funcKey, post);
|
|
459
|
-
if (around) fnHooks.around.set(funcKey, around);
|
|
460
|
-
fnHooks.funcKeys.add(funcKey);
|
|
461
|
-
}
|
|
462
|
-
hooks.set(fn, fnHooks);
|
|
463
|
-
|
|
464
|
-
if (fn[promisifyCustom] && fn[promisifyCustom] !== fn) {
|
|
465
|
-
hooks.set(fn[promisifyCustom], fnHooks);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/*
|
|
469
|
-
* special case - if a function was being directly hooked, not a property
|
|
470
|
-
* on an object (i.e. module export set to a function) return the patched
|
|
471
|
-
* function
|
|
472
|
-
*/
|
|
473
|
-
if (typeof obj === 'function' && !prop) {
|
|
474
|
-
return fn;
|
|
475
|
-
}
|
|
476
|
-
return obj;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
/**
|
|
480
|
-
* Remove a handler for an event given an id (rule name, key, etc) and an
|
|
481
|
-
* event name
|
|
482
|
-
*
|
|
483
|
-
* @param {Function} fn the function which we want to unpatch
|
|
484
|
-
* @param {string} funcName identifier for thе patch patchType:funcName
|
|
485
|
-
* @param {string} patchType one of patcher.PATCH_TYPES
|
|
486
|
-
*/
|
|
487
|
-
function unpatch(fn, funcName, patchType) {
|
|
488
|
-
const fnHooks = hooks.get(fn);
|
|
489
|
-
|
|
490
|
-
if (!fnHooks) {
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
Object.keys(fnHooks).forEach((key) => {
|
|
494
|
-
fnHooks[key].delete(`${patchType}:${funcName}`);
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* WeakMap lookup to get original, unwrapped version of a function.
|
|
500
|
-
* @param {Function} fn the function of which we want the original
|
|
501
|
-
* @return {Function} the original unpatched function
|
|
502
|
-
*/
|
|
503
|
-
function unwrap(fn) {
|
|
504
|
-
const hooked = hookedFunctions.get(fn);
|
|
505
|
-
return (hooked && hooked.fn) || fn;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* WeakMap lookup to whether the given function is hooked by our hooks.
|
|
510
|
-
* @param {Function} fn the function which we want to check
|
|
511
|
-
* @return {Boolean} true if the function is hooked with Contrast hooks
|
|
512
|
-
*/
|
|
513
|
-
function isContrastHooked(fn) {
|
|
514
|
-
return hookedFunctions.has(fn);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* In case we've monkey-patched the `Function.prototype.toString()` method we
|
|
519
|
-
* may need a way to return the `toString()` value for the hooked function (debug purposes?)
|
|
520
|
-
* @param {Function} fn the function which hooked version we want to run `toString()` against
|
|
521
|
-
* @return {String} returns the `.toString()` result for the hooked version of the function if it's hooked
|
|
522
|
-
* or the `.thoString() value of the non-hooked function otherwise
|
|
523
|
-
*/
|
|
524
|
-
function hookedFunctionToString(fn) {
|
|
525
|
-
const hooked = hookedFunctions.get(fn);
|
|
526
|
-
if (hooked && hooked.fn) {
|
|
527
|
-
return Reflect.apply(Function.prototype.toString, hooked.fn, arguments);
|
|
528
|
-
}
|
|
529
|
-
return Reflect.apply(Function.prototype.toString, fn, arguments);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
core.patcher = {
|
|
533
|
-
patch,
|
|
534
|
-
resetInstrumentation,
|
|
535
|
-
unpatch,
|
|
536
|
-
unwrap,
|
|
537
|
-
isContrastHooked,
|
|
538
|
-
hookedFunctionToString,
|
|
539
|
-
hookedFunctions,
|
|
540
|
-
hooks
|
|
541
|
-
};
|
|
542
|
-
|
|
543
|
-
return core.patcher;
|
|
544
|
-
};
|