@contrast/stash
v4.4.0
Published
Contrast Security
Downloads
428
Maintainers
Keywords
Readme
@contrast/stash
Node/v8 native module for attaching private data to JavaScript objects.
N.B. The key namespace is flat. To minimize the chance of collisions,
it's important to implement namespacing in the string, e.g. @contrast#rasp
instead of @contrast
or rasp
.
Usage
const { Stash } = require('@contrast/stash');
const stash = new Stash('contrast-security##rasp');
const obj = JSON.parse(req.body);
// the following could be `stash.setData(obj, true)` if no additional
// information is required.
stash.setData(obj, { tracked: true });
// meanwhile, back at the sink...
const trackingData = stash.getData(obj);
if (trackingData) {
// this object is tracked, so check it out.
}
API
The file returns an object implementing the interface defined in index.d.ts.
Building locally
npm run build
will build the project for your current OS and architecture.
npm run build:dev
passes the --debug
flag which can be useful during
development.
npm run download
will pull the most recent build artifacts from GitHub.
Publishing
Simply run npm version
and git push && git push --tags
.
CI will take care of releasing on version-tagged commits.
Supporting Software
Basic leak detection
test/basic.leak.js
is a simple leak detection program that verifies the
basic operation does not leak memory. Run it once with ITERATIONS
set to
1_000_000 then run it again with ITERATIONS
set to 2_000_000. The results
from two of those runs follows. N.B. each iteration executes on a 1ms interval
timer so it's not in a hard loop. This causes the test to take about 17 minutes
per million iterations.
cooldown 0 - startup {
rss: 41754624,
heapTotal: 270336,
heapUsed: -360016,
external: 1992396,
arrayBuffers: 1993208
}
per iteration { rss: 42, heapTotal: 0, heapUsed: -0, external: 2, arrayBuffers: 2 }
// 2 million iterations
cooldown 0 - startup {
rss: 40701952,
heapTotal: 270336,
heapUsed: -458664,
external: 1992396,
arrayBuffers: 1993208
}
per iteration { rss: 20, heapTotal: 0, heapUsed: -0, external: 1, arrayBuffers: 1 }
*/
Benchmarking
The benchmark facility uses simple-bench, a benchmarking tool. The benchmark
definition is scripts/simple-bench/benchmark.js
and the script to run the
benchmarks is scripts/simple-bench/simple-bench.sh
. The shell script rebuilds
stash
with the class implementation included.
Style Guide
See .clang-format.
- 4 spaces for indentation
- open curly brace goes on the same line as the statement
Software Archeology
The distringuish repo was the
starting point for this repo. While the code is completely different, the scaffolding
for prebuildify, the scripts, and the CI are all taken from distringuish
.
main.cc
also contains a C++ class-based implementation instead of the JavaScript
class. It was the first approach and was benchmarked against the second approach, which
turned out to be faster. Defining CLASS_BASED during the compilation will cause that
implementation to be built in addition to the one we're using. It's kept around because:
- it's there and fully tested,
- it's an alternate implementation that uses
v8::Private::New()
to create keys. v8::Private::New()
allows creating anonymous keys whileForApi()
(what the second approach uses) does not.- it's easy to fold the
#ifdef CLASS_BASED
with an editor and skip over it.
References
Things hard to deduce from the v8 and node docs and source code.
How to make a persistent copyable
- https://stackoverflow.com/questions/35248929/prevent-v8local-value-from-being-garbage-collected
Changing the NAPI_VERSION at the top of main.cc can lead to hard-to-decipher errors when building for versions of node that didn't implement that version.
- https://github.com/nodejs/nan/pull/599
- https://github.com/nodejs/nan/issues/587
Standard references
v8 Private docs
- https://v8.github.io/api/head/classv8_1_1Private.html
Nan Private docs
- https://github.com/nodejs/nan/blob/main/doc/maybe_types.md#nanhasprivate
N-API Doesn't do persistent strings
- https://github.com/nodejs/node-addon-api/issues/392
node-addon-api (the object-wrap.md example was my starting point)
- https://github.com/nodejs/node-addon-api/blob/main/doc