@blamejs/pki 0.5.15 → 0.5.16
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/CHANGELOG.md +27 -0
- package/lib/cmp-verify.js +425 -82
- package/lib/guard-all.js +2 -0
- package/lib/guard-async.js +14 -2
- package/lib/guard-bytes.js +183 -93
- package/lib/guard-compress.js +32 -12
- package/lib/guard-der.js +30 -7
- package/lib/guard-encoding.js +28 -12
- package/lib/guard-header.js +18 -7
- package/lib/guard-identifier.js +146 -79
- package/lib/guard-intrinsic.js +318 -0
- package/lib/guard-json.js +39 -12
- package/lib/guard-limits.js +15 -6
- package/lib/guard-name.js +72 -23
- package/lib/guard-parsed.js +71 -34
- package/lib/guard-range.js +17 -4
- package/lib/guard-secret.js +15 -1
- package/lib/guard-text.js +35 -6
- package/lib/guard-time.js +13 -4
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/guard-all.js
CHANGED
|
@@ -67,6 +67,7 @@ var compress = require("./guard-compress");
|
|
|
67
67
|
var secret = require("./guard-secret");
|
|
68
68
|
var parsed = require("./guard-parsed");
|
|
69
69
|
var async_ = require("./guard-async");
|
|
70
|
+
var intrinsic = require("./guard-intrinsic");
|
|
70
71
|
|
|
71
72
|
module.exports = {
|
|
72
73
|
bytes: bytes,
|
|
@@ -85,4 +86,5 @@ module.exports = {
|
|
|
85
86
|
secret: secret,
|
|
86
87
|
parsed: parsed,
|
|
87
88
|
async: async_,
|
|
89
|
+
intrinsic: intrinsic,
|
|
88
90
|
};
|
package/lib/guard-async.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// Copyright (c) blamejs contributors
|
|
3
3
|
"use strict";
|
|
4
|
+
|
|
5
|
+
// The two settle operations, taken at load and uncurried so the call sites read no property of
|
|
6
|
+
// them. These are how a synchronous fault becomes the rejection this guard promises, so a replaced
|
|
7
|
+
// `reject` returning a resolved promise turns a refusal into a pass at the one place the exit shape
|
|
8
|
+
// is decided. See guard-intrinsic for the whole captured set.
|
|
9
|
+
var _intrinsic = require("./guard-intrinsic");
|
|
10
|
+
var _resolve = _intrinsic.uncurry(_intrinsic.promiseResolve);
|
|
11
|
+
var _reject = _intrinsic.uncurry(_intrinsic.promiseReject);
|
|
12
|
+
var _Promise = Promise;
|
|
4
13
|
//
|
|
5
14
|
// @internal -- no operator-facing namespace. The documented surface is every verb whose
|
|
6
15
|
// @signature says `-> Promise<...>`; this is how each of them refuses.
|
|
@@ -29,9 +38,12 @@
|
|
|
29
38
|
// test/layer-0-primitives/promise-contract.test.js, which reads every `-> Promise<` @signature out
|
|
30
39
|
// of lib/ and calls each verb to prove the refusal arrives as a rejection. A new verb is in
|
|
31
40
|
// scope the day it is documented, so no list here can go stale.
|
|
41
|
+
// Both taken at load. These are how a synchronous fault becomes the rejection this guard promises,
|
|
42
|
+
// so a replaced `reject` returning a resolved promise turns a refusal into a pass at the one place
|
|
43
|
+
// the exit shape is decided. See guard-intrinsic for the whole captured set.
|
|
32
44
|
function deferred(body) {
|
|
33
|
-
try { return
|
|
34
|
-
catch (e) { return
|
|
45
|
+
try { return _resolve(_Promise, body()); }
|
|
46
|
+
catch (e) { return _reject(_Promise, e); }
|
|
35
47
|
}
|
|
36
48
|
|
|
37
49
|
module.exports = { deferred: deferred };
|
package/lib/guard-bytes.js
CHANGED
|
@@ -9,7 +9,63 @@
|
|
|
9
9
|
var async = require("./guard-async");
|
|
10
10
|
var identifier = require("./guard-identifier");
|
|
11
11
|
var time = require("./guard-time");
|
|
12
|
-
var
|
|
12
|
+
var intrinsic = require("./guard-intrinsic");
|
|
13
|
+
// The slot predicates, snapshotted at load. `util.types` is an ordinary object, so reading a
|
|
14
|
+
// predicate off it at call time would let a caller decide what this guard calls a typed array, a
|
|
15
|
+
// DataView, an ArrayBuffer or a Proxy -- which is every question this module asks about a value it
|
|
16
|
+
// was handed.
|
|
17
|
+
var util = { types: intrinsic.types };
|
|
18
|
+
var _isArray = intrinsic.isArray;
|
|
19
|
+
// The Buffer constructor, taken at load. It is how this module turns a backing store into
|
|
20
|
+
// something the toolkit can read or clear, so one returning a buffer over DIFFERENT memory hands
|
|
21
|
+
// every later step a decoy: a wipe then zeroes the decoy while the plaintext it was aimed at stays
|
|
22
|
+
// readable, and every check in between still passes.
|
|
23
|
+
var _bufferFrom = intrinsic.bufferFrom;
|
|
24
|
+
// The rest of what this module reads from the runtime while it is deciding something. `isView` is
|
|
25
|
+
// how it recognizes the shape whose backing store must be refused when shared, and the reflective
|
|
26
|
+
// operations are how it inspects a value honestly; a replacement for any of them answers the
|
|
27
|
+
// question this guard asked on the caller's behalf. See guard-intrinsic for the whole set.
|
|
28
|
+
var _isView = intrinsic.isView;
|
|
29
|
+
var _isBuffer = intrinsic.isBuffer;
|
|
30
|
+
var _create = intrinsic.create;
|
|
31
|
+
var _getPrototypeOf = intrinsic.getPrototypeOf;
|
|
32
|
+
var _getOwnPropertyDescriptor = intrinsic.getOwnPropertyDescriptor;
|
|
33
|
+
var _defineProperty = intrinsic.defineProperty;
|
|
34
|
+
var _objectKeys = intrinsic.keys;
|
|
35
|
+
var _isExtensible = intrinsic.isExtensible;
|
|
36
|
+
var _ownKeys = intrinsic.ownKeys;
|
|
37
|
+
var _stringify = intrinsic.stringify;
|
|
38
|
+
// The array operations, uncurried. They run on arrays this module owns, so `Array.prototype` is
|
|
39
|
+
// what a caller can still reach; a `forEach` replaced with a no-op makes a walk over real elements
|
|
40
|
+
// report nothing, and whatever is keyed on that walk then passes vacuously.
|
|
41
|
+
var _forEach = intrinsic.forEach;
|
|
42
|
+
var _map = intrinsic.map;
|
|
43
|
+
var _filter = intrinsic.filter;
|
|
44
|
+
var _reTest = intrinsic.uncurry(RegExp.prototype.test);
|
|
45
|
+
var _setForEach = intrinsic.uncurry(Set.prototype.forEach);
|
|
46
|
+
var _mapForEach = intrinsic.uncurry(Map.prototype.forEach);
|
|
47
|
+
var _String = intrinsic.String;
|
|
48
|
+
// The constructor the private copy of a caller's Date is built with. A replacement returns an
|
|
49
|
+
// object of its own choosing, and the snapshot that is supposed to be ours carries the caller's
|
|
50
|
+
// instant only if they let it.
|
|
51
|
+
var _Date = intrinsic.Date;
|
|
52
|
+
var _apply = intrinsic.apply;
|
|
53
|
+
var _promiseFinally = intrinsic.promiseFinally;
|
|
54
|
+
var _ArrayBuffer = intrinsic.ArrayBuffer;
|
|
55
|
+
var _Uint8Array = intrinsic.Uint8Array;
|
|
56
|
+
var _DataView = intrinsic.DataView;
|
|
57
|
+
var _ObjectProto = intrinsic.ObjectProto;
|
|
58
|
+
// The collection operations. The cycle-safe chain walks are a `Set` this module owns, and the copy
|
|
59
|
+
// writes bytes through the typed-array `set`; a replacement for either decides what the walk sees
|
|
60
|
+
// or what the copy contains.
|
|
61
|
+
var _setAdd = intrinsic.setAdd;
|
|
62
|
+
var _setHas = intrinsic.setHas;
|
|
63
|
+
var _mapSet = intrinsic.mapSet;
|
|
64
|
+
var _taSet = intrinsic.typedArraySet;
|
|
65
|
+
var _Set = intrinsic.Set;
|
|
66
|
+
var _Map = intrinsic.Map;
|
|
67
|
+
// Appended by index rather than through `push`, so the growth reads no prototype method at all.
|
|
68
|
+
function _append(arr, v) { _defineProperty(arr, arr.length, { value: v, writable: true, enumerable: true, configurable: true }); }
|
|
13
69
|
|
|
14
70
|
// isByteSource(x) -> boolean: is this one of the four forms the toolkit calls bytes?
|
|
15
71
|
//
|
|
@@ -21,13 +77,13 @@ var util = require("util");
|
|
|
21
77
|
// @enforced-by behavioral -- a narrowed restatement of a list has no rename-proof code shape;
|
|
22
78
|
// the RED vector (a byte form accepted by one door and refused by the other) is the guard.
|
|
23
79
|
function isByteSource(x) {
|
|
24
|
-
return
|
|
80
|
+
return _isBuffer(x) || _isView(x) || _isArrayBuffer(x);
|
|
25
81
|
}
|
|
26
82
|
|
|
27
83
|
// Is this value a byte store, asked of the internal slot rather than the prototype?
|
|
28
84
|
//
|
|
29
85
|
// `v instanceof ArrayBuffer` answers what a value inherits from, which is a different question
|
|
30
|
-
// from what it holds. `
|
|
86
|
+
// from what it holds. `_create(ArrayBuffer.prototype)` inherits everything and holds no
|
|
31
87
|
// bytes, so it passes and the read that follows throws a raw TypeError out of a boundary whose
|
|
32
88
|
// contract is a typed error. The same test also misses a real buffer from another realm, whose
|
|
33
89
|
// prototype is that realm's. `util.types` reads the slot, so both answers come out right.
|
|
@@ -48,35 +104,30 @@ function _isArrayBuffer(v) {
|
|
|
48
104
|
// The getters are taken off the prototypes the language installs them on and called against the
|
|
49
105
|
// view, which reaches the internal slot whatever the value's own class says. A subclass override
|
|
50
106
|
// is then what it is -- a property of the caller's object -- and answers no question asked here.
|
|
51
|
-
var _TYPED_ARRAY_PROTO =
|
|
107
|
+
var _TYPED_ARRAY_PROTO = _getPrototypeOf(Uint8Array.prototype);
|
|
52
108
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
var
|
|
63
|
-
var _taByteOffset = _intrinsicGetter(_TYPED_ARRAY_PROTO, "byteOffset", "%TypedArray%.prototype");
|
|
64
|
-
var _taByteLength = _intrinsicGetter(_TYPED_ARRAY_PROTO, "byteLength", "%TypedArray%.prototype");
|
|
65
|
-
var _dvBuffer = _intrinsicGetter(DataView.prototype, "buffer", "DataView.prototype");
|
|
66
|
-
var _dvByteOffset = _intrinsicGetter(DataView.prototype, "byteOffset", "DataView.prototype");
|
|
67
|
-
var _dvByteLength = _intrinsicGetter(DataView.prototype, "byteLength", "DataView.prototype");
|
|
109
|
+
// Uncurried as they are captured, so the reads below invoke them directly. A getter taken off a
|
|
110
|
+
// prototype is still reachable there, and an own `call` assigned to it would shadow
|
|
111
|
+
// `Function.prototype.call` and hand back whatever store, offset and length a caller chose. The
|
|
112
|
+
// capture and the refusal for a runtime that lacks the accessor both live in guard-intrinsic, so
|
|
113
|
+
// every guard measuring a view measures it the same way.
|
|
114
|
+
var _uncurriedGetter = intrinsic.getter;
|
|
115
|
+
var _taBuffer = _uncurriedGetter(_TYPED_ARRAY_PROTO, "buffer", "%TypedArray%.prototype");
|
|
116
|
+
var _taByteOffset = _uncurriedGetter(_TYPED_ARRAY_PROTO, "byteOffset", "%TypedArray%.prototype");
|
|
117
|
+
var _dvBuffer = _uncurriedGetter(DataView.prototype, "buffer", "DataView.prototype");
|
|
118
|
+
var _dvByteOffset = _uncurriedGetter(DataView.prototype, "byteOffset", "DataView.prototype");
|
|
68
119
|
|
|
69
120
|
// A DataView carries its own accessors rather than the typed-array ones, so the pair is chosen by
|
|
70
121
|
// the value's slot. Either getter refuses a receiver with no slot behind it, which is the same
|
|
71
122
|
// refusal a detached store gets, and every caller here already types that.
|
|
72
|
-
function _storeOf(v) { return util.types.isDataView(v) ? _dvBuffer
|
|
73
|
-
function _offsetOf(v) { return util.types.isDataView(v) ? _dvByteOffset
|
|
74
|
-
function _lengthOf(v) { return
|
|
123
|
+
function _storeOf(v) { return util.types.isDataView(v) ? _dvBuffer(v) : _taBuffer(v); }
|
|
124
|
+
function _offsetOf(v) { return util.types.isDataView(v) ? _dvByteOffset(v) : _taByteOffset(v); }
|
|
125
|
+
function _lengthOf(v) { return intrinsic.sizeOf(v); }
|
|
75
126
|
|
|
76
127
|
// The Buffer over a view's own bytes. The single place this module turns a view into a Buffer, so
|
|
77
128
|
// the intrinsic reads above cannot be skipped at one of the two call sites and kept at the other.
|
|
78
129
|
function _reView(v) {
|
|
79
|
-
return
|
|
130
|
+
return _bufferFrom(_storeOf(v), _offsetOf(v), _lengthOf(v));
|
|
80
131
|
}
|
|
81
132
|
|
|
82
133
|
// Which concrete typed-array kind a value is, decided by its slot and answered with this realm's
|
|
@@ -97,13 +148,21 @@ function _reView(v) {
|
|
|
97
148
|
// `util.types` is an ordinary object: replacing a predicate on it after this module loads would
|
|
98
149
|
// hand the kind decision, and with it the constructor the copy is built from, to whoever did.
|
|
99
150
|
// Reading it once at load leaves nothing to replace.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
151
|
+
// The two string operations in this table run AT LOAD, in the same statement that reads
|
|
152
|
+
// `util.types` once and for the same reason. Nothing a caller can replace has run yet, so there is
|
|
153
|
+
// no live read to remove; capturing them would only move the question one line earlier.
|
|
154
|
+
var _CONCRETE_KINDS = _filter(
|
|
155
|
+
_map(
|
|
156
|
+
// allow:guard-reads-runtime-live -- module-init, see above
|
|
157
|
+
_filter(_objectKeys(util.types), function (name) { return _reTest(/^is[A-Za-z0-9]+Array$/, name); }),
|
|
158
|
+
// allow:guard-reads-runtime-live -- module-init, see above
|
|
159
|
+
function (name) { return [util.types[name], globalThis[name.slice(2)]]; }
|
|
160
|
+
),
|
|
161
|
+
function (row) {
|
|
104
162
|
return typeof row[0] === "function" && typeof row[1] === "function" &&
|
|
105
163
|
typeof row[1].BYTES_PER_ELEMENT === "number" && row[1].BYTES_PER_ELEMENT > 0;
|
|
106
|
-
}
|
|
164
|
+
}
|
|
165
|
+
);
|
|
107
166
|
|
|
108
167
|
function _concreteKindOf(v) {
|
|
109
168
|
for (var i = 0; i < _CONCRETE_KINDS.length; i++) {
|
|
@@ -116,11 +175,11 @@ function _concreteKindOf(v) {
|
|
|
116
175
|
// `v.constructor.name` is two ordinary property reads a caller answers: a getter under either one
|
|
117
176
|
// took the refusal below out through the caller's exception, in place of the typed error whose
|
|
118
177
|
// whole purpose here is to say why the value was refused.
|
|
119
|
-
var _NAMED_KINDS = [
|
|
178
|
+
var _NAMED_KINDS = _filter([
|
|
120
179
|
["isNativeError", "Error"], ["isRegExp", "RegExp"], ["isPromise", "Promise"],
|
|
121
180
|
["isWeakMap", "WeakMap"], ["isWeakSet", "WeakSet"], ["isMap", "Map"], ["isSet", "Set"],
|
|
122
181
|
["isDate", "Date"], ["isProxy", "Proxy"]
|
|
123
|
-
]
|
|
182
|
+
], function (row) { return typeof util.types[row[0]] === "function"; });
|
|
124
183
|
|
|
125
184
|
function _kindName(v) {
|
|
126
185
|
for (var i = 0; i < _NAMED_KINDS.length; i++) {
|
|
@@ -129,7 +188,7 @@ function _kindName(v) {
|
|
|
129
188
|
return typeof v === "function" ? "function" : "value";
|
|
130
189
|
}
|
|
131
190
|
|
|
132
|
-
function _article(name) { return /^[AEIOU]/i
|
|
191
|
+
function _article(name) { return _reTest(/^[AEIOU]/i, name) ? "an" : "a"; }
|
|
133
192
|
|
|
134
193
|
// outputView(input, ErrorClass, code, label) -> a Buffer aliasing a caller's view, for WRITING.
|
|
135
194
|
//
|
|
@@ -145,7 +204,7 @@ function _article(name) { return /^[AEIOU]/i.test(name) ? "an" : "a"; }
|
|
|
145
204
|
// @enforced-by behavioral -- an input door reaching for this instead of `view` has no rename-proof
|
|
146
205
|
// code shape; the RED vectors (a shared view filled here, and a detached one refused) are the guard.
|
|
147
206
|
function outputView(input, ErrorClass, code, label) {
|
|
148
|
-
if (!util.types.isUint8Array(input) && !
|
|
207
|
+
if (!util.types.isUint8Array(input) && !_isView(input)) {
|
|
149
208
|
throw _raise(ErrorClass, code, label + ": expected a Buffer / TypedArray to write into");
|
|
150
209
|
}
|
|
151
210
|
try {
|
|
@@ -159,7 +218,7 @@ function outputView(input, ErrorClass, code, label) {
|
|
|
159
218
|
//
|
|
160
219
|
// For the boundaries that size a value rather than read it: a response-body cap, an emptiness
|
|
161
220
|
// test. `length` is an accessor on the shared typed-array prototype AND shadowable by an own
|
|
162
|
-
// property on any instance, so `
|
|
221
|
+
// property on any instance, so `_defineProperty(buf, "length", { get: () => 0 })` answers
|
|
163
222
|
// for a Buffer holding megabytes. A cap measured that way is a cap its caller sets.
|
|
164
223
|
// @enforced-by behavioral -- `x.length` is the ordinary spelling wherever the value is this
|
|
165
224
|
// toolkit's own, so the misuse has no rename-proof code shape; the RED vector (a planted `length`
|
|
@@ -178,7 +237,7 @@ function lengthOf(view) {
|
|
|
178
237
|
// container" about a container that plainly holds bytes reads as the toolkit being wrong.
|
|
179
238
|
function _refuseShared(v, ErrorClass, code, label) {
|
|
180
239
|
if (util.types.isSharedArrayBuffer(v) ||
|
|
181
|
-
(
|
|
240
|
+
(_isView(v) && util.types.isSharedArrayBuffer(_storeOf(v)))) {
|
|
182
241
|
throw _raise(ErrorClass, code, label + ": shared memory cannot be used here, because another " +
|
|
183
242
|
"thread can rewrite it after it has been checked; pass a Buffer or a Uint8Array over " +
|
|
184
243
|
"memory this process owns");
|
|
@@ -192,7 +251,7 @@ function _refuseShared(v, ErrorClass, code, label) {
|
|
|
192
251
|
//
|
|
193
252
|
// Defends the detached-buffer fail-OPEN: a transferred / structuredClone'd
|
|
194
253
|
// Buffer or view has a detached backing ArrayBuffer and reads as ZERO-LENGTH.
|
|
195
|
-
// An identity fast-path (`
|
|
254
|
+
// An identity fast-path (`_isBuffer(x) return x`) that skips the re-view
|
|
196
255
|
// hands the caller an empty buffer, so a downstream digest / signature / parse
|
|
197
256
|
// silently processes EMPTY input instead of failing (CWE-20 improper input
|
|
198
257
|
// validation feeding a CWE-347-style verification-of-nothing). Always re-viewing
|
|
@@ -218,8 +277,24 @@ function _refuseShared(v, ErrorClass, code, label) {
|
|
|
218
277
|
// would otherwise have to hand-roll the re-view to reach this guard at all, which is precisely what
|
|
219
278
|
// the re-inline detector forbids, so accept either: a class (its prototype is an Error) is
|
|
220
279
|
// constructed, anything else is called.
|
|
280
|
+
// Whether E's instances would be Errors, decided by walking the prototype chain with the captured
|
|
281
|
+
// `getPrototypeOf` rather than by `instanceof`, which asks `Error[Symbol.hasInstance]` at call time.
|
|
282
|
+
// The walk carries the same visited set _protoChainIsCyclic uses, because a Proxy can report a
|
|
283
|
+
// cyclic chain and an unbounded walk would hang here rather than at the boundary that refuses one.
|
|
284
|
+
var _ErrorProto = Error.prototype;
|
|
285
|
+
function _isErrorClass(E) {
|
|
286
|
+
if (typeof E !== "function") return false;
|
|
287
|
+
var seen = new _Set();
|
|
288
|
+
for (var p = E.prototype; p !== null && typeof p === "object"; p = _getPrototypeOf(p)) {
|
|
289
|
+
if (p === _ErrorProto) return true;
|
|
290
|
+
if (_setHas(seen, p)) return false;
|
|
291
|
+
_setAdd(seen, p);
|
|
292
|
+
}
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
|
|
221
296
|
function _raise(E, code, message, cause) {
|
|
222
|
-
return (E
|
|
297
|
+
return _isErrorClass(E) ? new E(code, message, cause) : E(code, message, cause);
|
|
223
298
|
}
|
|
224
299
|
|
|
225
300
|
// view(input, ErrorClass, code, label) -> Buffer view | throws ErrorClass(code, msg, cause)
|
|
@@ -228,7 +303,7 @@ function _raise(E, code, message, cause) {
|
|
|
228
303
|
// threaded as the cause).
|
|
229
304
|
// The kind is read from the slot. A prototype test turns away a real Uint8Array built in another
|
|
230
305
|
// realm, whose prototype is that realm's, and tells the caller their bytes are not bytes. It
|
|
231
|
-
// admits the mirror shape, `
|
|
306
|
+
// admits the mirror shape, `_create(Uint8Array.prototype)`, which holds none; that one comes
|
|
232
307
|
// back as this guard's own code either way, since the read below is wrapped, so reading the slot
|
|
233
308
|
// only moves the refusal to the door from the failing read.
|
|
234
309
|
// @enforced-by guard-shape-reinlined
|
|
@@ -261,9 +336,9 @@ function view(input, ErrorClass, code, label) {
|
|
|
261
336
|
function source(input, ErrorClass, code, label) {
|
|
262
337
|
_refuseShared(input, ErrorClass, code, label);
|
|
263
338
|
var isAb = _isArrayBuffer(input);
|
|
264
|
-
if (isAb ||
|
|
339
|
+
if (isAb || _isView(input)) {
|
|
265
340
|
try {
|
|
266
|
-
return isAb ?
|
|
341
|
+
return isAb ? _bufferFrom(input) : _reView(input);
|
|
267
342
|
} catch (e) {
|
|
268
343
|
throw _raise(ErrorClass, code, label + ": input is not a usable byte source (detached backing buffer?)", e);
|
|
269
344
|
}
|
|
@@ -292,7 +367,7 @@ function source(input, ErrorClass, code, label) {
|
|
|
292
367
|
// that mutates the caller's buffer between parse and verify and asserts the
|
|
293
368
|
// verdict still describes the bytes that were verified.
|
|
294
369
|
function snapshot(input, ErrorClass, code, label) {
|
|
295
|
-
return
|
|
370
|
+
return _bufferFrom(view(input, ErrorClass, code, label));
|
|
296
371
|
}
|
|
297
372
|
|
|
298
373
|
// snapshotSource(input, ErrorClass, code, label) -> private Buffer copy | throws
|
|
@@ -304,7 +379,7 @@ function snapshot(input, ErrorClass, code, label) {
|
|
|
304
379
|
// @enforced-by behavioral -- a copy has no rename-proof shape to detect; the guard
|
|
305
380
|
// is the RED vector that mutates the caller's backing buffer across the await.
|
|
306
381
|
function snapshotSource(input, ErrorClass, code, label) {
|
|
307
|
-
return
|
|
382
|
+
return _bufferFrom(source(input, ErrorClass, code, label));
|
|
308
383
|
}
|
|
309
384
|
|
|
310
385
|
// snapshotDeep(value, ErrorClass, code, label) -> a private copy of every byte leaf | throws
|
|
@@ -369,8 +444,8 @@ function snapshotDeep(value, ErrorClass, code, label, opts) {
|
|
|
369
444
|
// `Symbol.toStringTag` is on every surface: it is the language's own name for what a value is, a
|
|
370
445
|
// key handle carries it as a non-enumerable own property, and it answers no named option.
|
|
371
446
|
function _surface(names) {
|
|
372
|
-
var t =
|
|
373
|
-
names
|
|
447
|
+
var t = _create(null);
|
|
448
|
+
_forEach(names, function (n) { t[n] = 1; });
|
|
374
449
|
t[Symbol.toStringTag] = 1;
|
|
375
450
|
return t;
|
|
376
451
|
}
|
|
@@ -399,20 +474,26 @@ var _THENABLE_SURFACE = _surface(["then", "catch", "finally"]);
|
|
|
399
474
|
// object literal is never opaque whatever it looks like: it is data this module can read and copy,
|
|
400
475
|
// and isCryptoKeyLike is structural by design so a literal can wear the key shape.
|
|
401
476
|
function _opaqueSurface(v, ErrorClass, code, label) {
|
|
402
|
-
var proto =
|
|
403
|
-
if (proto ===
|
|
404
|
-
|
|
405
|
-
|
|
477
|
+
var proto = _getPrototypeOf(v);
|
|
478
|
+
if (proto === _ObjectProto || proto === null) return null;
|
|
479
|
+
// Deliberately empty, and null-prototype so it stays empty: this surface is the allowed-field set
|
|
480
|
+
// for a value with no enumerable contents, and on a `{}` a planted `Object.prototype[name]` reads
|
|
481
|
+
// back as an allowed field, so a mutable one the caller added would pass the refusal.
|
|
482
|
+
if (util.types.isWeakMap(v) || util.types.isWeakSet(v)) return _create(null);
|
|
483
|
+
// The slot, not the prototype. This picks which surface an opaque object is copied through, and
|
|
484
|
+
// `instanceof` asks `Error[Symbol.hasInstance]`, which a caller can answer. It also admits a real
|
|
485
|
+
// Error from another realm, whose prototype is that realm's and which the prototype test refuses.
|
|
486
|
+
if (util.types.isNativeError(v)) return _ERROR_SURFACE;
|
|
406
487
|
if (util.types.isRegExp(v)) return _REGEXP_SURFACE;
|
|
407
488
|
// A node:crypto KeyObject, read off its internal slot. `pki.hpke` documents one as a key input
|
|
408
489
|
// and `pki.ct` names it too, and a copy of a key handle is not a key: its material lives behind
|
|
409
490
|
// the slot, so what the copy holds is the shape of a key and none of the key. Recognized here so
|
|
410
491
|
// it reaches the verb as itself, which is the same treatment a WebCrypto CryptoKey gets.
|
|
411
492
|
// `util.types.isKeyObject` reads the slot, so it answers for a handle from any realm and says no
|
|
412
|
-
// to `
|
|
493
|
+
// to `_create(KeyObject.prototype)`.
|
|
413
494
|
if (util.types.isKeyObject(v)) return _CRYPTO_KEY_SURFACE;
|
|
414
495
|
// Asking whether it is key-shaped reads its properties, and a value wearing a key's prototype
|
|
415
|
-
// without a key behind it answers with a getter that throws: `
|
|
496
|
+
// without a key behind it answers with a getter that throws: `_create(KeyObject.prototype)`
|
|
416
497
|
// raises a raw TypeError from inside `type`. Typed here, like the `then` read below, so a
|
|
417
498
|
// question this module asked on its own behalf cannot escape as somebody else's error.
|
|
418
499
|
var keyLike;
|
|
@@ -451,17 +532,17 @@ function _opaqueSurface(v, ErrorClass, code, label) {
|
|
|
451
532
|
// call and change what an inherited name answers. That is true of every value passed by reference,
|
|
452
533
|
// and a platform object's prototype is the platform's.
|
|
453
534
|
function _canChangeAfterTheCheck(v, name) {
|
|
454
|
-
var visited = new
|
|
455
|
-
for (var o = v; o && !visited
|
|
456
|
-
visited
|
|
457
|
-
var d =
|
|
535
|
+
var visited = new _Set();
|
|
536
|
+
for (var o = v; o && !_setHas(visited, o); o = _getPrototypeOf(o)) {
|
|
537
|
+
_setAdd(visited, o);
|
|
538
|
+
var d = _getOwnPropertyDescriptor(o, name);
|
|
458
539
|
if (!d) continue;
|
|
459
540
|
if (d.get || d.set || d.writable || d.configurable) return true;
|
|
460
541
|
// Settled where it sits. Reached through the chain it is settled only while nothing can be put
|
|
461
542
|
// in front of it: an extensible receiver takes an own property of the same name at any time,
|
|
462
543
|
// and the read then answers with that one. Own on the value itself, or a value nothing can be
|
|
463
544
|
// added to, is the case where what was read is what stays.
|
|
464
|
-
return o !== v &&
|
|
545
|
+
return o !== v && _isExtensible(v);
|
|
465
546
|
}
|
|
466
547
|
return false;
|
|
467
548
|
}
|
|
@@ -541,13 +622,18 @@ function _opaqueFieldOutsideSurface(v, surface, ErrorClass, code, label, depth)
|
|
|
541
622
|
// field takes, so the copy preserves the type and the validator still sees what it was given.
|
|
542
623
|
function _copyBytesSameKind(v, ErrorClass, code, label, collect) {
|
|
543
624
|
var src = source(v, ErrorClass, code, label); // re-views; a detached backing store is refused
|
|
544
|
-
|
|
545
|
-
|
|
625
|
+
// Sized once, from the slot. `src.length` is a replaceable accessor, and it decides three things
|
|
626
|
+
// here at once: how large the private store is, how much of it the returned view covers, and how
|
|
627
|
+
// much of it goes on the wipe list. A number smaller than the truth puts a short Buffer on that
|
|
628
|
+
// list, so `release` clears the front of a copy that still holds the rest of the secret.
|
|
629
|
+
var srcLen = _lengthOf(src);
|
|
630
|
+
var owned = new _ArrayBuffer(srcLen);
|
|
631
|
+
_taSet(new _Uint8Array(owned), src);
|
|
546
632
|
// What `release` clears: a Buffer over the whole private store, whatever kind is handed back.
|
|
547
|
-
if (collect) collect
|
|
548
|
-
if (
|
|
633
|
+
if (collect) _append(collect, _bufferFrom(owned, 0, srcLen));
|
|
634
|
+
if (_isBuffer(v)) return _bufferFrom(owned, 0, srcLen);
|
|
549
635
|
if (_isArrayBuffer(v)) return owned;
|
|
550
|
-
if (util.types.isDataView(v)) return new
|
|
636
|
+
if (util.types.isDataView(v)) return new _DataView(owned);
|
|
551
637
|
// The kind comes from the value's slot, never from `v.constructor` or `v.BYTES_PER_ELEMENT`.
|
|
552
638
|
// Both are ordinary properties a subclass answers: a `constructor` that threw took this module
|
|
553
639
|
// out through the caller's own exception, and a `BYTES_PER_ELEMENT` that lied built the copy
|
|
@@ -558,7 +644,7 @@ function _copyBytesSameKind(v, ErrorClass, code, label, collect) {
|
|
|
558
644
|
(util.types.isTypedArray(v) ? "typed array of a kind this runtime added" : "byte view") +
|
|
559
645
|
" cannot be copied while keeping its kind; pass a Buffer or a Uint8Array");
|
|
560
646
|
}
|
|
561
|
-
return new Ctor(owned, 0,
|
|
647
|
+
return new Ctor(owned, 0, srcLen / Ctor.BYTES_PER_ELEMENT);
|
|
562
648
|
}
|
|
563
649
|
|
|
564
650
|
// Is this value's prototype chain cyclic? A Proxy whose `getPrototypeOf` trap returns the proxy
|
|
@@ -572,10 +658,10 @@ function _copyBytesSameKind(v, ErrorClass, code, label, collect) {
|
|
|
572
658
|
// Naming the shape is the fail-closed answer. An options bag cannot need a prototype chain that
|
|
573
659
|
// loops, and copying one has no meaning to fall back to.
|
|
574
660
|
function _protoChainIsCyclic(v) {
|
|
575
|
-
var visited = new
|
|
576
|
-
for (var o = v; o; o =
|
|
577
|
-
if (visited
|
|
578
|
-
visited
|
|
661
|
+
var visited = new _Set();
|
|
662
|
+
for (var o = v; o; o = _getPrototypeOf(o)) {
|
|
663
|
+
if (_setHas(visited, o)) return true;
|
|
664
|
+
_setAdd(visited, o);
|
|
579
665
|
}
|
|
580
666
|
return false;
|
|
581
667
|
}
|
|
@@ -584,9 +670,9 @@ function _protoChainIsCyclic(v) {
|
|
|
584
670
|
// above a plain object decides what the copy takes while the original answers reads from its
|
|
585
671
|
// `get` trap. Testing only the value handed in leaves that one line of indirection open.
|
|
586
672
|
function _protoChainHasProxy(v) {
|
|
587
|
-
var visited = new
|
|
588
|
-
for (var o = v; o && !visited
|
|
589
|
-
visited
|
|
673
|
+
var visited = new _Set();
|
|
674
|
+
for (var o = v; o && !_setHas(visited, o); o = _getPrototypeOf(o)) {
|
|
675
|
+
_setAdd(visited, o);
|
|
590
676
|
if (util.types.isProxy(o)) return true;
|
|
591
677
|
}
|
|
592
678
|
return false;
|
|
@@ -594,7 +680,7 @@ function _protoChainHasProxy(v) {
|
|
|
594
680
|
|
|
595
681
|
// Give the copy of a collection the same prototype the original carries.
|
|
596
682
|
//
|
|
597
|
-
// The object branch does this with `
|
|
683
|
+
// The object branch does this with `_create(_getPrototypeOf(v))`, so an instance of a
|
|
598
684
|
// caller's class keeps its methods. A collection branch builds a plain `[]`, `Map` or `Set`, and
|
|
599
685
|
// a subclass of one holds its additions on a prototype above that. Copying the chain down onto a
|
|
600
686
|
// plain array turns `class Opts extends Array { describe() {} }` into an array with `describe` as
|
|
@@ -646,7 +732,7 @@ function _deep(v, ErrorClass, code, label, cap, depth, collect) {
|
|
|
646
732
|
throw _raise(ErrorClass, code, label + ": its prototype chain is a cycle, so it cannot be " +
|
|
647
733
|
"read or copied; pass a plain object");
|
|
648
734
|
}
|
|
649
|
-
if (
|
|
735
|
+
if (_isBuffer(v) || _isView(v) || _isArrayBuffer(v)) {
|
|
650
736
|
var bytesCopy = _copyBytesSameKind(v, ErrorClass, code, label, collect);
|
|
651
737
|
// A byte value can carry named properties too, and a verb reads an option by name whatever the
|
|
652
738
|
// argument's type: `opts = new Uint8Array(0); opts.pem = true` is an options object as far as
|
|
@@ -678,11 +764,11 @@ function _deep(v, ErrorClass, code, label, cap, depth, collect) {
|
|
|
678
764
|
// signing time was encoded. Normalizing the prototype does not reach an own shadow, so the
|
|
679
765
|
// shadow is left behind here. The excluded set is read off `Date.prototype` rather than
|
|
680
766
|
// written out, so it cannot fall behind the language.
|
|
681
|
-
var dateCopy = new
|
|
767
|
+
var dateCopy = new _Date(time.instantOf(v));
|
|
682
768
|
_copyNamed(v, dateCopy, ErrorClass, code, label, cap, depth, collect, _DATE_BEHAVIOR);
|
|
683
769
|
return _plainCopy(dateCopy);
|
|
684
770
|
}
|
|
685
|
-
if (
|
|
771
|
+
if (_isArray(v)) {
|
|
686
772
|
var arr = [];
|
|
687
773
|
// The indices a read on the array resolves, rather than a count from zero to `length`. An
|
|
688
774
|
// array is sparse whenever a caller sets a high index or assigns `length`, and
|
|
@@ -705,7 +791,7 @@ function _deep(v, ErrorClass, code, label, cap, depth, collect) {
|
|
|
705
791
|
// it pays, an element answering as a trusted signer to the check and as another afterwards.
|
|
706
792
|
// The argument itself, not everything under it, matching the rule for names.
|
|
707
793
|
if (depth === 0) identifier.refuseAccessorFields(v, indices, indexE, code, label);
|
|
708
|
-
indices
|
|
794
|
+
_forEach(indices, function (k) {
|
|
709
795
|
// Reading an element can run a caller's accessor, the same as reading a named field: an
|
|
710
796
|
// index can carry a getter too, and one that threw escaped as itself from a boundary whose
|
|
711
797
|
// contract is a typed error. Typed here with the raw fault as its cause, as the named walk
|
|
@@ -735,15 +821,15 @@ function _deep(v, ErrorClass, code, label, cap, depth, collect) {
|
|
|
735
821
|
var carried = _opaqueFieldOutsideSurface(v, surface, ErrorClass, code, label);
|
|
736
822
|
if (carried === null) return v;
|
|
737
823
|
throw _raise(ErrorClass, code, label + ": " + _article(_kindName(v)) + " " + _kindName(v) +
|
|
738
|
-
" carrying its own field " +
|
|
824
|
+
" carrying its own field " + _stringify(_String(carried)) + " cannot be used here -- its " +
|
|
739
825
|
"state cannot be copied, so that field would stay changeable after it was checked; pass the " +
|
|
740
826
|
"fields as a plain object");
|
|
741
827
|
}
|
|
742
828
|
if (util.types.isMap(v)) {
|
|
743
|
-
return _plainCopy(_copyEntries(v, new
|
|
829
|
+
return _plainCopy(_copyEntries(v, new _Map(), ErrorClass, code, label, cap, depth, collect));
|
|
744
830
|
}
|
|
745
831
|
if (util.types.isSet(v)) {
|
|
746
|
-
return _plainCopy(_copyEntries(v, new
|
|
832
|
+
return _plainCopy(_copyEntries(v, new _Set(), ErrorClass, code, label, cap, depth, collect));
|
|
747
833
|
}
|
|
748
834
|
// A plain object, or a dictionary with no prototype at all -- never the caller's class.
|
|
749
835
|
//
|
|
@@ -752,11 +838,11 @@ function _deep(v, ErrorClass, code, label, cap, depth, collect) {
|
|
|
752
838
|
// begun. The names the copy reports do not depend on it, which the vectors measure rather than
|
|
753
839
|
// assume, and no verb calls a method on an options bag.
|
|
754
840
|
//
|
|
755
|
-
// Having NO prototype is different and is kept. `
|
|
841
|
+
// Having NO prototype is different and is kept. `_create(null)` and what `JSON.parse`
|
|
756
842
|
// produces inherit nothing, and a copy that gained `Object.prototype` would inherit whatever a
|
|
757
843
|
// runtime has planted there -- names the original never answered, reported against a caller who
|
|
758
844
|
// never wrote them.
|
|
759
|
-
var out =
|
|
845
|
+
var out = _create(_getPrototypeOf(v) === null ? null : _ObjectProto);
|
|
760
846
|
_copyNamed(v, out, ErrorClass, code, label, cap, depth, collect);
|
|
761
847
|
return out;
|
|
762
848
|
}
|
|
@@ -782,7 +868,7 @@ function _deep(v, ErrorClass, code, label, cap, depth, collect) {
|
|
|
782
868
|
// One walk answers for both questions, because a second walk here drifts from it and the two then
|
|
783
869
|
// disagree about one value. A walk that stops at whatever object is identical to `Object.prototype`
|
|
784
870
|
// reads a foreign realm's root as caller data and copies `__proto__` down as a field. One that
|
|
785
|
-
// reads every level outside a collection gives `
|
|
871
|
+
// reads every level outside a collection gives `_create(Array.prototype)` an own `length`
|
|
786
872
|
// and `Symbol.unscopables`. Either way the copy holds a different set than the check accepted, and
|
|
787
873
|
// a bag that passes the check is refused once it has been copied.
|
|
788
874
|
//
|
|
@@ -810,12 +896,14 @@ function _copyEntries(src, dst, ErrorClass, code, label, cap, depth, collect) {
|
|
|
810
896
|
// The walk uses the intrinsic `forEach`, called against the collection. `forEach` is an ordinary
|
|
811
897
|
// method on `Map.prototype` and `Set.prototype`, so an own one or a subclass's answers instead:
|
|
812
898
|
// one that threw took this module out through the caller's own exception, and one that yielded
|
|
813
|
-
// different entries filled the copy with something other than what the collection holds.
|
|
814
|
-
|
|
815
|
-
|
|
899
|
+
// different entries filled the copy with something other than what the collection holds. Both are
|
|
900
|
+
// taken at load and invoked uncurried, so neither the method nor the `call` that reaches it is
|
|
901
|
+
// read off a prototype while a caller is in a position to have replaced it.
|
|
902
|
+
var walk = util.types.isSet(src) ? _setForEach : _mapForEach;
|
|
903
|
+
walk(src, function (value, key) {
|
|
816
904
|
var copiedValue = _deep(value, ErrorClass, code, label, cap, depth + 1, collect);
|
|
817
|
-
if (util.types.isSet(dst)) dst
|
|
818
|
-
else dst
|
|
905
|
+
if (util.types.isSet(dst)) _setAdd(dst, copiedValue);
|
|
906
|
+
else _mapSet(dst, _deep(key, ErrorClass, code, label, cap, depth + 1, collect), copiedValue);
|
|
819
907
|
});
|
|
820
908
|
_copyNamed(src, dst, ErrorClass, code, label, cap, depth, collect);
|
|
821
909
|
return dst;
|
|
@@ -832,8 +920,8 @@ function _copyEntries(src, dst, ErrorClass, code, label, cap, depth, collect) {
|
|
|
832
920
|
// The names `Date.prototype` supplies, read off the language rather than written out, so a method
|
|
833
921
|
// the language gains later is behavior here on the day it lands.
|
|
834
922
|
var _DATE_BEHAVIOR = (function () {
|
|
835
|
-
var t =
|
|
836
|
-
|
|
923
|
+
var t = _create(null);
|
|
924
|
+
_forEach(_ownKeys(Date.prototype), function (n) { t[n] = 1; });
|
|
837
925
|
return t;
|
|
838
926
|
})();
|
|
839
927
|
|
|
@@ -849,7 +937,7 @@ function _copyNamed(src, dst, ErrorClass, code, label, cap, depth, collect, beha
|
|
|
849
937
|
// like any other: the fault gets this boundary's typed code with the raw error as its cause,
|
|
850
938
|
// and never escapes as itself from inside a verb the caller called for something else.
|
|
851
939
|
try { value = src[keys[k]]; }
|
|
852
|
-
catch (e) { throw _raise(ErrorClass, code, label + ": reading " +
|
|
940
|
+
catch (e) { throw _raise(ErrorClass, code, label + ": reading " + _stringify(keys[k]) + " threw", e); }
|
|
853
941
|
// A name the destination's KIND already defines, holding a FUNCTION, is a shadow of that
|
|
854
942
|
// kind's own method: copying it down would make the copy answer with the caller's code where
|
|
855
943
|
// the original answered with the language's. The value decides, not the name -- a plain
|
|
@@ -860,7 +948,7 @@ function _copyNamed(src, dst, ErrorClass, code, label, cap, depth, collect, beha
|
|
|
860
948
|
// still carried. Dropping it changed what the caller passed: an unknown spec
|
|
861
949
|
// field whose value happened to be a function stopped reaching the verb's own key check, so a
|
|
862
950
|
// typo that used to be refused was silently accepted.
|
|
863
|
-
|
|
951
|
+
_defineProperty(dst, keys[k], {
|
|
864
952
|
value: typeof value === "function" ? value
|
|
865
953
|
: _deep(value, ErrorClass, code, label, cap, depth + 1, collect),
|
|
866
954
|
writable: true, enumerable: _wasEnumerable(src, keys[k]), configurable: true,
|
|
@@ -871,8 +959,8 @@ function _copyNamed(src, dst, ErrorClass, code, label, cap, depth, collect, beha
|
|
|
871
959
|
// Whether a name lookup on `v` would have found this property as an enumerable one, anywhere on
|
|
872
960
|
// the chain -- so the copy's own keys enumerate the way the original's did.
|
|
873
961
|
function _wasEnumerable(v, name) {
|
|
874
|
-
for (var o = v; o && o !==
|
|
875
|
-
var d =
|
|
962
|
+
for (var o = v; o && o !== _ObjectProto; o = _getPrototypeOf(o)) {
|
|
963
|
+
var d = _getOwnPropertyDescriptor(o, name);
|
|
876
964
|
if (d) return !!d.enumerable;
|
|
877
965
|
}
|
|
878
966
|
return false;
|
|
@@ -908,7 +996,7 @@ function fixArguments(ErrorClass, code, args) {
|
|
|
908
996
|
}
|
|
909
997
|
try {
|
|
910
998
|
for (var i = 0; i < args.length; i++) {
|
|
911
|
-
values
|
|
999
|
+
_append(values, snapshotDeep(args[i][0], ErrorClass, code, args[i][1], { collect: copies }));
|
|
912
1000
|
}
|
|
913
1001
|
} catch (e) {
|
|
914
1002
|
// The copying itself can fail partway (a detached leaf, a structure past the depth cap, a
|
|
@@ -936,10 +1024,12 @@ function fixArguments(ErrorClass, code, args) {
|
|
|
936
1024
|
// including a fault raised by the copy itself) and the per-verb entry-value vectors.
|
|
937
1025
|
function fixedCall(ErrorClass, code, args, body) {
|
|
938
1026
|
var handle = null;
|
|
939
|
-
|
|
1027
|
+
// Both halves through captures. `body.apply` and `.finally` are prototype reads, and between them
|
|
1028
|
+
// they decide whether the verb runs and whether the copies it was handed are ever cleared.
|
|
1029
|
+
return _promiseFinally(async.deferred(function () {
|
|
940
1030
|
handle = fixArguments(ErrorClass, code, args);
|
|
941
|
-
return body
|
|
942
|
-
})
|
|
1031
|
+
return _apply(body, null, handle.values);
|
|
1032
|
+
}), function () { if (handle) handle.release(); });
|
|
943
1033
|
}
|
|
944
1034
|
|
|
945
1035
|
module.exports = {
|