@blamejs/pki 0.5.10 → 0.5.11

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.
@@ -7,6 +7,183 @@
7
7
  // pki.cbor.decode, pki.ct.parseSctList, pki.webcrypto.*).
8
8
  //
9
9
  var async = require("./guard-async");
10
+ var identifier = require("./guard-identifier");
11
+ var time = require("./guard-time");
12
+ var util = require("util");
13
+
14
+ // isByteSource(x) -> boolean: is this one of the four forms the toolkit calls bytes?
15
+ //
16
+ // A Buffer, any typed-array view, a DataView, or a bare ArrayBuffer. Exported so a door deciding
17
+ // whether an argument is bytes asks the module that finally reads them, instead of restating the
18
+ // list. A restatement narrows without anyone noticing. An `x instanceof ArrayBuffer` at such a
19
+ // door turns away a real buffer from another realm, and the caller's container is then accepted
20
+ // at one door and refused at the next.
21
+ // @enforced-by behavioral -- a narrowed restatement of a list has no rename-proof code shape;
22
+ // the RED vector (a byte form accepted by one door and refused by the other) is the guard.
23
+ function isByteSource(x) {
24
+ return Buffer.isBuffer(x) || ArrayBuffer.isView(x) || _isArrayBuffer(x);
25
+ }
26
+
27
+ // Is this value a byte store, asked of the internal slot rather than the prototype?
28
+ //
29
+ // `v instanceof ArrayBuffer` answers what a value inherits from, which is a different question
30
+ // from what it holds. `Object.create(ArrayBuffer.prototype)` inherits everything and holds no
31
+ // bytes, so it passes and the read that follows throws a raw TypeError out of a boundary whose
32
+ // contract is a typed error. The same test also misses a real buffer from another realm, whose
33
+ // prototype is that realm's. `util.types` reads the slot, so both answers come out right.
34
+ function _isArrayBuffer(v) {
35
+ return util.types.isArrayBuffer(v);
36
+ }
37
+
38
+ // Where a view's bytes actually are, asked of the language rather than of the view.
39
+ //
40
+ // `v.buffer`, `v.byteOffset` and `v.byteLength` are accessors on the shared typed-array prototype,
41
+ // so `class Opts extends Uint8Array { get buffer() { return elsewhere; } }` answers all three
42
+ // questions itself. Two things followed from reading them off the value. A getter that throws left
43
+ // this module through the caller's own exception, from a boundary whose contract is a typed error.
44
+ // And a getter that lied substituted the memory: an array holding AA AA AA AA whose `buffer`
45
+ // returned another store had `view` and `snapshot` hand back that other store's bytes, so the
46
+ // bytes a verb went on to hash, sign or parse were not the bytes in the array it was given.
47
+ //
48
+ // The getters are taken off the prototypes the language installs them on and called against the
49
+ // view, which reaches the internal slot whatever the value's own class says. A subclass override
50
+ // is then what it is -- a property of the caller's object -- and answers no question asked here.
51
+ var _TYPED_ARRAY_PROTO = Object.getPrototypeOf(Uint8Array.prototype);
52
+
53
+ function _intrinsicGetter(proto, name, who) {
54
+ var d = Object.getOwnPropertyDescriptor(proto, name);
55
+ if (!d || typeof d.get !== "function") {
56
+ throw new TypeError("guard.bytes: this runtime has no intrinsic " + who + "." + name +
57
+ " accessor, so a view's backing store cannot be read without invoking the value's own");
58
+ }
59
+ return d.get;
60
+ }
61
+
62
+ var _taBuffer = _intrinsicGetter(_TYPED_ARRAY_PROTO, "buffer", "%TypedArray%.prototype");
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");
68
+
69
+ // A DataView carries its own accessors rather than the typed-array ones, so the pair is chosen by
70
+ // the value's slot. Either getter refuses a receiver with no slot behind it, which is the same
71
+ // refusal a detached store gets, and every caller here already types that.
72
+ function _storeOf(v) { return util.types.isDataView(v) ? _dvBuffer.call(v) : _taBuffer.call(v); }
73
+ function _offsetOf(v) { return util.types.isDataView(v) ? _dvByteOffset.call(v) : _taByteOffset.call(v); }
74
+ function _lengthOf(v) { return util.types.isDataView(v) ? _dvByteLength.call(v) : _taByteLength.call(v); }
75
+
76
+ // The Buffer over a view's own bytes. The single place this module turns a view into a Buffer, so
77
+ // the intrinsic reads above cannot be skipped at one of the two call sites and kept at the other.
78
+ function _reView(v) {
79
+ return Buffer.from(_storeOf(v), _offsetOf(v), _lengthOf(v));
80
+ }
81
+
82
+ // Which concrete typed-array kind a value is, decided by its slot and answered with this realm's
83
+ // own constructor. `v.constructor` is an ordinary inherited property, so a subclass answers it and
84
+ // a copy built through it is whatever the caller said.
85
+ //
86
+ // The pairs are DERIVED from what this runtime offers, never written out. A hand-written list is
87
+ // complete on the day it is written and silently short afterwards: `Float16Array` landed on Node 24
88
+ // and a list drafted before it refused the kind outright, since the fallback that used to catch it
89
+ // was `v.constructor` -- which is the read this table exists to replace. Deriving covers the next
90
+ // kind on the day the runtime exposes its predicate, and covers nothing the runtime does not.
91
+ //
92
+ // `util.types` names each concrete kind's predicate `is<Constructor>`, so the global of that name
93
+ // is the constructor for it. `BYTES_PER_ELEMENT` on the CONSTRUCTOR is what separates a concrete
94
+ // kind from the umbrella predicates: `isTypedArray` has no `TypedArray` global to pair with, and
95
+ // `isArrayBufferView` would pair with none either.
96
+ // The predicate FUNCTION is held, never its name. A name is looked up afresh on every call, and
97
+ // `util.types` is an ordinary object: replacing a predicate on it after this module loads would
98
+ // hand the kind decision, and with it the constructor the copy is built from, to whoever did.
99
+ // Reading it once at load leaves nothing to replace.
100
+ var _CONCRETE_KINDS = Object.keys(util.types)
101
+ .filter(function (name) { return /^is[A-Za-z0-9]+Array$/.test(name); })
102
+ .map(function (name) { return [util.types[name], globalThis[name.slice(2)]]; })
103
+ .filter(function (row) {
104
+ return typeof row[0] === "function" && typeof row[1] === "function" &&
105
+ typeof row[1].BYTES_PER_ELEMENT === "number" && row[1].BYTES_PER_ELEMENT > 0;
106
+ });
107
+
108
+ function _concreteKindOf(v) {
109
+ for (var i = 0; i < _CONCRETE_KINDS.length; i++) {
110
+ if (_CONCRETE_KINDS[i][0](v)) return _CONCRETE_KINDS[i][1];
111
+ }
112
+ return null;
113
+ }
114
+
115
+ // A name for a refused value, for the message alone. Taken from what the value IS, since
116
+ // `v.constructor.name` is two ordinary property reads a caller answers: a getter under either one
117
+ // took the refusal below out through the caller's exception, in place of the typed error whose
118
+ // whole purpose here is to say why the value was refused.
119
+ var _NAMED_KINDS = [
120
+ ["isNativeError", "Error"], ["isRegExp", "RegExp"], ["isPromise", "Promise"],
121
+ ["isWeakMap", "WeakMap"], ["isWeakSet", "WeakSet"], ["isMap", "Map"], ["isSet", "Set"],
122
+ ["isDate", "Date"], ["isProxy", "Proxy"]
123
+ ].filter(function (row) { return typeof util.types[row[0]] === "function"; });
124
+
125
+ function _kindName(v) {
126
+ for (var i = 0; i < _NAMED_KINDS.length; i++) {
127
+ if (util.types[_NAMED_KINDS[i][0]](v)) return _NAMED_KINDS[i][1];
128
+ }
129
+ return typeof v === "function" ? "function" : "value";
130
+ }
131
+
132
+ function _article(name) { return /^[AEIOU]/i.test(name) ? "an" : "a"; }
133
+
134
+ // outputView(input, ErrorClass, code, label) -> a Buffer aliasing a caller's view, for WRITING.
135
+ //
136
+ // The same slot-based re-view as `view`, without the shared-memory refusal. That refusal answers a
137
+ // question about INPUT: bytes another thread can rewrite after they have been checked cannot be
138
+ // checked at all. A write target is the other direction. The caller is asking to be handed random
139
+ // bytes in memory they chose, and choosing shared memory is a decision they are entitled to make;
140
+ // `crypto.getRandomValues` on a `SharedArrayBuffer`-backed view is ordinary, and both the platform
141
+ // and this runtime fill it. Refusing it here turned a supported W3C call into an error.
142
+ //
143
+ // The bytes still come back through the intrinsic accessors, so a subclass cannot redirect the
144
+ // write to memory the caller does not own, and a detached store is still refused.
145
+ // @enforced-by behavioral -- an input door reaching for this instead of `view` has no rename-proof
146
+ // code shape; the RED vectors (a shared view filled here, and a detached one refused) are the guard.
147
+ function outputView(input, ErrorClass, code, label) {
148
+ if (!util.types.isUint8Array(input) && !ArrayBuffer.isView(input)) {
149
+ throw _raise(ErrorClass, code, label + ": expected a Buffer / TypedArray to write into");
150
+ }
151
+ try {
152
+ return _reView(input);
153
+ } catch (e) {
154
+ throw _raise(ErrorClass, code, label + ": output is not a usable byte view (detached backing buffer?)", e);
155
+ }
156
+ }
157
+
158
+ // lengthOf(view) -> how many bytes a view holds, read the same way.
159
+ //
160
+ // For the boundaries that size a value rather than read it: a response-body cap, an emptiness
161
+ // test. `length` is an accessor on the shared typed-array prototype AND shadowable by an own
162
+ // property on any instance, so `Object.defineProperty(buf, "length", { get: () => 0 })` answers
163
+ // for a Buffer holding megabytes. A cap measured that way is a cap its caller sets.
164
+ // @enforced-by behavioral -- `x.length` is the ordinary spelling wherever the value is this
165
+ // toolkit's own, so the misuse has no rename-proof code shape; the RED vector (a planted `length`
166
+ // getting a body past a documented size cap) is the guard.
167
+ function lengthOf(view) {
168
+ return _lengthOf(view);
169
+ }
170
+
171
+ // Shared memory is refused rather than accepted as bytes.
172
+ //
173
+ // This module exists to hand a verb bytes its caller can no longer change once they have been
174
+ // checked, and a SharedArrayBuffer is writable from another thread for as long as it lives, so
175
+ // no copy taken here can hold that promise for the value the caller passed. Copying it into a
176
+ // private ArrayBuffer would keep the bytes and change the kind, which is the same-kind contract
177
+ // broken quietly; refusing says so instead. The message names the shape, since "not a byte
178
+ // container" about a container that plainly holds bytes reads as the toolkit being wrong.
179
+ function _refuseShared(v, ErrorClass, code, label) {
180
+ if (util.types.isSharedArrayBuffer(v) ||
181
+ (ArrayBuffer.isView(v) && util.types.isSharedArrayBuffer(_storeOf(v)))) {
182
+ throw _raise(ErrorClass, code, label + ": shared memory cannot be used here, because another " +
183
+ "thread can rewrite it after it has been checked; pass a Buffer or a Uint8Array over " +
184
+ "memory this process owns");
185
+ }
186
+ }
10
187
 
11
188
  // guard-bytes -- fail-closed coercion of an untrusted byte-source input to a
12
189
  // Buffer view. One of the enforced choke points of the guard family: a
@@ -49,12 +226,22 @@ function _raise(E, code, message, cause) {
49
226
  // Accepts a Buffer / Uint8Array -- the DER / CBOR / CT / Merkle input contract.
50
227
  // ErrorClass MUST be a withCause PkiError subclass (the raw detach failure is
51
228
  // threaded as the cause).
229
+ // The kind is read from the slot. A prototype test turns away a real Uint8Array built in another
230
+ // realm, whose prototype is that realm's, and tells the caller their bytes are not bytes. It
231
+ // admits the mirror shape, `Object.create(Uint8Array.prototype)`, which holds none; that one comes
232
+ // back as this guard's own code either way, since the read below is wrapped, so reading the slot
233
+ // only moves the refusal to the door from the failing read.
52
234
  // @enforced-by guard-shape-reinlined
53
- // @guard-shape Buffer\.from\(\s*([A-Za-z_$][\w$]*)\.buffer\s*,\s*\1\.byteOffset
235
+ // The shape covers the re-view however the view is constructed. It was anchored on `Buffer.from(`
236
+ // alone, and `Buffer.from(new Uint8Array(v.buffer, v.byteOffset, v.byteLength))` slipped past it
237
+ // into two format modules, where a caller's subclass could answer all three accessors and hand the
238
+ // copy a different store than the array held.
239
+ // @guard-shape (?:Buffer\.from|new\s+[A-Za-z_$][\w$]*Array)\(\s*(?:new\s+[A-Za-z_$][\w$]*Array\(\s*)?([A-Za-z_$][\w$]*)\.buffer\s*,\s*\1\.byteOffset
54
240
  function view(input, ErrorClass, code, label) {
55
- if (Buffer.isBuffer(input) || input instanceof Uint8Array) {
241
+ _refuseShared(input, ErrorClass, code, label);
242
+ if (util.types.isUint8Array(input)) {
56
243
  try {
57
- return Buffer.from(input.buffer, input.byteOffset, input.byteLength);
244
+ return _reView(input);
58
245
  } catch (e) {
59
246
  throw _raise(ErrorClass, code, label + ": input is not a usable byte view (detached backing buffer?)", e);
60
247
  }
@@ -72,10 +259,11 @@ function view(input, ErrorClass, code, label) {
72
259
  // copies. Throws on a detached backing store.
73
260
  // @enforced-by guard-shape-reinlined (the re-view shape is declared on view above)
74
261
  function source(input, ErrorClass, code, label) {
75
- var isAb = input instanceof ArrayBuffer;
262
+ _refuseShared(input, ErrorClass, code, label);
263
+ var isAb = _isArrayBuffer(input);
76
264
  if (isAb || ArrayBuffer.isView(input)) {
77
265
  try {
78
- return isAb ? Buffer.from(input) : Buffer.from(input.buffer, input.byteOffset, input.byteLength);
266
+ return isAb ? Buffer.from(input) : _reView(input);
79
267
  } catch (e) {
80
268
  throw _raise(ErrorClass, code, label + ": input is not a usable byte source (detached backing buffer?)", e);
81
269
  }
@@ -168,13 +356,36 @@ function snapshotDeep(value, ErrorClass, code, label, opts) {
168
356
  // platform's, or another implementation's) carries exactly these (its key material lives in an
169
357
  // internal slot or a non-enumerable own property). A caller's options bag that happens to satisfy
170
358
  // the structural predicate carries its own fields alongside, and those are what give it away.
171
- var _CRYPTO_KEY_SURFACE = { type: 1, extractable: 1, algorithm: 1, usages: 1 };
359
+ // `Symbol.toStringTag` is the language's own name for what a value is, and a key handle carries it
360
+ // as a non-enumerable own property. It answers no named option, so it is surface rather than data,
361
+ // and naming it here is what lets the pass-through test below judge every key by the same rule it
362
+ // judges every other property by.
363
+ // A surface is a table of names, so it is built WITHOUT a prototype. An ordinary object literal
364
+ // answers `surface["toString"]` with a function it inherited, and every table is then read as
365
+ // though it listed `toString`, `constructor`, `valueOf`, `hasOwnProperty` and `__proto__` -- names
366
+ // a caller can write, on an object that is passed on by reference. Membership has to be a fact
367
+ // about the table rather than about what any object answers to a lookup.
368
+ //
369
+ // `Symbol.toStringTag` is on every surface: it is the language's own name for what a value is, a
370
+ // key handle carries it as a non-enumerable own property, and it answers no named option.
371
+ function _surface(names) {
372
+ var t = Object.create(null);
373
+ names.forEach(function (n) { t[n] = 1; });
374
+ t[Symbol.toStringTag] = 1;
375
+ return t;
376
+ }
377
+ // `_handle` is this engine's own state on its own key object, the counterpart of the
378
+ // `asymmetricKeyType` and `asymmetricKeyDetails` that Node puts on a KeyObject. What it holds
379
+ // varies by algorithm -- a KeyObject for a signing key, the raw bytes for an HMAC one -- and it is
380
+ // reachable only on a value already recognized as a key, whose material the caller holds anyway.
381
+ var _CRYPTO_KEY_SURFACE = _surface(["type", "extractable", "algorithm", "usages",
382
+ "asymmetricKeyType", "asymmetricKeyDetails", "_handle"]);
172
383
  // The same, for the other kinds whose state cannot be copied: what belongs to the kind, so that
173
384
  // anything else on the object is recognizably the caller's own and gets the refusal below.
174
- var _ERROR_SURFACE = { message: 1, stack: 1, name: 1, cause: 1 };
175
- var _REGEXP_SURFACE = { lastIndex: 1, source: 1, flags: 1, global: 1, ignoreCase: 1, multiline: 1,
176
- sticky: 1, unicode: 1, unicodeSets: 1, hasIndices: 1, dotAll: 1 };
177
- var _THENABLE_SURFACE = { then: 1, catch: 1, finally: 1 };
385
+ var _ERROR_SURFACE = _surface(["message", "stack", "name", "cause"]);
386
+ var _REGEXP_SURFACE = _surface(["lastIndex", "source", "flags", "global", "ignoreCase", "multiline",
387
+ "sticky", "unicode", "unicodeSets", "hasIndices", "dotAll"]);
388
+ var _THENABLE_SURFACE = _surface(["then", "catch", "finally"]);
178
389
 
179
390
  // Is this an object whose state this module cannot read, and therefore cannot copy?
180
391
  //
@@ -190,10 +401,27 @@ var _THENABLE_SURFACE = { then: 1, catch: 1, finally: 1 };
190
401
  function _opaqueSurface(v, ErrorClass, code, label) {
191
402
  var proto = Object.getPrototypeOf(v);
192
403
  if (proto === Object.prototype || proto === null) return null;
193
- if (v instanceof WeakMap || v instanceof WeakSet) return {}; // deliberately not enumerable
404
+ if (util.types.isWeakMap(v) || util.types.isWeakSet(v)) return {}; // deliberately not enumerable
194
405
  if (v instanceof Error) return _ERROR_SURFACE;
195
- if (v instanceof RegExp) return _REGEXP_SURFACE;
196
- if (require("./webcrypto").isCryptoKeyLike(v)) return _CRYPTO_KEY_SURFACE; // allow:inline-require -- circular load: webcrypto requires this module
406
+ if (util.types.isRegExp(v)) return _REGEXP_SURFACE;
407
+ // A node:crypto KeyObject, read off its internal slot. `pki.hpke` documents one as a key input
408
+ // and `pki.ct` names it too, and a copy of a key handle is not a key: its material lives behind
409
+ // the slot, so what the copy holds is the shape of a key and none of the key. Recognized here so
410
+ // it reaches the verb as itself, which is the same treatment a WebCrypto CryptoKey gets.
411
+ // `util.types.isKeyObject` reads the slot, so it answers for a handle from any realm and says no
412
+ // to `Object.create(KeyObject.prototype)`.
413
+ if (util.types.isKeyObject(v)) return _CRYPTO_KEY_SURFACE;
414
+ // 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: `Object.create(KeyObject.prototype)`
416
+ // raises a raw TypeError from inside `type`. Typed here, like the `then` read below, so a
417
+ // question this module asked on its own behalf cannot escape as somebody else's error.
418
+ var keyLike;
419
+ try {
420
+ keyLike = require("./webcrypto").isCryptoKeyLike(v); // allow:inline-require -- circular load: webcrypto requires this module
421
+ } catch (e) {
422
+ throw _raise(ErrorClass, code, label + ": reading the key surface threw", e);
423
+ }
424
+ if (keyLike) return _CRYPTO_KEY_SURFACE;
197
425
  // Asking whether it is a thenable reads a property, and a caller's accessor can throw: the
198
426
  // same fault the copy itself types, so it is typed here too and never escapes raw from a
199
427
  // question this module asked on its own behalf.
@@ -209,42 +437,100 @@ function _opaqueSurface(v, ErrorClass, code, label) {
209
437
  // passing it through would leave that data the caller's to change after the checks have read it.
210
438
  // Every reachable name is examined, not only the own ones; a verb reads a field by name and does
211
439
  // not care where on the chain it sits.
212
- function _opaqueIsSafeToPass(v, surface) {
213
- var keys = _reachableKeys(v);
214
- for (var i = 0; i < keys.length; i++) {
215
- if (surface[keys[i]]) continue;
216
- // Only what the caller put there. An implementation's own internals are non-enumerable by
217
- // construction (this engine's key handle, a platform object's slots), and so are the methods
218
- // on any prototype, built-in or class-declared. What a caller adds, they add by assignment,
219
- // which is enumerable; that is the case the refusal is for, whatever the value's type. A
220
- // callable value is no exemption: an option is read for what it is, and `signedAttributes`
221
- // holding a function is neither false nor a method of anything.
222
- if (!_wasEnumerable(v, keys[i])) continue;
223
- return false;
440
+ // Can this name answer differently after the checks have read it? That is the whole question for a
441
+ // value handed on BY REFERENCE, and it is a fact about the property rather than a guess about who
442
+ // wrote it. An accessor answers afresh every read. A writable or configurable data property can be
443
+ // assigned or redefined. A data property that is neither is settled: whatever the checks saw is
444
+ // what the verb gets.
445
+ //
446
+ // Judged where the property is found, walking up as a read does. A `getPrototypeOf` trap can hand
447
+ // back a fresh object forever, so the walk stops at one it has already visited, the same bound the
448
+ // name walk uses.
449
+ //
450
+ // One limit, stated rather than papered over: a caller can still swap the whole prototype after the
451
+ // call and change what an inherited name answers. That is true of every value passed by reference,
452
+ // and a platform object's prototype is the platform's.
453
+ function _canChangeAfterTheCheck(v, name) {
454
+ var visited = new Set();
455
+ for (var o = v; o && !visited.has(o); o = Object.getPrototypeOf(o)) {
456
+ visited.add(o);
457
+ var d = Object.getOwnPropertyDescriptor(o, name);
458
+ if (!d) continue;
459
+ if (d.get || d.set || d.writable || d.configurable) return true;
460
+ // Settled where it sits. Reached through the chain it is settled only while nothing can be put
461
+ // in front of it: an extensible receiver takes an own property of the same name at any time,
462
+ // and the read then answers with that one. Own on the value itself, or a value nothing can be
463
+ // added to, is the case where what was read is what stays.
464
+ return o !== v && Object.isExtensible(v);
224
465
  }
225
- return true;
466
+ return false;
226
467
  }
227
468
 
228
- // Every property name a `v.field` lookup could resolve: own and inherited, enumerable or not.
229
- //
230
- // The enumerable-only version of this was wrong three times running, each time in the same
231
- // direction (own keys missed an inherited field, enumerable keys missed a non-enumerable one),
232
- // and each miss left the caller's object reachable behind a copy that looked complete. A verb reads
233
- // an option by name, so the set that has to be fixed is the set a name lookup can reach, and
234
- // nothing narrower. Object.prototype's own members are excluded: they are the language's, not the
235
- // caller's, and copying them onto every spec would shadow the prototype for no gain.
236
- function _reachableKeys(v) {
237
- var names = [];
238
- var seen = Object.create(null);
239
- for (var o = v; o && o !== Object.prototype; o = Object.getPrototypeOf(o)) {
240
- var own = Object.getOwnPropertyNames(o);
241
- for (var i = 0; i < own.length; i++) {
242
- if (own[i] === "constructor" || seen[own[i]]) continue;
243
- seen[own[i]] = true;
244
- names.push(own[i]);
245
- }
469
+ // Is what a settled binding POINTS AT settled too? A property that cannot be reassigned still
470
+ // answers with whatever its value has become: a frozen `signingTime` holding a Date is a binding
471
+ // nobody can move and an instant anybody can move, and `pki.cms.sign` signed 2030 while the
472
+ // operator read 2040 off the same object afterwards. A primitive cannot change. Another handle is
473
+ // settled exactly when the same question about it comes back clean, which is this function one
474
+ // level down. Everything else is state the caller keeps, and this module would have copied it.
475
+ //
476
+ // Bounded, because the chain is the caller's to make as long as they like.
477
+ var _SETTLED_DEPTH = 4;
478
+ function _settledValueIsFixed(value, ErrorClass, code, label, depth) {
479
+ if (value === null || (typeof value !== "object" && typeof value !== "function")) return true;
480
+ if (depth >= _SETTLED_DEPTH) return false;
481
+ // A Proxy answers every question through a handler, so it is never settled and asking is the
482
+ // harm: reading its prototype runs a trap, and a trap that throws would leave this module over
483
+ // a question it asked on its own behalf. `util.types.isProxy` reads the slot and runs nothing.
484
+ if (util.types.isProxy(value)) return false;
485
+ var surface = _opaqueSurface(value, ErrorClass, code, label);
486
+ if (!surface) return false;
487
+ return _opaqueFieldOutsideSurface(value, surface, ErrorClass, code, label, depth + 1) === null;
488
+ }
489
+
490
+ function _opaqueFieldOutsideSurface(v, surface, ErrorClass, code, label, depth) {
491
+ var keys = _namesToCopy(v, ErrorClass, code, label);
492
+ for (var i = 0; i < keys.length; i++) {
493
+ // The kind's own surface, and nothing else. Enumerability says how a property was written,
494
+ // never who wrote it: `Object.defineProperty` is available to a caller as much as to a
495
+ // platform, so skipping the non-enumerable ones let a field ride in on a handle that is
496
+ // passed through BY REFERENCE and stays the caller's to change afterwards. A foreign RegExp
497
+ // carrying a non-enumerable `detached` reached pki.cms.sign that way, and flipping it after
498
+ // the call moved the content out of the message the call had already been asked to sign.
499
+ //
500
+ // The surfaces are what makes this affordable rather than a blanket refusal: each names what
501
+ // the real platform object of that kind carries, so the ordinary value passes and anything
502
+ // beyond it is the caller's. A callable value is no exemption either -- an option is read for
503
+ // what it is, and `signedAttributes` holding a function is neither false nor a method of
504
+ // anything.
505
+ if (surface[keys[i]]) continue;
506
+ // A symbol is not an option. Every verb reads its options by name, so nothing under a symbol
507
+ // key reaches one, and refusing a handle for carrying one buys nothing. What it costs is real:
508
+ // a CryptoKey from another WebCrypto implementation is a documented input, and an
509
+ // implementation that keeps its internals under a symbol -- written the ordinary way, by
510
+ // assignment -- would have its keys refused at every verb.
511
+ //
512
+ // The options door is unaffected and still refuses one. `assertKnownKeys` walks the bag a
513
+ // caller passed as options and reports a symbol there, because a caller who wrote one meant it
514
+ // as an option and no verb will ever read it. That is a different question from whether a key
515
+ // handle may be handed on.
516
+ if (typeof keys[i] === "symbol") continue;
517
+ // A name outside the surface is refused only if it can still move. Enumerability was the old
518
+ // test and it decided the wrong question: it describes how a property was written, and
519
+ // `Object.defineProperty` belongs to a caller as much as to a platform, so a hidden `detached`
520
+ // on a foreign RegExp rode into pki.cms.sign and moved the content out of the signed message
521
+ // after the call. Position was no better -- a key is an argument in its own right at
522
+ // `pki.csr.sign(spec, key)`, so refusing everything at the argument refused the key.
523
+ //
524
+ // Settled data is what an implementation's internals are: this engine writes `_handle` on a key
525
+ // with neither `writable` nor `configurable`, so it cannot be reassigned or redefined, and
526
+ // nothing the checks read about that key can change afterwards. A field a caller can still
527
+ // assign to, redefine, or answer with a getter is the case this refusal is for -- whatever
528
+ // kind of object it rides on, and wherever in the arguments that object sits.
529
+ if (!_canChangeAfterTheCheck(v, keys[i]) &&
530
+ _settledValueIsFixed(v[keys[i]], ErrorClass, code, label, depth || 0)) continue;
531
+ return keys[i];
246
532
  }
247
- return names;
533
+ return null;
248
534
  }
249
535
 
250
536
  // A private copy of a byte value of the same kind the caller passed. The kind is
@@ -260,15 +546,107 @@ function _copyBytesSameKind(v, ErrorClass, code, label, collect) {
260
546
  // What `release` clears: a Buffer over the whole private store, whatever kind is handed back.
261
547
  if (collect) collect.push(Buffer.from(owned, 0, src.length));
262
548
  if (Buffer.isBuffer(v)) return Buffer.from(owned, 0, src.length);
263
- if (v instanceof ArrayBuffer) return owned;
264
- if (v instanceof DataView) return new DataView(owned);
265
- return new v.constructor(owned, 0, src.length / v.BYTES_PER_ELEMENT);
549
+ if (_isArrayBuffer(v)) return owned;
550
+ if (util.types.isDataView(v)) return new DataView(owned);
551
+ // The kind comes from the value's slot, never from `v.constructor` or `v.BYTES_PER_ELEMENT`.
552
+ // Both are ordinary properties a subclass answers: a `constructor` that threw took this module
553
+ // out through the caller's own exception, and a `BYTES_PER_ELEMENT` that lied built the copy
554
+ // with a different element count and a different kind than the value it was copying.
555
+ var Ctor = _concreteKindOf(v);
556
+ if (!Ctor) {
557
+ throw _raise(ErrorClass, code, label + ": a " +
558
+ (util.types.isTypedArray(v) ? "typed array of a kind this runtime added" : "byte view") +
559
+ " cannot be copied while keeping its kind; pass a Buffer or a Uint8Array");
560
+ }
561
+ return new Ctor(owned, 0, src.length / Ctor.BYTES_PER_ELEMENT);
562
+ }
563
+
564
+ // Is this value's prototype chain cyclic? A Proxy whose `getPrototypeOf` trap returns the proxy
565
+ // itself makes one, and the engine permits it while the target stays extensible.
566
+ //
567
+ // It has to be asked before anything else this module does with the value. Almost every question
568
+ // about a kind is an `instanceof`, and `instanceof` walks the prototype chain. On a cyclic chain
569
+ // it exhausts the stack, and a raw RangeError escapes from a guard whose whole contract is a
570
+ // typed error.
571
+ //
572
+ // Naming the shape is the fail-closed answer. An options bag cannot need a prototype chain that
573
+ // loops, and copying one has no meaning to fall back to.
574
+ function _protoChainIsCyclic(v) {
575
+ var visited = new Set();
576
+ for (var o = v; o; o = Object.getPrototypeOf(o)) {
577
+ if (visited.has(o)) return true;
578
+ visited.add(o);
579
+ }
580
+ return false;
266
581
  }
267
582
 
583
+ // Is a Proxy anywhere on this chain? The copy reads names from the whole chain, so one sitting
584
+ // above a plain object decides what the copy takes while the original answers reads from its
585
+ // `get` trap. Testing only the value handed in leaves that one line of indirection open.
586
+ function _protoChainHasProxy(v) {
587
+ var visited = new Set();
588
+ for (var o = v; o && !visited.has(o); o = Object.getPrototypeOf(o)) {
589
+ visited.add(o);
590
+ if (util.types.isProxy(o)) return true;
591
+ }
592
+ return false;
593
+ }
594
+
595
+ // Give the copy of a collection the same prototype the original carries.
596
+ //
597
+ // The object branch does this with `Object.create(Object.getPrototypeOf(v))`, so an instance of a
598
+ // caller's class keeps its methods. A collection branch builds a plain `[]`, `Map` or `Set`, and
599
+ // a subclass of one holds its additions on a prototype above that. Copying the chain down onto a
600
+ // plain array turns `class Opts extends Array { describe() {} }` into an array with `describe` as
601
+ // an own function that nothing above supplies, which the check reads as a typed option and
602
+ // refuses, though the same bag passed that check before the copy.
603
+ //
604
+ // A subclass of a built-in is the caller's own class, so this is the same trade the object branch
605
+ // makes. The prototype is theirs and stays theirs, while every readable name is copied down so no
606
+ // value is re-read through it after the checks have run.
607
+ // The copy's class is this module's, never the caller's.
608
+ //
609
+ // A copy used to be given the original's prototype back, so that the walk which reports option
610
+ // names read the copy the way it read the original. It does that anyway: a method the caller's
611
+ // class defines is not a name that walk reports, so it is never copied across as one, and the two
612
+ // sides agree without the prototype. Measured, not assumed -- the vectors compare both.
613
+ //
614
+ // What restoring it cost was the whole point of copying. The prototype is part of the argument, so
615
+ // the copy went on dispatching into the caller's code: `list.map(...)` inside a signing verb
616
+ // reached an override on an Array subclass, `getUTCFullYear()` reached one on a Date subclass, and
617
+ // an override that threw surfaced the caller's own exception from inside a verb whose contract is
618
+ // a typed error. Worse, a prototype can be rewritten after the call has begun, so a copy taken to
619
+ // stop the argument changing under the verb changed with it.
620
+ function _plainCopy(copy) { return copy; }
621
+
268
622
  function _deep(v, ErrorClass, code, label, cap, depth, collect) {
269
623
  if (depth > cap) throw _raise(ErrorClass, code, label + " is nested too deeply to copy");
270
624
  if (v == null || typeof v !== "object") return v;
271
- if (Buffer.isBuffer(v) || ArrayBuffer.isView(v) || v instanceof ArrayBuffer) {
625
+ _refuseShared(v, ErrorClass, code, label);
626
+ // The Proxy test comes FIRST, ahead of the cycle walk and every `instanceof` below, because
627
+ // both of those read the prototype chain and a `getPrototypeOf` trap runs the caller's code.
628
+ // A trap that throws then escapes as its own raw Error from a guard whose whole contract is a
629
+ // typed one. This test reaches `Object.getPrototypeOf` only on links it has already cleared,
630
+ // so no trap runs before the refusal that makes running it unnecessary.
631
+ //
632
+ // A Proxy answers `ownKeys` and `get` from two independent traps, so the copy takes the names
633
+ // one trap reports while the original answers reads from the other. One reporting no keys and
634
+ // returning "pw" for `password` copies to an object holding nothing, and the field the caller
635
+ // supplied is gone with no fault raised. Copying it is therefore not copying it, which is the
636
+ // case this refusal is for: an argument is copied or refused, never half-taken.
637
+ if (_protoChainHasProxy(v)) {
638
+ throw _raise(ErrorClass, code, label + ": a Proxy cannot be copied faithfully, because the " +
639
+ "keys it reports need not be the ones it answers; pass a plain object");
640
+ }
641
+ // A second line under the Proxy rule, and unreachable while that one holds: `setPrototypeOf`
642
+ // refuses to build a cycle out of ordinary objects, so a Proxy is the only way to have one and
643
+ // the refusal above already covers every such value. It stays because the cost is one walk and
644
+ // the failure it prevents is an unbounded loop rather than a wrong answer.
645
+ if (_protoChainIsCyclic(v)) {
646
+ throw _raise(ErrorClass, code, label + ": its prototype chain is a cycle, so it cannot be " +
647
+ "read or copied; pass a plain object");
648
+ }
649
+ if (Buffer.isBuffer(v) || ArrayBuffer.isView(v) || _isArrayBuffer(v)) {
272
650
  var bytesCopy = _copyBytesSameKind(v, ErrorClass, code, label, collect);
273
651
  // A byte value can carry named properties too, and a verb reads an option by name whatever the
274
652
  // argument's type: `opts = new Uint8Array(0); opts.pem = true` is an options object as far as
@@ -284,16 +662,66 @@ function _deep(v, ErrorClass, code, label, cap, depth, collect) {
284
662
  // added a field no door re-derives, so `AsProduced` is what is asked, not `isRecorded`.
285
663
  // Required inline because guard-parsed requires this module; at call time it is fully loaded.
286
664
  if (require("./guard-parsed").isRecordedAsProduced(v)) return v; // allow:inline-require -- circular load: guard-parsed requires this module
287
- if (v instanceof Date) return new Date(v.getTime());
665
+ if (util.types.isDate(v)) {
666
+ // A Date can carry named properties too, and a verb reads an option by name whatever the
667
+ // argument's type. Returning the instant alone dropped anything the caller had added, so the
668
+ // copy held nothing while the original still answered, and the check read the copy.
669
+ //
670
+ // The instant comes through the time guard's intrinsic read. `getTime` is an ordinary method
671
+ // a subclass answers, so reading it off the value put a different instant in the copy than the
672
+ // original holds, and the value validated and the value used were two different reads.
673
+ //
674
+ // What the copy carries is the caller's DATA. A name the language already supplies on a Date
675
+ // is that Date's behavior, and copying an own one down put a caller's function on an object
676
+ // whose whole purpose is to answer as a plain Date holding that instant: an own
677
+ // `getUTCFullYear` that throws rode onto the copy and threw out of pki.cms.sign when the
678
+ // signing time was encoded. Normalizing the prototype does not reach an own shadow, so the
679
+ // shadow is left behind here. The excluded set is read off `Date.prototype` rather than
680
+ // written out, so it cannot fall behind the language.
681
+ var dateCopy = new Date(time.instantOf(v));
682
+ _copyNamed(v, dateCopy, ErrorClass, code, label, cap, depth, collect, _DATE_BEHAVIOR);
683
+ return _plainCopy(dateCopy);
684
+ }
288
685
  if (Array.isArray(v)) {
289
686
  var arr = [];
290
- for (var i = 0; i < v.length; i++) arr.push(_deep(v[i], ErrorClass, code, label, cap, depth + 1, collect));
687
+ // The indices a read on the array resolves, rather than a count from zero to `length`. An
688
+ // array is sparse whenever a caller sets a high index or assigns `length`, and
689
+ // `[].length = 4e9` is one statement: walking to `length` then does four billion iterations
690
+ // for an array holding nothing, inside a guard whose job includes keeping a caller's argument
691
+ // from costing unbounded work. Copying the indices that resolve costs what the array actually
692
+ // holds. `length` is carried across afterwards so trailing holes survive and the copy measures
693
+ // the same.
694
+ //
695
+ // Asked of guard-identifier, which owns the same question for names. Its own keys are not the
696
+ // answer: an array consults its prototype for a hole, so a length-one signer list holding its
697
+ // only signer on its prototype reports no own index while every consumer reads one element.
698
+ // Copying the own keys alone handed the verb an empty list.
699
+ var indexE = function (c, m) { return _raise(ErrorClass, c, m); };
700
+ var indices = identifier.readableIndices(v, indexE, code, label);
701
+ // An accessor is refused among the elements for the reason it is refused among the names:
702
+ // reading it once and writing what it returned as plain data leaves the later check nothing
703
+ // to find, since it sees a value and cannot tell an accessor was ever there. The refusal
704
+ // covered names only, so the same trick under an index passed -- and a list is exactly where
705
+ // it pays, an element answering as a trusted signer to the check and as another afterwards.
706
+ // The argument itself, not everything under it, matching the rule for names.
707
+ if (depth === 0) identifier.refuseAccessorFields(v, indices, indexE, code, label);
708
+ indices.forEach(function (k) {
709
+ // Reading an element can run a caller's accessor, the same as reading a named field: an
710
+ // index can carry a getter too, and one that threw escaped as itself from a boundary whose
711
+ // contract is a typed error. Typed here with the raw fault as its cause, as the named walk
712
+ // below does, so an element and a field fail the same way.
713
+ var element;
714
+ try { element = v[k]; }
715
+ catch (e) { throw _raise(ErrorClass, code, label + ": reading element " + k + " threw", e); }
716
+ arr[k] = _deep(element, ErrorClass, code, label, cap, depth + 1, collect);
717
+ });
718
+ arr.length = v.length;
291
719
  // An array can carry named properties too, and a verb reads an option by name whatever the
292
720
  // argument's type: `opts = []; opts.pem = true` is an options object as far as `opts.pem` is
293
721
  // concerned. Copying only the indexed elements dropped those fields, which silently changed
294
722
  // what the verb was asked to do instead of failing.
295
723
  _copyNamed(v, arr, ErrorClass, code, label, cap, depth, collect);
296
- return arr;
724
+ return _plainCopy(arr);
297
725
  }
298
726
  // The only kinds this module cannot read the state of. One carrying nothing of its own is passed
299
727
  // through: there is no data on it to fix, and a copy would break it. One carrying its own
@@ -302,18 +730,33 @@ function _deep(v, ErrorClass, code, label, cap, depth, collect) {
302
730
  // never half-handled, which is what keeps this from being another shape to be found later.
303
731
  var surface = _opaqueSurface(v, ErrorClass, code, label);
304
732
  if (surface) {
305
- if (_opaqueIsSafeToPass(v, surface)) return v;
306
- throw _raise(ErrorClass, code, label + ": a " + (v.constructor && v.constructor.name || "value") +
307
- " carrying its own fields cannot be used here -- its state cannot be copied, so those fields " +
308
- "would stay changeable after they were checked; pass the fields as a plain object");
733
+ // The name that decided it, so the message says which field to move rather than leaving the
734
+ // caller to find it on an object whose whole problem is that its state cannot be read.
735
+ var carried = _opaqueFieldOutsideSurface(v, surface, ErrorClass, code, label);
736
+ if (carried === null) return v;
737
+ throw _raise(ErrorClass, code, label + ": " + _article(_kindName(v)) + " " + _kindName(v) +
738
+ " carrying its own field " + JSON.stringify(String(carried)) + " cannot be used here -- its " +
739
+ "state cannot be copied, so that field would stay changeable after it was checked; pass the " +
740
+ "fields as a plain object");
741
+ }
742
+ if (util.types.isMap(v)) {
743
+ return _plainCopy(_copyEntries(v, new Map(), ErrorClass, code, label, cap, depth, collect));
744
+ }
745
+ if (util.types.isSet(v)) {
746
+ return _plainCopy(_copyEntries(v, new Set(), ErrorClass, code, label, cap, depth, collect));
309
747
  }
310
- if (v instanceof Map) return _copyEntries(v, new Map(), ErrorClass, code, label, cap, depth, collect);
311
- if (v instanceof Set) return _copyEntries(v, new Set(), ErrorClass, code, label, cap, depth, collect);
312
- // The prototype is kept so an instance's methods still resolve. A null-prototype dictionary
313
- // (what `JSON.parse` or an explicit `Object.create(null)` produces) must not come back
314
- // inheriting from Object.prototype either, which is why the prototype is carried across and
315
- // never assumed.
316
- var out = Object.create(Object.getPrototypeOf(v));
748
+ // A plain object, or a dictionary with no prototype at all -- never the caller's class.
749
+ //
750
+ // Carrying the class across was for its methods, and it cost what copying is for: the copy went
751
+ // on dispatching into the caller's code, and their class could be rewritten after the call had
752
+ // begun. The names the copy reports do not depend on it, which the vectors measure rather than
753
+ // assume, and no verb calls a method on an options bag.
754
+ //
755
+ // Having NO prototype is different and is kept. `Object.create(null)` and what `JSON.parse`
756
+ // produces inherit nothing, and a copy that gained `Object.prototype` would inherit whatever a
757
+ // runtime has planted there -- names the original never answered, reported against a caller who
758
+ // never wrote them.
759
+ var out = Object.create(Object.getPrototypeOf(v) === null ? null : Object.prototype);
317
760
  _copyNamed(v, out, ErrorClass, code, label, cap, depth, collect);
318
761
  return out;
319
762
  }
@@ -329,25 +772,49 @@ function _deep(v, ErrorClass, code, label, cap, depth, collect) {
329
772
  // allocated from). Every one of those is already correct on the copy, and reading them would
330
773
  // copy things the caller never passed. Enumerating the accessors to skip is the wrong way round;
331
774
  // what the caller added is exactly what is own and not an index.
332
- function _namesToCopy(src, dst) {
333
- var indexed = Array.isArray(dst) || ArrayBuffer.isView(dst);
334
- var kind = indexed || dst instanceof Map || dst instanceof Set || dst instanceof ArrayBuffer;
335
- if (!kind) return _reachableKeys(src);
336
- var own = Object.getOwnPropertyNames(src);
337
- var out = [];
338
- for (var i = 0; i < own.length; i++) {
339
- if (own[i] === "length" || (indexed && String(Number(own[i])) === own[i])) continue;
340
- out.push(own[i]);
341
- }
342
- return out;
775
+ //
776
+ // Which strings are indices is guard-identifier's to answer, for names and for elements alike. A
777
+ // second copy of that test here could drift from it, and the set of names that module passes over
778
+ // would then stop matching the set this one carries across as structure.
779
+
780
+ // The names to carry across, asked of the module that decides which names a caller supplied.
781
+ //
782
+ // One walk answers for both questions, because a second walk here drifts from it and the two then
783
+ // disagree about one value. A walk that stops at whatever object is identical to `Object.prototype`
784
+ // 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 `Object.create(Array.prototype)` an own `length`
786
+ // and `Symbol.unscopables`. Either way the copy holds a different set than the check accepted, and
787
+ // a bag that passes the check is refused once it has been copied.
788
+ //
789
+ // The prototype is kept on every branch, so a name skipped here still resolves through it, and the
790
+ // indices of an array are carried by that branch as the structure they are. What the check reads
791
+ // is therefore what the copy answers to.
792
+ function _namesToCopy(src, ErrorClass, code, label, atArgument) {
793
+ var E = function (c, m) { return _raise(ErrorClass, c, m); };
794
+ var names = identifier.readableNames(src, E, code, label);
795
+ // Refused here as well as at the options door, because this copy runs FIRST for the verbs that
796
+ // take a spec. Reading an accessor and writing what it returned as plain data leaves the later
797
+ // check nothing to find: it sees a value and cannot tell an accessor was ever there, so a field
798
+ // that answers differently on the next read passes as a settled one.
799
+ //
800
+ // The argument itself, not everything under it. A platform object nested in a spec carries its
801
+ // own accessors, and a Node KeyObject inside a signer holds `asymmetricKeyType` among others;
802
+ // those belong to the platform and refusing them turns an ordinary signer into a bad input.
803
+ if (atArgument) identifier.refuseAccessorFields(src, names, E, code, label);
804
+ return names;
343
805
  }
344
806
 
345
807
  // A Map or a Set is data the caller can still change, entry by entry, so it is copied like any
346
808
  // other: entries first, then the named properties one can carry alongside them.
347
809
  function _copyEntries(src, dst, ErrorClass, code, label, cap, depth, collect) {
348
- src.forEach(function (value, key) {
810
+ // The walk uses the intrinsic `forEach`, called against the collection. `forEach` is an ordinary
811
+ // method on `Map.prototype` and `Set.prototype`, so an own one or a subclass's answers instead:
812
+ // 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
+ var walk = util.types.isSet(src) ? Set.prototype.forEach : Map.prototype.forEach;
815
+ walk.call(src, function (value, key) {
349
816
  var copiedValue = _deep(value, ErrorClass, code, label, cap, depth + 1, collect);
350
- if (dst instanceof Set) dst.add(copiedValue);
817
+ if (util.types.isSet(dst)) dst.add(copiedValue);
351
818
  else dst.set(_deep(key, ErrorClass, code, label, cap, depth + 1, collect), copiedValue);
352
819
  });
353
820
  _copyNamed(src, dst, ErrorClass, code, label, cap, depth, collect);
@@ -362,8 +829,20 @@ function _copyEntries(src, dst, ErrorClass, code, label, cap, depth, collect) {
362
829
  // copy is what makes an inherited value stop tracking the caller's prototype. A method is left
363
830
  // where it is, since copying a function would only move it, and it is the prototype's behavior,
364
831
  // not the caller's data.
365
- function _copyNamed(src, dst, ErrorClass, code, label, cap, depth, collect) {
366
- var keys = _namesToCopy(src, dst);
832
+ // The names `Date.prototype` supplies, read off the language rather than written out, so a method
833
+ // the language gains later is behavior here on the day it lands.
834
+ var _DATE_BEHAVIOR = (function () {
835
+ var t = Object.create(null);
836
+ Reflect.ownKeys(Date.prototype).forEach(function (n) { t[n] = 1; });
837
+ return t;
838
+ })();
839
+
840
+ // `behavior`, when given, names what belongs to the destination's KIND rather than to the caller.
841
+ // An own property under one of those names is a shadow of the kind's own method, and copying it
842
+ // down would make the copy answer with the caller's function where the original answered with the
843
+ // language's. The copy is meant to be that kind holding the caller's data.
844
+ function _copyNamed(src, dst, ErrorClass, code, label, cap, depth, collect, behavior) {
845
+ var keys = _namesToCopy(src, ErrorClass, code, label, depth === 0);
367
846
  for (var k = 0; k < keys.length; k++) {
368
847
  var value;
369
848
  // Reading a caller's property can run a caller's accessor, and one that throws is a bad input
@@ -371,6 +850,12 @@ function _copyNamed(src, dst, ErrorClass, code, label, cap, depth, collect) {
371
850
  // and never escapes as itself from inside a verb the caller called for something else.
372
851
  try { value = src[keys[k]]; }
373
852
  catch (e) { throw _raise(ErrorClass, code, label + ": reading " + JSON.stringify(keys[k]) + " threw", e); }
853
+ // A name the destination's KIND already defines, holding a FUNCTION, is a shadow of that
854
+ // kind's own method: copying it down would make the copy answer with the caller's code where
855
+ // the original answered with the language's. The value decides, not the name -- a plain
856
+ // `date.getTime = "unused"` is a field, and dropping it took the caller's typo out of reach of
857
+ // the unknown-option check, which is the silence this release exists to end.
858
+ if (behavior && behavior[keys[k]] && typeof value === "function") continue;
374
859
  // A function is carried across by reference, since there is nothing in it to copy, but it is
375
860
  // still carried. Dropping it changed what the caller passed: an unknown spec
376
861
  // field whose value happened to be a function stopped reaching the verb's own key check, so a
@@ -459,5 +944,6 @@ function fixedCall(ErrorClass, code, args, body) {
459
944
 
460
945
  module.exports = {
461
946
  view: view, source: source, snapshot: snapshot, snapshotSource: snapshotSource,
947
+ isByteSource: isByteSource, lengthOf: lengthOf, outputView: outputView,
462
948
  snapshotDeep: snapshotDeep, fixArguments: fixArguments, fixedCall: fixedCall,
463
949
  };