@blamejs/pki 0.8.54 → 0.8.56
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 +84 -0
- package/lib/acme.js +2 -2
- package/lib/asn1-der.js +17 -5
- package/lib/attrcert-verify.js +1 -1
- package/lib/cmc-verify.js +1 -1
- package/lib/cmp-session.js +2 -2
- package/lib/cmp-verify.js +2 -2
- package/lib/cms-decrypt.js +4 -1
- package/lib/cms-encrypt.js +4 -1
- package/lib/cms-sign.js +26 -12
- package/lib/cms-verify.js +1 -1
- package/lib/composite-kem.js +30 -12
- package/lib/composite-sig.js +42 -23
- package/lib/constants.js +7 -2
- package/lib/crl-verify.js +1 -1
- package/lib/crmf-sign.js +72 -43
- package/lib/crmf-verify.js +1 -1
- package/lib/csr-verify.js +1 -1
- package/lib/ct.js +11 -13
- package/lib/edwards-point.js +1 -1
- package/lib/est.js +3 -3
- package/lib/guard-async.js +22 -1
- package/lib/guard-bytes.js +6 -3
- package/lib/guard-identifier.js +24 -1
- package/lib/guard-intrinsic.js +474 -0
- package/lib/http-digest.js +146 -62
- package/lib/http-transport.js +82 -17
- package/lib/identity-match.js +2 -2
- package/lib/merkle.js +2 -2
- package/lib/ocsp-request-verify.js +1 -1
- package/lib/ocsp.js +46 -22
- package/lib/path-validate.js +234 -88
- package/lib/pbes2.js +14 -7
- package/lib/schema-attrcert.js +2 -2
- package/lib/schema-cmc.js +2 -2
- package/lib/schema-cmp.js +2 -2
- package/lib/schema-cms.js +2 -2
- package/lib/schema-crmf.js +2 -2
- package/lib/schema-csr.js +2 -2
- package/lib/schema-pkix.js +3 -3
- package/lib/schema-x509.js +2 -2
- package/lib/sigstore.js +14 -3
- package/lib/tlog.js +7 -4
- package/lib/trust.js +187 -104
- package/lib/tsp-sign.js +1 -1
- package/lib/webauthn-mds.js +257 -121
- package/lib/webauthn.js +327 -164
- package/lib/webcrypto.js +10 -3
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/crmf-sign.js
CHANGED
|
@@ -43,10 +43,9 @@ var _Promise = intrinsic.Promise;
|
|
|
43
43
|
var _promiseResolve = intrinsic.uncurry(intrinsic.promiseResolve);
|
|
44
44
|
/** @internal `verifyPop`'s verdict is the aggregate of the per-message results, so a replaced `all`
|
|
45
45
|
* that resolves a fabricated array reports an unverified proof of possession as verified. */
|
|
46
|
-
var _promiseAll = intrinsic.uncurry(intrinsic.promiseAll);
|
|
47
46
|
var _hasOwn = intrinsic.hasOwn;
|
|
48
47
|
var _isBuffer = intrinsic.isBuffer;
|
|
49
|
-
var
|
|
48
|
+
var _String = intrinsic.String;
|
|
50
49
|
var _stringify = intrinsic.stringify;
|
|
51
50
|
var cms = require("./schema-cms");
|
|
52
51
|
var possession = require("./possession");
|
|
@@ -108,7 +107,7 @@ function _ctlPossession(v) {
|
|
|
108
107
|
b.raw(_b.reqDer(issuerRaw, "statementOfPossession signer.issuer (the signature certificate's issuer Name DER)")),
|
|
109
108
|
b.integer(guard.range.authoredInteger(signer.serialNumber, _err, "crmf/bad-controls", "statementOfPossession signer.serialNumber")),
|
|
110
109
|
])];
|
|
111
|
-
if (v.certificate != null)
|
|
110
|
+
if (v.certificate != null) guard.list.append(fields, b.raw(_b.reqDer(v.certificate, "statementOfPossession certificate")));
|
|
112
111
|
var der = b.sequence(fields);
|
|
113
112
|
try { possession.parse(der); }
|
|
114
113
|
catch (e) { throw _err("crmf/bad-controls", "statementOfPossession: " + ((e && e.message) || _String(e)), e); }
|
|
@@ -177,8 +176,8 @@ function _encodeOptionalValidity(validity) {
|
|
|
177
176
|
var nb = validity.notBefore, na = validity.notAfter;
|
|
178
177
|
if (nb == null && na == null) throw _err("crmf/bad-validity", "validity must contain notBefore or notAfter (RFC 4211 sec. 5)");
|
|
179
178
|
var parts = [];
|
|
180
|
-
if (nb != null)
|
|
181
|
-
if (na != null)
|
|
179
|
+
if (nb != null) guard.list.append(parts, b.explicit(0, _b.timeDer(nb, "validity notBefore")));
|
|
180
|
+
if (na != null) guard.list.append(parts, b.explicit(1, _b.timeDer(na, "validity notAfter")));
|
|
182
181
|
// allow:nan-date-comparison-unguarded -- both instants passed timeDer's guard.time.assertEncodable above.
|
|
183
182
|
if (nb != null && na != null && guard.time.instantOf(nb) > guard.time.instantOf(na)) throw _err("crmf/bad-validity", "notBefore must not be after notAfter");
|
|
184
183
|
return b.implicit(4, b.sequence(parts));
|
|
@@ -190,19 +189,22 @@ function _encodeCertTemplate(tpl, opts) {
|
|
|
190
189
|
var fields = [];
|
|
191
190
|
if (tpl.version != null) {
|
|
192
191
|
if (tpl.version !== 2) throw _err("crmf/bad-version", "certTemplate version MUST be 2 (v3) if supplied (RFC 4211 sec. 5)");
|
|
193
|
-
|
|
192
|
+
guard.list.append(fields, b.implicit(0, b.integer(2n)));
|
|
194
193
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if (tpl.
|
|
194
|
+
/** @internal Appended through the guard. These members are the template a proof of possession is
|
|
195
|
+
* computed over and a CA issues from, so a replaced append that drops or substitutes one changes
|
|
196
|
+
* what was requested from what was proven. */
|
|
197
|
+
if (tpl.serialNumber != null) guard.list.append(fields, b.implicit(1, _b.serialInteger(tpl.serialNumber)));
|
|
198
|
+
if (tpl.issuer != null) guard.list.append(fields, b.explicit(3, _b.encodeName(tpl.issuer)));
|
|
199
|
+
if (tpl.validity != null) guard.list.append(fields, _encodeOptionalValidity(tpl.validity));
|
|
200
|
+
if (tpl.subject != null) guard.list.append(fields, b.explicit(5, _b.encodeName(tpl.subject)));
|
|
199
201
|
var spki = null;
|
|
200
202
|
if (tpl.publicKey != null) {
|
|
201
203
|
spki = _b.reqDer(tpl.publicKey, "certTemplate.publicKey (the SPKI DER of the requested key)");
|
|
202
204
|
_b.assertValidSpki(spki, "certTemplate.publicKey");
|
|
203
|
-
|
|
205
|
+
guard.list.append(fields, b.implicit(6, spki));
|
|
204
206
|
}
|
|
205
|
-
if (tpl.extensions != null)
|
|
207
|
+
if (tpl.extensions != null) guard.list.append(fields, b.implicit(9, _b.requestedExtensions(tpl.extensions, spki)));
|
|
206
208
|
return { der: b.sequence(fields), spki: spki, complete: tpl.subject != null && tpl.publicKey != null };
|
|
207
209
|
}
|
|
208
210
|
|
|
@@ -237,7 +239,7 @@ function _buildAttrTypeAndValues(spec, code, label, valueMap, collect) {
|
|
|
237
239
|
var typeOid = O(k);
|
|
238
240
|
if (seen[typeOid]) throw _err(code, "duplicate " + label + " type " + k);
|
|
239
241
|
seen[typeOid] = true;
|
|
240
|
-
|
|
242
|
+
guard.list.append(out, b.sequence([b.oid(typeOid), enc(spec[k])]));
|
|
241
243
|
});
|
|
242
244
|
if (!out.length) throw _err(code, label + " must carry at least one entry");
|
|
243
245
|
return b.sequence(out);
|
|
@@ -916,19 +918,23 @@ function _buildEncryptedKeyPop(pop, outerTag, template) {
|
|
|
916
918
|
"the proof is that the enclosed private key is the one being certified (RFC 4211 sec. 4.2)");
|
|
917
919
|
}
|
|
918
920
|
encKeyWithIdDer = _encKeyWithID(privateKeyDer, pop.identifier);
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
921
|
+
/** @internal Each step is continued through the capture. The first decides whether the enclosed
|
|
922
|
+
* private key IS the one being certified, which is the whole proof, and the last is what wipes the
|
|
923
|
+
* key material whichever way the chain settles. */
|
|
924
|
+
var enveloped = intrinsic.chain(_assertEnclosedKeyMatches(privateKeyDer, template.spki), function () {
|
|
925
|
+
var encrypted = cmsEncrypt.encrypt(encKeyWithIdDer, recipients,
|
|
926
|
+
{ contentType: "encKeyWithID", contentEncryptionAlgorithm: cea });
|
|
927
|
+
return intrinsic.chain(encrypted, null, function (e) {
|
|
928
|
+
if (e instanceof CrmfError) throw e;
|
|
929
|
+
throw _err("crmf/bad-input", "the encryptedKey proof of possession could not envelope the private key to " +
|
|
930
|
+
"pop.recipients: " + ((e && e.message) || e), e);
|
|
931
|
+
});
|
|
932
|
+
});
|
|
933
|
+
var wrapped = intrinsic.chain(enveloped, function (contentInfo) {
|
|
934
|
+
var inner = _bareEnvelopedData(contentInfo);
|
|
935
|
+
return b.explicit(outerTag, b.implicit(4, inner));
|
|
936
|
+
});
|
|
937
|
+
return intrinsic.chain(wrapped, function (out) { wipe(); return out; }, function (e) { wipe(); throw e; });
|
|
932
938
|
}
|
|
933
939
|
}
|
|
934
940
|
|
|
@@ -964,9 +970,9 @@ function _assertEnclosedKeyMatches(privateKeyDer, templateSpki) {
|
|
|
964
970
|
* cannot use it, so those are proven by USING the key against the template. */
|
|
965
971
|
var enclosedAlg = key.algorithmOidAt(privateKeyDer, 1);
|
|
966
972
|
if (enclosedAlg !== null && !key.isDhOid(enclosedAlg)) return _assertEnclosedKeyCorresponds(privateKeyDer, templateSpki);
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
973
|
+
var derivedP = intrinsic.chain(_promiseResolve(_Promise, undefined),
|
|
974
|
+
function () { return key.publicFromPrivate(privateKeyDer); });
|
|
975
|
+
return intrinsic.chain(derivedP, function (derivedSpki) {
|
|
970
976
|
var derived = guard.bytes.view(derivedSpki, CrmfError, "crmf/bad-input", "the derived public key");
|
|
971
977
|
var wanted = guard.bytes.view(templateSpki, CrmfError, "crmf/bad-input", "certTemplate.publicKey");
|
|
972
978
|
/** @internal A finite-field key names itself in either encoding here too, and an enclosed key
|
|
@@ -1074,12 +1080,20 @@ function _buildProofOfPossession(pop, certReqDer, template, signingKey, opts, po
|
|
|
1074
1080
|
signedRegion = poposkSeq;
|
|
1075
1081
|
poposkInputField = b.implicit(0, poposkSeq);
|
|
1076
1082
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1083
|
+
/** @internal Both continuations are captured. The inner one runs after the proof's own signature
|
|
1084
|
+
* has been verified against the key being certified, so a replacement settling it emits a proof
|
|
1085
|
+
* whose signature was never checked against that key. */
|
|
1086
|
+
return intrinsic.chain(signScheme.signOverTbs(scheme, signingKey, signedRegion, _signE), function (sig) {
|
|
1087
|
+
var selfChecked = _promiseResolve(_Promise, _b.assertSignatureVerifies(signedRegion, sig, provingSpki, scheme));
|
|
1088
|
+
return intrinsic.chain(selfChecked, function () {
|
|
1079
1089
|
var popoChildren = [];
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1090
|
+
/** @internal Appended through the guard, which defines the index rather than calling a method
|
|
1091
|
+
* the prototype answers for. These three members ARE the proof: the signature value is added
|
|
1092
|
+
* AFTER it has been verified against the key being certified, so a replaced append that alters
|
|
1093
|
+
* it emits a proof whose bytes nothing checked. */
|
|
1094
|
+
if (poposkInputField) guard.list.append(popoChildren, poposkInputField);
|
|
1095
|
+
guard.list.append(popoChildren, scheme.sigAlgId);
|
|
1096
|
+
guard.list.append(popoChildren, b.bitString(sig, 0));
|
|
1083
1097
|
return b.implicit(1, b.sequence(popoChildren));
|
|
1084
1098
|
});
|
|
1085
1099
|
}, function (e) {
|
|
@@ -1171,7 +1185,7 @@ function _buildCertReqMsg(spec, key, opts) {
|
|
|
1171
1185
|
var template = _encodeCertTemplate(spec.certTemplate);
|
|
1172
1186
|
var certReqChildren = [b.integer(_certReqId(spec.certReqId)), template.der];
|
|
1173
1187
|
var encodedControls = [];
|
|
1174
|
-
if (spec.controls != null)
|
|
1188
|
+
if (spec.controls != null) guard.list.append(certReqChildren, _buildAttrTypeAndValues(spec.controls, "crmf/bad-controls", "controls", CONTROL_VALUE, encodedControls));
|
|
1175
1189
|
var certReqDer = b.sequence(certReqChildren);
|
|
1176
1190
|
|
|
1177
1191
|
/** @internal The key the RFC 9883 control names, when the request carries one: that key makes the
|
|
@@ -1196,10 +1210,12 @@ function _buildCertReqMsg(spec, key, opts) {
|
|
|
1196
1210
|
possessionSpki = _encodedPossessionSpki(encodedControls);
|
|
1197
1211
|
}
|
|
1198
1212
|
|
|
1199
|
-
|
|
1213
|
+
var popoP = _promiseResolve(_Promise,
|
|
1214
|
+
_buildProofOfPossession(spec.pop, certReqDer, template, signingKey, opts, possessionSpki));
|
|
1215
|
+
return intrinsic.chain(popoP, function (popoDer) {
|
|
1200
1216
|
var msgChildren = [certReqDer];
|
|
1201
|
-
if (popoDer)
|
|
1202
|
-
if (spec.regInfo != null)
|
|
1217
|
+
if (popoDer) guard.list.append(msgChildren, popoDer);
|
|
1218
|
+
if (spec.regInfo != null) guard.list.append(msgChildren, _buildAttrTypeAndValues(spec.regInfo, "crmf/bad-reg-info", "regInfo", REGINFO_VALUE));
|
|
1203
1219
|
return b.sequence(msgChildren);
|
|
1204
1220
|
});
|
|
1205
1221
|
}
|
|
@@ -1218,7 +1234,9 @@ function _build(spec, key, opts) {
|
|
|
1218
1234
|
specs = [spec];
|
|
1219
1235
|
}
|
|
1220
1236
|
if (!specs.length) throw _err("crmf/bad-input", "at least one certificate request message is required (RFC 4211 sec. 3)");
|
|
1221
|
-
return
|
|
1237
|
+
return intrinsic.chain(intrinsic.allOf(intrinsic.mapList(specs, function (s) {
|
|
1238
|
+
return _buildCertReqMsg(s, key, opts);
|
|
1239
|
+
})), function (msgs) {
|
|
1222
1240
|
var der = b.sequence(msgs);
|
|
1223
1241
|
if (opts.pem != null) {
|
|
1224
1242
|
if (typeof opts.pem !== "string" || !opts.pem) throw _err("crmf/bad-input", "opts.pem must be a non-empty PEM label string");
|
|
@@ -1310,7 +1328,10 @@ function _verifyOne(msg) {
|
|
|
1310
1328
|
spki = sopSpki;
|
|
1311
1329
|
bound = false;
|
|
1312
1330
|
}
|
|
1313
|
-
|
|
1331
|
+
/** @internal The continuation comes from the capture. It is where the signature answer becomes this
|
|
1332
|
+
* message's verdict, so a replacement settling it hands back a record stating `verified: true` for
|
|
1333
|
+
* a proof nothing checked, and the aggregate above then reports the whole set as verified. */
|
|
1334
|
+
return intrinsic.chain(crmfVerify.verifyPopSignature(popo, spki, preimage), function (ok) {
|
|
1314
1335
|
return guard.verdict.of(base, {
|
|
1315
1336
|
valid: ok === true, verified: ok === true, method: "signature", cryptographicallyVerified: ok === true,
|
|
1316
1337
|
subject: bound ? base.subject : null,
|
|
@@ -1368,9 +1389,17 @@ function _verifyOne(msg) {
|
|
|
1368
1389
|
function verifyPop(messages) { return guard.async.deferred(function () { return _verifyPop(messages); }); }
|
|
1369
1390
|
function _verifyPop(messages) {
|
|
1370
1391
|
var parsed = _coerceMessages(messages);
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1392
|
+
/** @internal The aggregate, the projection into it and the universal test over its results all come
|
|
1393
|
+
* from the captures. This IS the proof-of-possession verdict for a set of requests: the aggregate's
|
|
1394
|
+
* static form reads `resolve` off the constructor at each call, so a replacement answers for every
|
|
1395
|
+
* message without one being verified, and the test below is what requires all of them to have
|
|
1396
|
+
* verified. */
|
|
1397
|
+
return intrinsic.chain(intrinsic.allOf(intrinsic.mapList(parsed.messages, _verifyOne)), function (out) {
|
|
1398
|
+
var allVerified = out.length > 0 && intrinsic.everyOwn(out, function (m) { return m && m.verified === true; });
|
|
1399
|
+
/** @internal Copied before it is handed back. The aggregate's own list carries no prototype, so
|
|
1400
|
+
* that a `then` installed on `Array.prototype` cannot settle the aggregate with something else;
|
|
1401
|
+
* a caller reading `result.messages` expects an ordinary array it can iterate and map. */
|
|
1402
|
+
return guard.verdict.of({ valid: allVerified, verified: allVerified, messages: intrinsic.copyList(out) });
|
|
1374
1403
|
});
|
|
1375
1404
|
}
|
|
1376
1405
|
|
package/lib/crmf-verify.js
CHANGED
|
@@ -12,4 +12,4 @@ function verifyPopSignature(popo, spkiBytes, preimage) {
|
|
|
12
12
|
return _seam.verify(popo.algorithmIdentifier, popo.signature, spkiBytes, preimage);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
module.exports = { setEngine: _seam.setEngine, verifyPopSignature: verifyPopSignature };
|
|
15
|
+
module.exports = Object.freeze({ setEngine: _seam.setEngine, verifyPopSignature: verifyPopSignature });
|
package/lib/csr-verify.js
CHANGED
|
@@ -13,4 +13,4 @@ function verifyCsrSignature(parsed) {
|
|
|
13
13
|
parsed.subjectPublicKeyInfo.bytes, parsed.certificationRequestInfoBytes);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
module.exports = { setEngine: _seam.setEngine, verifyCsrSignature: verifyCsrSignature };
|
|
16
|
+
module.exports = Object.freeze({ setEngine: _seam.setEngine, verifyCsrSignature: verifyCsrSignature });
|
package/lib/ct.js
CHANGED
|
@@ -1353,18 +1353,16 @@ function _clientDoor(opts, keyName) {
|
|
|
1353
1353
|
}
|
|
1354
1354
|
|
|
1355
1355
|
/** @internal Every DECLARED option the bag can answer, read once into a record of plain values, before
|
|
1356
|
-
* anything derives from one.
|
|
1357
|
-
*
|
|
1358
|
-
* which
|
|
1359
|
-
* prototype chain exactly as the direct reads it replaces did,
|
|
1360
|
-
*
|
|
1361
|
-
*
|
|
1356
|
+
* anything derives from one. The presence-preserving snapshot is the one this module needs: absence
|
|
1357
|
+
* survives, so a name the bag cannot answer is left out rather than materialized as `undefined`,
|
|
1358
|
+
* which is what lets an absent `transport` still mean "open the connection yourself, under the
|
|
1359
|
+
* pinned anchors". It consults the prototype chain exactly as the direct reads it replaces did,
|
|
1360
|
+
* because the door accepts an option supplied through a caller's defaults object and an enumeration
|
|
1361
|
+
* omits an inherited FUNCTION member, which silently dropped a `transport` and fell through to
|
|
1362
|
+
* opening a real connection. */
|
|
1363
|
+
// @guard-via guard.identifier.snapshotPresentOptions
|
|
1362
1364
|
function _takeTopLevel(bag, known) {
|
|
1363
|
-
|
|
1364
|
-
intrinsic.forEach(intrinsic.keys(known), function (k) {
|
|
1365
|
-
if (k in bag) o[k] = bag[k];
|
|
1366
|
-
});
|
|
1367
|
-
return o;
|
|
1365
|
+
return guard.identifier.snapshotPresentOptions(bag, known);
|
|
1368
1366
|
}
|
|
1369
1367
|
|
|
1370
1368
|
/** @internal The two values a verdict rests on, made IMMUNE rather than merely taken. Holding a
|
|
@@ -2255,7 +2253,7 @@ async function fetchLogList(opts) {
|
|
|
2255
2253
|
});
|
|
2256
2254
|
}
|
|
2257
2255
|
|
|
2258
|
-
module.exports = {
|
|
2256
|
+
module.exports = intrinsic.freeze({
|
|
2259
2257
|
parseSctList: parseSctList,
|
|
2260
2258
|
reconstructSignedData: reconstructSignedData,
|
|
2261
2259
|
verifySct: verifySct,
|
|
@@ -2278,4 +2276,4 @@ module.exports = {
|
|
|
2278
2276
|
addPreChain: addPreChain,
|
|
2279
2277
|
HASH_ALGORITHMS: HASH_ALGORITHMS,
|
|
2280
2278
|
SIGNATURE_ALGORITHMS: SIGNATURE_ALGORITHMS,
|
|
2281
|
-
};
|
|
2279
|
+
});
|
package/lib/edwards-point.js
CHANGED
package/lib/est.js
CHANGED
|
@@ -287,7 +287,7 @@ function _findMultipartMarks(text, boundary) {
|
|
|
287
287
|
if (lsN !== -1) { var r1 = _matchDelimAt(text, lsN, boundary); if (r1) { found = r1; foundAt = p; break; } }
|
|
288
288
|
}
|
|
289
289
|
if (!found) break;
|
|
290
|
-
marks
|
|
290
|
+
guard.list.append(marks, { at: foundAt, bodyStart: found.end, close: found.close });
|
|
291
291
|
searchStart = found.end === foundAt ? found.end + 1 : found.end;
|
|
292
292
|
}
|
|
293
293
|
return marks;
|
|
@@ -328,9 +328,9 @@ function _splitCrlf(s) {
|
|
|
328
328
|
var nlLen = 0;
|
|
329
329
|
if (_charCodeAt(s, i) === 0x0d && i + 1 < n && _charCodeAt(s, i + 1) === 0x0a) nlLen = 2;
|
|
330
330
|
else if (_charCodeAt(s, i) === 0x0a) nlLen = 1;
|
|
331
|
-
if (nlLen > 0) { out
|
|
331
|
+
if (nlLen > 0) { guard.list.append(out, _strSlice(s, last, i)); i += nlLen; last = i; } else i += 1;
|
|
332
332
|
}
|
|
333
|
-
out
|
|
333
|
+
guard.list.append(out, _strSlice(s, last, n));
|
|
334
334
|
return out;
|
|
335
335
|
}
|
|
336
336
|
|
package/lib/guard-async.js
CHANGED
|
@@ -22,6 +22,26 @@ function deferred(body) {
|
|
|
22
22
|
catch (e) { return _reject(_Promise, e); }
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
// @internal
|
|
26
|
+
/** @internal A continuation taken from the capture, for a module that holds the guards rather than
|
|
27
|
+
* the intrinsic captures directly. `p.then(f)` reads `then` off the promise at the call, so a
|
|
28
|
+
* replacement settles the chain without running `f`, and `f` is where a step's result becomes the
|
|
29
|
+
* next step's input. */
|
|
30
|
+
// @enforced-by behavioral -- the RED vectors live with each consumer's own verdict
|
|
31
|
+
function chain(p, onOk, onFail) {
|
|
32
|
+
return _intrinsic.chain(p, onOk, onFail);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// @internal
|
|
36
|
+
/** @internal Run `body` once the work settles, either way, and pass the outcome through unchanged.
|
|
37
|
+
* `Promise.prototype.finally` is not this: it calls the receiver's own `then`, which is the live
|
|
38
|
+
* method, so a replacement there settles the chain with a value of its own AND skips the callback.
|
|
39
|
+
* Cleanup that wipes key material is exactly the callback that must not be skipped. */
|
|
40
|
+
// @enforced-by behavioral -- each consumer's RED vector drives its own cleanup
|
|
41
|
+
function cleanup(p, body) {
|
|
42
|
+
return _intrinsic.chain(p, function (out) { body(); return out; }, function (e) { body(); throw e; });
|
|
43
|
+
}
|
|
44
|
+
|
|
25
45
|
// @internal
|
|
26
46
|
// @enforced-by behavioral -- a RED vector in each client suite refuses a transport yielding no thenable
|
|
27
47
|
function awaited(value, E, code, label) {
|
|
@@ -96,4 +116,5 @@ function bounded(value, ms, E, code, label) {
|
|
|
96
116
|
});
|
|
97
117
|
}
|
|
98
118
|
|
|
99
|
-
module.exports = _intrinsic.freeze({ deferred: deferred, awaited: awaited, invoked: invoked, bounded: bounded
|
|
119
|
+
module.exports = _intrinsic.freeze({ deferred: deferred, awaited: awaited, invoked: invoked, bounded: bounded,
|
|
120
|
+
chain: chain, cleanup: cleanup });
|
package/lib/guard-bytes.js
CHANGED
|
@@ -34,7 +34,6 @@ var _mapForEach = intrinsic.uncurry(Map.prototype.forEach);
|
|
|
34
34
|
var _String = intrinsic.String;
|
|
35
35
|
var _Date = intrinsic.Date;
|
|
36
36
|
var _apply = intrinsic.apply;
|
|
37
|
-
var _promiseFinally = intrinsic.promiseFinally;
|
|
38
37
|
var _ArrayBuffer = intrinsic.ArrayBuffer;
|
|
39
38
|
var _Uint8Array = intrinsic.Uint8Array;
|
|
40
39
|
var _DataView = intrinsic.DataView;
|
|
@@ -559,10 +558,14 @@ function fixArguments(ErrorClass, code, args) {
|
|
|
559
558
|
// @enforced-by behavioral -- an arrangement of two calls has no rename-proof shape to detect. The
|
|
560
559
|
function fixedCall(ErrorClass, code, args, body) {
|
|
561
560
|
var handle = null;
|
|
562
|
-
|
|
561
|
+
/** @internal The release is attached on BOTH outcomes rather than through `finally`, which calls
|
|
562
|
+
* the receiver's own `then` and so reads the live method: a replacement there settles the chain
|
|
563
|
+
* with a value of its own AND skips this callback, so the fixed views stay pinned. */
|
|
564
|
+
var ran = async.deferred(function () {
|
|
563
565
|
handle = fixArguments(ErrorClass, code, args);
|
|
564
566
|
return _apply(body, null, handle.values);
|
|
565
|
-
})
|
|
567
|
+
});
|
|
568
|
+
return async.cleanup(ran, function () { if (handle) handle.release(); });
|
|
566
569
|
}
|
|
567
570
|
|
|
568
571
|
/**
|
package/lib/guard-identifier.js
CHANGED
|
@@ -69,7 +69,7 @@ function assertCanonicalOid(str, E, code, label, boundsCode, countCode) {
|
|
|
69
69
|
}
|
|
70
70
|
if (boundsCode === null) return str;
|
|
71
71
|
var bcode = boundsCode === undefined ? code : boundsCode;
|
|
72
|
-
var parts =
|
|
72
|
+
var parts = intrinsic.splitChar(str, 46);
|
|
73
73
|
if (parts.length - 1 > constants.LIMITS.OID_MAX_SUBIDENTIFIERS) {
|
|
74
74
|
throw E(countCode || bcode, who + " carries more than " + constants.LIMITS.OID_MAX_SUBIDENTIFIERS + " sub-identifiers");
|
|
75
75
|
}
|
|
@@ -101,6 +101,28 @@ function snapshotOptions(obj, known) {
|
|
|
101
101
|
return out;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/** @internal The same one-read capture, for a caller that tells an ABSENT option from one present
|
|
105
|
+
* and holding `undefined`. `snapshotOptions` materializes every declared name, which is correct for
|
|
106
|
+
* a caller testing `!== undefined` and wrong for one testing presence: an omitted option becomes an
|
|
107
|
+
* own key, and a presence-based guard then sees an option the caller never passed. Measured, a bag
|
|
108
|
+
* omitting `transport` is ACCEPTED by `assertCallableOption` and REFUSED after `snapshotOptions`,
|
|
109
|
+
* because the materialized `undefined` is a transport that is not callable.
|
|
110
|
+
*
|
|
111
|
+
* Presence consults the prototype chain, because a caller supplying options through a defaults
|
|
112
|
+
* object is supplying them, and an enumeration omits an inherited FUNCTION member: that is how a
|
|
113
|
+
* copy once dropped a `transport` and fell through to opening a real connection where the caller
|
|
114
|
+
* had passed a fake one. The VALUE is still read once per name, which is what the snapshot is for.
|
|
115
|
+
* The two live side by side rather than behind a flag so a caller chooses between them knowingly. */
|
|
116
|
+
// @enforced-by guard-shape-reinlined
|
|
117
|
+
// @guard-shape if \(\w+ in \w+\) \w+\[\w+\] = \w+\[\w+\];
|
|
118
|
+
function snapshotPresentOptions(obj, known) {
|
|
119
|
+
var out = _create(null);
|
|
120
|
+
if (obj === null || obj === undefined) return out;
|
|
121
|
+
var o = _Object(obj);
|
|
122
|
+
_forEach(_getOwnPropertyNames(known), function (k) { if (k in o) out[k] = o[k]; });
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
|
|
104
126
|
/** @internal The option names a bag carries, read the way assertKnownKeys read them: every own
|
|
105
127
|
* string key, whatever its descriptor says. Object.keys reports only the enumerable ones, so an
|
|
106
128
|
* option written with `enumerable: false` clears the door and then vanishes from the read.
|
|
@@ -656,6 +678,7 @@ module.exports = intrinsic.freeze({
|
|
|
656
678
|
optionsObject: optionsObject,
|
|
657
679
|
refuseAccessorFields: refuseAccessorFields,
|
|
658
680
|
snapshotOptions: snapshotOptions,
|
|
681
|
+
snapshotPresentOptions: snapshotPresentOptions,
|
|
659
682
|
optionNames: optionNames,
|
|
660
683
|
ownOptions: ownOptions,
|
|
661
684
|
pickSettings: pickSettings,
|