@learncard/sss-key-manager 0.2.1 → 0.2.3
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/dist/escrow-attestation.d.ts +2 -9
- package/dist/escrow-attestation.d.ts.map +1 -1
- package/dist/escrow-authority.d.ts +138 -0
- package/dist/escrow-authority.d.ts.map +1 -0
- package/dist/escrow-authority.types.d.ts +51 -0
- package/dist/escrow-authority.types.d.ts.map +1 -0
- package/dist/escrow-crypto.d.ts +9 -1
- package/dist/escrow-crypto.d.ts.map +1 -1
- package/dist/escrow-enrollment-intent.d.ts +13 -0
- package/dist/escrow-enrollment-intent.d.ts.map +1 -0
- package/dist/escrow-enrollment-intent.types.d.ts +28 -0
- package/dist/escrow-enrollment-intent.types.d.ts.map +1 -0
- package/dist/escrow-nitro-attestation.d.ts +2 -0
- package/dist/escrow-nitro-attestation.d.ts.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/sss-key-manager.cjs.development.js +1652 -214
- package/dist/sss-key-manager.cjs.development.js.map +4 -4
- package/dist/sss-key-manager.cjs.production.min.js +28 -23
- package/dist/sss-key-manager.cjs.production.min.js.map +4 -4
- package/dist/sss-key-manager.esm.js +1167 -164
- package/dist/sss-key-manager.esm.js.map +4 -4
- package/dist/sss-strategy.d.ts +2 -1
- package/dist/sss-strategy.d.ts.map +1 -1
- package/dist/types.d.ts +21 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__fixtures__/escrow-authority-v1.json +96 -0
- package/src/__fixtures__/escrow-carry-contact-contract-v1.json +33 -0
- package/src/__fixtures__/escrow-enrollment-intent-v1.json +26 -0
- package/src/__fixtures__/nitro-attestation-real/staging-nsm-document.json +16 -0
- package/src/escrow-attestation.ts +10 -9
- package/src/escrow-authority.test.ts +757 -0
- package/src/escrow-authority.ts +671 -0
- package/src/escrow-authority.types.ts +56 -0
- package/src/escrow-crypto.ts +39 -1
- package/src/escrow-enrollment-intent.test.ts +224 -0
- package/src/escrow-enrollment-intent.ts +236 -0
- package/src/escrow-enrollment-intent.types.ts +28 -0
- package/src/escrow-nitro-attestation.test.ts +72 -0
- package/src/escrow-nitro-attestation.ts +34 -3
- package/src/index.ts +29 -0
- package/src/sss-authority.test.ts +889 -0
- package/src/sss-strategy.test.ts +32 -0
- package/src/sss-strategy.ts +503 -39
- package/src/types.ts +27 -3
|
@@ -199,6 +199,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
199
199
|
FlatAuthGrantValidator: /* @__PURE__ */ __name(() => FlatAuthGrantValidator, "FlatAuthGrantValidator"),
|
|
200
200
|
FrameworkWithSkillsValidator: /* @__PURE__ */ __name(() => FrameworkWithSkillsValidator, "FrameworkWithSkillsValidator"),
|
|
201
201
|
FullClaimHookValidator: /* @__PURE__ */ __name(() => FullClaimHookValidator, "FullClaimHookValidator"),
|
|
202
|
+
GenerateSkillIconsInputValidator: /* @__PURE__ */ __name(() => GenerateSkillIconsInputValidator, "GenerateSkillIconsInputValidator"),
|
|
202
203
|
GeoCoordinatesValidator: /* @__PURE__ */ __name(() => GeoCoordinatesValidator, "GeoCoordinatesValidator"),
|
|
203
204
|
GetCounterEventValidator: /* @__PURE__ */ __name(() => GetCounterEventValidator, "GetCounterEventValidator"),
|
|
204
205
|
GetCountersEventValidator: /* @__PURE__ */ __name(() => GetCountersEventValidator, "GetCountersEventValidator"),
|
|
@@ -359,6 +360,8 @@ var require_types_cjs_development = __commonJS({
|
|
|
359
360
|
SHARE_RECOVERY_PROTOCOL: /* @__PURE__ */ __name(() => SHARE_RECOVERY_PROTOCOL, "SHARE_RECOVERY_PROTOCOL"),
|
|
360
361
|
SHARE_TAG_BYTES: /* @__PURE__ */ __name(() => SHARE_TAG_BYTES, "SHARE_TAG_BYTES"),
|
|
361
362
|
SHARE_VIEW_RECEIPT_TTL_SECONDS: /* @__PURE__ */ __name(() => SHARE_VIEW_RECEIPT_TTL_SECONDS, "SHARE_VIEW_RECEIPT_TTL_SECONDS"),
|
|
363
|
+
SKILL_ICON_MAX_CHARACTERS_PER_REQUEST: /* @__PURE__ */ __name(() => SKILL_ICON_MAX_CHARACTERS_PER_REQUEST, "SKILL_ICON_MAX_CHARACTERS_PER_REQUEST"),
|
|
364
|
+
SKILL_ICON_MAX_NAMES_PER_REQUEST: /* @__PURE__ */ __name(() => SKILL_ICON_MAX_NAMES_PER_REQUEST, "SKILL_ICON_MAX_NAMES_PER_REQUEST"),
|
|
362
365
|
SendAiSessionCredentialEventValidator: /* @__PURE__ */ __name(() => SendAiSessionCredentialEventValidator, "SendAiSessionCredentialEventValidator"),
|
|
363
366
|
SendBoostInputValidator: /* @__PURE__ */ __name(() => SendBoostInputValidator, "SendBoostInputValidator"),
|
|
364
367
|
SendBoostResponseValidator: /* @__PURE__ */ __name(() => SendBoostResponseValidator, "SendBoostResponseValidator"),
|
|
@@ -411,6 +414,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
411
414
|
SkillFrameworkQueryValidator: /* @__PURE__ */ __name(() => SkillFrameworkQueryValidator, "SkillFrameworkQueryValidator"),
|
|
412
415
|
SkillFrameworkStatusEnum: /* @__PURE__ */ __name(() => SkillFrameworkStatusEnum, "SkillFrameworkStatusEnum"),
|
|
413
416
|
SkillFrameworkValidator: /* @__PURE__ */ __name(() => SkillFrameworkValidator, "SkillFrameworkValidator"),
|
|
417
|
+
SkillIconNamesValidator: /* @__PURE__ */ __name(() => SkillIconNamesValidator, "SkillIconNamesValidator"),
|
|
414
418
|
SkillQueryValidator: /* @__PURE__ */ __name(() => SkillQueryValidator, "SkillQueryValidator"),
|
|
415
419
|
SkillSemanticSearchInputValidator: /* @__PURE__ */ __name(() => SkillSemanticSearchInputValidator, "SkillSemanticSearchInputValidator"),
|
|
416
420
|
SkillSemanticSearchResultItemValidator: /* @__PURE__ */ __name(() => SkillSemanticSearchResultItemValidator, "SkillSemanticSearchResultItemValidator"),
|
|
@@ -568,7 +572,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
568
572
|
_function: /* @__PURE__ */ __name(() => _function, "_function"),
|
|
569
573
|
any: /* @__PURE__ */ __name(() => any, "any"),
|
|
570
574
|
array: /* @__PURE__ */ __name(() => array, "array"),
|
|
571
|
-
base64: /* @__PURE__ */ __name(() =>
|
|
575
|
+
base64: /* @__PURE__ */ __name(() => base6422, "base64"),
|
|
572
576
|
base64url: /* @__PURE__ */ __name(() => base64url2, "base64url"),
|
|
573
577
|
bigint: /* @__PURE__ */ __name(() => bigint2, "bigint"),
|
|
574
578
|
boolean: /* @__PURE__ */ __name(() => boolean2, "boolean"),
|
|
@@ -609,7 +613,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
609
613
|
gt: /* @__PURE__ */ __name(() => _gt, "gt"),
|
|
610
614
|
gte: /* @__PURE__ */ __name(() => _gte, "gte"),
|
|
611
615
|
guid: /* @__PURE__ */ __name(() => guid2, "guid"),
|
|
612
|
-
hash: /* @__PURE__ */ __name(() =>
|
|
616
|
+
hash: /* @__PURE__ */ __name(() => hash2, "hash"),
|
|
613
617
|
hex: /* @__PURE__ */ __name(() => hex22, "hex"),
|
|
614
618
|
hostname: /* @__PURE__ */ __name(() => hostname2, "hostname"),
|
|
615
619
|
httpUrl: /* @__PURE__ */ __name(() => httpUrl, "httpUrl"),
|
|
@@ -658,7 +662,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
658
662
|
nullable: /* @__PURE__ */ __name(() => nullable, "nullable"),
|
|
659
663
|
nullish: /* @__PURE__ */ __name(() => nullish2, "nullish"),
|
|
660
664
|
number: /* @__PURE__ */ __name(() => number2, "number"),
|
|
661
|
-
object: /* @__PURE__ */ __name(() =>
|
|
665
|
+
object: /* @__PURE__ */ __name(() => object2, "object"),
|
|
662
666
|
optional: /* @__PURE__ */ __name(() => optional, "optional"),
|
|
663
667
|
overwrite: /* @__PURE__ */ __name(() => _overwrite, "overwrite"),
|
|
664
668
|
parse: /* @__PURE__ */ __name(() => parse2, "parse"),
|
|
@@ -1020,9 +1024,9 @@ var require_types_cjs_development = __commonJS({
|
|
|
1020
1024
|
inst._zod.traits.add(name);
|
|
1021
1025
|
initializer3(inst, def);
|
|
1022
1026
|
const proto = _.prototype;
|
|
1023
|
-
const
|
|
1024
|
-
for (let i = 0; i <
|
|
1025
|
-
const k =
|
|
1027
|
+
const keys2 = Object.keys(proto);
|
|
1028
|
+
for (let i = 0; i < keys2.length; i++) {
|
|
1029
|
+
const k = keys2[i];
|
|
1026
1030
|
if (!(k in inst)) {
|
|
1027
1031
|
inst[k] = proto[k].bind(inst);
|
|
1028
1032
|
}
|
|
@@ -1244,9 +1248,9 @@ var require_types_cjs_development = __commonJS({
|
|
|
1244
1248
|
__name(floatSafeRemainder, "floatSafeRemainder");
|
|
1245
1249
|
__name2(floatSafeRemainder, "floatSafeRemainder");
|
|
1246
1250
|
var EVALUATING = /* @__PURE__ */ Symbol("evaluating");
|
|
1247
|
-
function defineLazy(
|
|
1251
|
+
function defineLazy(object22, key, getter) {
|
|
1248
1252
|
let value = void 0;
|
|
1249
|
-
Object.defineProperty(
|
|
1253
|
+
Object.defineProperty(object22, key, {
|
|
1250
1254
|
get() {
|
|
1251
1255
|
if (value === EVALUATING) {
|
|
1252
1256
|
return void 0;
|
|
@@ -1258,7 +1262,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
1258
1262
|
return value;
|
|
1259
1263
|
},
|
|
1260
1264
|
set(v) {
|
|
1261
|
-
Object.defineProperty(
|
|
1265
|
+
Object.defineProperty(object22, key, {
|
|
1262
1266
|
value: v
|
|
1263
1267
|
// configurable: true,
|
|
1264
1268
|
});
|
|
@@ -1306,12 +1310,12 @@ var require_types_cjs_development = __commonJS({
|
|
|
1306
1310
|
__name(getElementAtPath, "getElementAtPath");
|
|
1307
1311
|
__name2(getElementAtPath, "getElementAtPath");
|
|
1308
1312
|
function promiseAllObject(promisesObj) {
|
|
1309
|
-
const
|
|
1310
|
-
const promises =
|
|
1313
|
+
const keys2 = Object.keys(promisesObj);
|
|
1314
|
+
const promises = keys2.map((key) => promisesObj[key]);
|
|
1311
1315
|
return Promise.all(promises).then((results) => {
|
|
1312
1316
|
const resolvedObj = {};
|
|
1313
|
-
for (let i = 0; i <
|
|
1314
|
-
resolvedObj[
|
|
1317
|
+
for (let i = 0; i < keys2.length; i++) {
|
|
1318
|
+
resolvedObj[keys2[i]] = results[i];
|
|
1315
1319
|
}
|
|
1316
1320
|
return resolvedObj;
|
|
1317
1321
|
});
|
|
@@ -1851,18 +1855,18 @@ var require_types_cjs_development = __commonJS({
|
|
|
1851
1855
|
__name2(cleanEnum, "cleanEnum");
|
|
1852
1856
|
function base64ToUint8Array(base643) {
|
|
1853
1857
|
const binaryString = atob(base643);
|
|
1854
|
-
const
|
|
1858
|
+
const bytes3 = new Uint8Array(binaryString.length);
|
|
1855
1859
|
for (let i = 0; i < binaryString.length; i++) {
|
|
1856
|
-
|
|
1860
|
+
bytes3[i] = binaryString.charCodeAt(i);
|
|
1857
1861
|
}
|
|
1858
|
-
return
|
|
1862
|
+
return bytes3;
|
|
1859
1863
|
}
|
|
1860
1864
|
__name(base64ToUint8Array, "base64ToUint8Array");
|
|
1861
1865
|
__name2(base64ToUint8Array, "base64ToUint8Array");
|
|
1862
|
-
function uint8ArrayToBase64(
|
|
1866
|
+
function uint8ArrayToBase64(bytes3) {
|
|
1863
1867
|
let binaryString = "";
|
|
1864
|
-
for (let i = 0; i <
|
|
1865
|
-
binaryString += String.fromCharCode(
|
|
1868
|
+
for (let i = 0; i < bytes3.length; i++) {
|
|
1869
|
+
binaryString += String.fromCharCode(bytes3[i]);
|
|
1866
1870
|
}
|
|
1867
1871
|
return btoa(binaryString);
|
|
1868
1872
|
}
|
|
@@ -1875,8 +1879,8 @@ var require_types_cjs_development = __commonJS({
|
|
|
1875
1879
|
}
|
|
1876
1880
|
__name(base64urlToUint8Array, "base64urlToUint8Array");
|
|
1877
1881
|
__name2(base64urlToUint8Array, "base64urlToUint8Array");
|
|
1878
|
-
function uint8ArrayToBase64url(
|
|
1879
|
-
return uint8ArrayToBase64(
|
|
1882
|
+
function uint8ArrayToBase64url(bytes3) {
|
|
1883
|
+
return uint8ArrayToBase64(bytes3).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
1880
1884
|
}
|
|
1881
1885
|
__name(uint8ArrayToBase64url, "uint8ArrayToBase64url");
|
|
1882
1886
|
__name2(uint8ArrayToBase64url, "uint8ArrayToBase64url");
|
|
@@ -1885,16 +1889,16 @@ var require_types_cjs_development = __commonJS({
|
|
|
1885
1889
|
if (cleanHex.length % 2 !== 0) {
|
|
1886
1890
|
throw new Error("Invalid hex string length");
|
|
1887
1891
|
}
|
|
1888
|
-
const
|
|
1892
|
+
const bytes3 = new Uint8Array(cleanHex.length / 2);
|
|
1889
1893
|
for (let i = 0; i < cleanHex.length; i += 2) {
|
|
1890
|
-
|
|
1894
|
+
bytes3[i / 2] = Number.parseInt(cleanHex.slice(i, i + 2), 16);
|
|
1891
1895
|
}
|
|
1892
|
-
return
|
|
1896
|
+
return bytes3;
|
|
1893
1897
|
}
|
|
1894
1898
|
__name(hexToUint8Array, "hexToUint8Array");
|
|
1895
1899
|
__name2(hexToUint8Array, "hexToUint8Array");
|
|
1896
|
-
function uint8ArrayToHex(
|
|
1897
|
-
return Array.from(
|
|
1900
|
+
function uint8ArrayToHex(bytes3) {
|
|
1901
|
+
return Array.from(bytes3).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1898
1902
|
}
|
|
1899
1903
|
__name(uint8ArrayToHex, "uint8ArrayToHex");
|
|
1900
1904
|
__name2(uint8ArrayToHex, "uint8ArrayToHex");
|
|
@@ -2143,7 +2147,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
2143
2147
|
var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync($ZodRealError);
|
|
2144
2148
|
var regexes_exports = {};
|
|
2145
2149
|
__export(regexes_exports, {
|
|
2146
|
-
base64: /* @__PURE__ */ __name(() =>
|
|
2150
|
+
base64: /* @__PURE__ */ __name(() => base642, "base64"),
|
|
2147
2151
|
base64url: /* @__PURE__ */ __name(() => base64url, "base64url"),
|
|
2148
2152
|
bigint: /* @__PURE__ */ __name(() => bigint, "bigint"),
|
|
2149
2153
|
boolean: /* @__PURE__ */ __name(() => boolean, "boolean"),
|
|
@@ -2166,7 +2170,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
2166
2170
|
html5Email: /* @__PURE__ */ __name(() => html5Email, "html5Email"),
|
|
2167
2171
|
httpProtocol: /* @__PURE__ */ __name(() => httpProtocol, "httpProtocol"),
|
|
2168
2172
|
idnEmail: /* @__PURE__ */ __name(() => idnEmail, "idnEmail"),
|
|
2169
|
-
integer: /* @__PURE__ */ __name(() =>
|
|
2173
|
+
integer: /* @__PURE__ */ __name(() => integer3, "integer"),
|
|
2170
2174
|
ipv4: /* @__PURE__ */ __name(() => ipv4, "ipv4"),
|
|
2171
2175
|
ipv6: /* @__PURE__ */ __name(() => ipv6, "ipv6"),
|
|
2172
2176
|
ksuid: /* @__PURE__ */ __name(() => ksuid, "ksuid"),
|
|
@@ -2240,7 +2244,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
2240
2244
|
}, "mac");
|
|
2241
2245
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
2242
2246
|
var cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
|
|
2243
|
-
var
|
|
2247
|
+
var base642 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
|
|
2244
2248
|
var base64url = /^[A-Za-z0-9_-]*$/;
|
|
2245
2249
|
var hostname = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/;
|
|
2246
2250
|
var domain = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
@@ -2277,7 +2281,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
2277
2281
|
return new RegExp(`^${regex}$`);
|
|
2278
2282
|
}, "string");
|
|
2279
2283
|
var bigint = /^-?\d+n?$/;
|
|
2280
|
-
var
|
|
2284
|
+
var integer3 = /^-?\d+$/;
|
|
2281
2285
|
var number = /^-?\d+(?:\.\d+)?$/;
|
|
2282
2286
|
var boolean = /^(?:true|false)$/i;
|
|
2283
2287
|
var _null = /^null$/i;
|
|
@@ -2411,7 +2415,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
2411
2415
|
bag.minimum = minimum;
|
|
2412
2416
|
bag.maximum = maximum;
|
|
2413
2417
|
if (isInt)
|
|
2414
|
-
bag.pattern =
|
|
2418
|
+
bag.pattern = integer3;
|
|
2415
2419
|
});
|
|
2416
2420
|
inst._zod.check = (payload) => {
|
|
2417
2421
|
const input = payload.value;
|
|
@@ -3251,7 +3255,7 @@ var require_types_cjs_development = __commonJS({
|
|
|
3251
3255
|
__name(isValidBase64, "isValidBase64");
|
|
3252
3256
|
__name2(isValidBase64, "isValidBase64");
|
|
3253
3257
|
var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
|
|
3254
|
-
def.pattern ?? (def.pattern =
|
|
3258
|
+
def.pattern ?? (def.pattern = base642);
|
|
3255
3259
|
$ZodStringFormat.init(inst, def);
|
|
3256
3260
|
inst._zod.bag.contentEncoding = "base64";
|
|
3257
3261
|
inst._zod.check = (payload) => {
|
|
@@ -3597,8 +3601,8 @@ var require_types_cjs_development = __commonJS({
|
|
|
3597
3601
|
__name(handlePropertyResult, "handlePropertyResult");
|
|
3598
3602
|
__name2(handlePropertyResult, "handlePropertyResult");
|
|
3599
3603
|
function normalizeDef(def) {
|
|
3600
|
-
const
|
|
3601
|
-
for (const k of
|
|
3604
|
+
const keys2 = Object.keys(def.shape);
|
|
3605
|
+
for (const k of keys2) {
|
|
3602
3606
|
if (!def.shape?.[k]?._zod?.traits?.has("$ZodType")) {
|
|
3603
3607
|
throw new Error(`Invalid element at key "${k}": expected a Zod schema`);
|
|
3604
3608
|
}
|
|
@@ -3606,9 +3610,9 @@ var require_types_cjs_development = __commonJS({
|
|
|
3606
3610
|
const okeys = optionalKeys(def.shape);
|
|
3607
3611
|
return {
|
|
3608
3612
|
...def,
|
|
3609
|
-
keys,
|
|
3610
|
-
keySet: new Set(
|
|
3611
|
-
numKeys:
|
|
3613
|
+
keys: keys2,
|
|
3614
|
+
keySet: new Set(keys2),
|
|
3615
|
+
numKeys: keys2.length,
|
|
3612
3616
|
optionalKeys: new Set(okeys)
|
|
3613
3617
|
};
|
|
3614
3618
|
}
|
|
@@ -8370,8 +8374,8 @@ var require_types_cjs_development = __commonJS({
|
|
|
8370
8374
|
}
|
|
8371
8375
|
__name(ko_default, "ko_default");
|
|
8372
8376
|
__name2(ko_default, "default");
|
|
8373
|
-
var capitalizeFirstCharacter = /* @__PURE__ */ __name2((
|
|
8374
|
-
return
|
|
8377
|
+
var capitalizeFirstCharacter = /* @__PURE__ */ __name2((text2) => {
|
|
8378
|
+
return text2.charAt(0).toUpperCase() + text2.slice(1);
|
|
8375
8379
|
}, "capitalizeFirstCharacter");
|
|
8376
8380
|
function getUnitTypeFromNumber(number4) {
|
|
8377
8381
|
const abs = Math.abs(number4);
|
|
@@ -13491,7 +13495,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
13491
13495
|
_function: /* @__PURE__ */ __name(() => _function, "_function"),
|
|
13492
13496
|
any: /* @__PURE__ */ __name(() => any, "any"),
|
|
13493
13497
|
array: /* @__PURE__ */ __name(() => array, "array"),
|
|
13494
|
-
base64: /* @__PURE__ */ __name(() =>
|
|
13498
|
+
base64: /* @__PURE__ */ __name(() => base6422, "base64"),
|
|
13495
13499
|
base64url: /* @__PURE__ */ __name(() => base64url2, "base64url"),
|
|
13496
13500
|
bigint: /* @__PURE__ */ __name(() => bigint2, "bigint"),
|
|
13497
13501
|
boolean: /* @__PURE__ */ __name(() => boolean2, "boolean"),
|
|
@@ -13516,7 +13520,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
13516
13520
|
float64: /* @__PURE__ */ __name(() => float64, "float64"),
|
|
13517
13521
|
function: /* @__PURE__ */ __name(() => _function, "function"),
|
|
13518
13522
|
guid: /* @__PURE__ */ __name(() => guid2, "guid"),
|
|
13519
|
-
hash: /* @__PURE__ */ __name(() =>
|
|
13523
|
+
hash: /* @__PURE__ */ __name(() => hash2, "hash"),
|
|
13520
13524
|
hex: /* @__PURE__ */ __name(() => hex22, "hex"),
|
|
13521
13525
|
hostname: /* @__PURE__ */ __name(() => hostname2, "hostname"),
|
|
13522
13526
|
httpUrl: /* @__PURE__ */ __name(() => httpUrl, "httpUrl"),
|
|
@@ -13548,7 +13552,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
13548
13552
|
nullable: /* @__PURE__ */ __name(() => nullable, "nullable"),
|
|
13549
13553
|
nullish: /* @__PURE__ */ __name(() => nullish2, "nullish"),
|
|
13550
13554
|
number: /* @__PURE__ */ __name(() => number2, "number"),
|
|
13551
|
-
object: /* @__PURE__ */ __name(() =>
|
|
13555
|
+
object: /* @__PURE__ */ __name(() => object2, "object"),
|
|
13552
13556
|
optional: /* @__PURE__ */ __name(() => optional, "optional"),
|
|
13553
13557
|
partialRecord: /* @__PURE__ */ __name(() => partialRecord, "partialRecord"),
|
|
13554
13558
|
pipe: /* @__PURE__ */ __name(() => pipe, "pipe"),
|
|
@@ -14149,11 +14153,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14149
14153
|
$ZodBase64.init(inst, def);
|
|
14150
14154
|
ZodStringFormat.init(inst, def);
|
|
14151
14155
|
});
|
|
14152
|
-
function
|
|
14156
|
+
function base6422(params) {
|
|
14153
14157
|
return /* @__PURE__ */ _base64(ZodBase64, params);
|
|
14154
14158
|
}
|
|
14155
|
-
__name(
|
|
14156
|
-
__name2(
|
|
14159
|
+
__name(base6422, "base642");
|
|
14160
|
+
__name2(base6422, "base64");
|
|
14157
14161
|
var ZodBase64URL = /* @__PURE__ */ $constructor("ZodBase64URL", (inst, def) => {
|
|
14158
14162
|
$ZodBase64URL.init(inst, def);
|
|
14159
14163
|
ZodStringFormat.init(inst, def);
|
|
@@ -14200,7 +14204,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14200
14204
|
}
|
|
14201
14205
|
__name(hex22, "hex2");
|
|
14202
14206
|
__name2(hex22, "hex");
|
|
14203
|
-
function
|
|
14207
|
+
function hash2(alg, params) {
|
|
14204
14208
|
const enc = params?.enc ?? "hex";
|
|
14205
14209
|
const format = `${alg}_${enc}`;
|
|
14206
14210
|
const regex = regexes_exports[format];
|
|
@@ -14208,8 +14212,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14208
14212
|
throw new Error(`Unrecognized hash format: ${format}`);
|
|
14209
14213
|
return /* @__PURE__ */ _stringFormat(ZodCustomStringFormat, format, regex, params);
|
|
14210
14214
|
}
|
|
14211
|
-
__name(
|
|
14212
|
-
__name2(
|
|
14215
|
+
__name(hash2, "hash");
|
|
14216
|
+
__name2(hash2, "hash");
|
|
14213
14217
|
var ZodNumber = /* @__PURE__ */ $constructor("ZodNumber", (inst, def) => {
|
|
14214
14218
|
$ZodNumber.init(inst, def);
|
|
14215
14219
|
ZodType.init(inst, def);
|
|
@@ -14521,7 +14525,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14521
14525
|
}
|
|
14522
14526
|
});
|
|
14523
14527
|
});
|
|
14524
|
-
function
|
|
14528
|
+
function object2(shape, params) {
|
|
14525
14529
|
const def = {
|
|
14526
14530
|
type: "object",
|
|
14527
14531
|
shape: shape ?? {},
|
|
@@ -14529,8 +14533,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14529
14533
|
};
|
|
14530
14534
|
return new ZodObject(def);
|
|
14531
14535
|
}
|
|
14532
|
-
__name(
|
|
14533
|
-
__name2(
|
|
14536
|
+
__name(object2, "object");
|
|
14537
|
+
__name2(object2, "object");
|
|
14534
14538
|
function strictObject(shape, params) {
|
|
14535
14539
|
return new ZodObject({
|
|
14536
14540
|
type: "object",
|
|
@@ -14725,11 +14729,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14725
14729
|
inst._zod.processJSONSchema = (ctx, json2, params) => enumProcessor(inst, ctx, json2, params);
|
|
14726
14730
|
inst.enum = def.entries;
|
|
14727
14731
|
inst.options = Object.values(def.entries);
|
|
14728
|
-
const
|
|
14732
|
+
const keys2 = new Set(Object.keys(def.entries));
|
|
14729
14733
|
inst.extract = (values, params) => {
|
|
14730
14734
|
const newEntries = {};
|
|
14731
14735
|
for (const value of values) {
|
|
14732
|
-
if (
|
|
14736
|
+
if (keys2.has(value)) {
|
|
14733
14737
|
newEntries[value] = def.entries[value];
|
|
14734
14738
|
} else
|
|
14735
14739
|
throw new Error(`Key ${value} not found in enum`);
|
|
@@ -14744,7 +14748,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14744
14748
|
inst.exclude = (values, params) => {
|
|
14745
14749
|
const newEntries = { ...def.entries };
|
|
14746
14750
|
for (const value of values) {
|
|
14747
|
-
if (
|
|
14751
|
+
if (keys2.has(value)) {
|
|
14748
14752
|
delete newEntries[value];
|
|
14749
14753
|
} else
|
|
14750
14754
|
throw new Error(`Key ${value} not found in enum`);
|
|
@@ -15880,7 +15884,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15880
15884
|
verificationMethod: external_exports.string(),
|
|
15881
15885
|
jws: external_exports.string().optional()
|
|
15882
15886
|
}).catchall(external_exports.any()).superRefine((proof, ctx) => {
|
|
15883
|
-
if (proof.created === void 0 &&
|
|
15887
|
+
if (proof.created === void 0 && // These standardized Data Integrity suites make created optional.
|
|
15888
|
+
// Keep the prior requirement for legacy and unknown proof suites.
|
|
15889
|
+
// https://www.w3.org/TR/vc-di-eddsa/#proof-configuration-eddsa-jcs-2022
|
|
15890
|
+
// https://www.w3.org/TR/vc-di-bbs/#proof-configuration
|
|
15891
|
+
(proof.type !== "DataIntegrityProof" || ![
|
|
15892
|
+
"ecdsa-rdfc-2019",
|
|
15893
|
+
"ecdsa-jcs-2019",
|
|
15894
|
+
"ecdsa-sd-2023",
|
|
15895
|
+
"eddsa-rdfc-2022",
|
|
15896
|
+
"eddsa-jcs-2022",
|
|
15897
|
+
"bbs-2023"
|
|
15898
|
+
].includes(proof.cryptosuite))) {
|
|
15884
15899
|
ctx.addIssue({
|
|
15885
15900
|
code: "custom",
|
|
15886
15901
|
path: ["created"],
|
|
@@ -16137,6 +16152,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16137
16152
|
term: external_exports.string().optional()
|
|
16138
16153
|
}).catchall(external_exports.any());
|
|
16139
16154
|
var UnsignedAchievementCredentialValidator = UnsignedVCValidator.extend({
|
|
16155
|
+
awardedDate: external_exports.string().optional(),
|
|
16140
16156
|
name: external_exports.string().optional(),
|
|
16141
16157
|
description: external_exports.string().optional(),
|
|
16142
16158
|
image: ImageValidator.optional(),
|
|
@@ -18519,12 +18535,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18519
18535
|
}
|
|
18520
18536
|
return table;
|
|
18521
18537
|
})();
|
|
18522
|
-
var encodeBase64Url = /* @__PURE__ */ __name2((
|
|
18538
|
+
var encodeBase64Url = /* @__PURE__ */ __name2((bytes3) => {
|
|
18523
18539
|
let output = "";
|
|
18524
|
-
for (let index = 0; index <
|
|
18525
|
-
const first =
|
|
18526
|
-
const second =
|
|
18527
|
-
const third =
|
|
18540
|
+
for (let index = 0; index < bytes3.length; index += 3) {
|
|
18541
|
+
const first = bytes3[index];
|
|
18542
|
+
const second = bytes3[index + 1];
|
|
18543
|
+
const third = bytes3[index + 2];
|
|
18528
18544
|
output += BASE64URL_ALPHABET[first >> 2];
|
|
18529
18545
|
output += BASE64URL_ALPHABET[(first & 3) << 4 | (second ?? 0) >> 4];
|
|
18530
18546
|
if (second === void 0) break;
|
|
@@ -18565,8 +18581,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18565
18581
|
}, "isCanonicalBase64Url");
|
|
18566
18582
|
var decodedBase64UrlByteLength = /* @__PURE__ */ __name2((value) => decodeBase64Url(value)?.length ?? null, "decodedBase64UrlByteLength");
|
|
18567
18583
|
var utf8ByteLength = /* @__PURE__ */ __name2((value) => new TextEncoder().encode(value).length, "utf8ByteLength");
|
|
18568
|
-
var canonicalBase64Url = /* @__PURE__ */ __name2((
|
|
18569
|
-
message: `must be canonical base64url for exactly ${
|
|
18584
|
+
var canonicalBase64Url = /* @__PURE__ */ __name2((bytes3) => external_exports.string().refine((value) => isCanonicalBase64Url(value, bytes3), {
|
|
18585
|
+
message: `must be canonical base64url for exactly ${bytes3} bytes`
|
|
18570
18586
|
}), "canonicalBase64Url");
|
|
18571
18587
|
var ShareLinkIdValidator = canonicalBase64Url(SHARE_LINK_ID_BYTES);
|
|
18572
18588
|
var ShareContentKeyValidator = canonicalBase64Url(SHARE_CONTENT_KEY_BYTES);
|
|
@@ -18993,6 +19009,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18993
19009
|
contentUrl: external_exports.string(),
|
|
18994
19010
|
receipt: external_exports.string().min(22).max(128).regex(/^[A-Za-z0-9_-]+$/)
|
|
18995
19011
|
}).strict();
|
|
19012
|
+
var SKILL_ICON_MAX_NAMES_PER_REQUEST = 100;
|
|
19013
|
+
var SKILL_ICON_MAX_CHARACTERS_PER_REQUEST = 2500;
|
|
19014
|
+
var SkillIconNamesValidator = external_exports.array(external_exports.string().nonempty()).min(1).max(SKILL_ICON_MAX_NAMES_PER_REQUEST, {
|
|
19015
|
+
message: `A maximum of ${SKILL_ICON_MAX_NAMES_PER_REQUEST} skill names can be sent per request`
|
|
19016
|
+
}).refine(
|
|
19017
|
+
(names) => names.reduce((total, name) => total + name.length, 0) <= SKILL_ICON_MAX_CHARACTERS_PER_REQUEST,
|
|
19018
|
+
{
|
|
19019
|
+
message: `Skill names may total at most ${SKILL_ICON_MAX_CHARACTERS_PER_REQUEST} characters per request`
|
|
19020
|
+
}
|
|
19021
|
+
);
|
|
19022
|
+
var GenerateSkillIconsInputValidator = external_exports.object({ names: SkillIconNamesValidator });
|
|
18996
19023
|
}
|
|
18997
19024
|
});
|
|
18998
19025
|
|
|
@@ -19165,37 +19192,37 @@ var DEFAULT_KDF_PARAMS = {
|
|
|
19165
19192
|
parallelism: ARGON2_PARALLELISM
|
|
19166
19193
|
};
|
|
19167
19194
|
function bufferToBase64(buf) {
|
|
19168
|
-
const
|
|
19195
|
+
const bytes3 = new Uint8Array(buf);
|
|
19169
19196
|
let binary = "";
|
|
19170
|
-
for (let i = 0; i <
|
|
19171
|
-
binary += String.fromCharCode(
|
|
19197
|
+
for (let i = 0; i < bytes3.byteLength; i++) {
|
|
19198
|
+
binary += String.fromCharCode(bytes3[i]);
|
|
19172
19199
|
}
|
|
19173
19200
|
return btoa(binary);
|
|
19174
19201
|
}
|
|
19175
19202
|
__name(bufferToBase64, "bufferToBase64");
|
|
19176
19203
|
function base64ToBuffer(b64) {
|
|
19177
19204
|
const binary = atob(b64);
|
|
19178
|
-
const
|
|
19205
|
+
const bytes3 = new Uint8Array(binary.length);
|
|
19179
19206
|
for (let i = 0; i < binary.length; i++) {
|
|
19180
|
-
|
|
19207
|
+
bytes3[i] = binary.charCodeAt(i);
|
|
19181
19208
|
}
|
|
19182
|
-
return
|
|
19209
|
+
return bytes3;
|
|
19183
19210
|
}
|
|
19184
19211
|
__name(base64ToBuffer, "base64ToBuffer");
|
|
19185
19212
|
function hexToBytes(hex2) {
|
|
19186
|
-
const
|
|
19213
|
+
const bytes3 = new Uint8Array(hex2.length / 2);
|
|
19187
19214
|
for (let i = 0; i < hex2.length; i += 2) {
|
|
19188
|
-
|
|
19215
|
+
bytes3[i / 2] = parseInt(hex2.slice(i, i + 2), 16);
|
|
19189
19216
|
}
|
|
19190
|
-
return
|
|
19217
|
+
return bytes3;
|
|
19191
19218
|
}
|
|
19192
19219
|
__name(hexToBytes, "hexToBytes");
|
|
19193
|
-
function bytesToHex(
|
|
19194
|
-
return Array.from(
|
|
19220
|
+
function bytesToHex(bytes3) {
|
|
19221
|
+
return Array.from(bytes3).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
19195
19222
|
}
|
|
19196
19223
|
__name(bytesToHex, "bytesToHex");
|
|
19197
19224
|
async function deriveKeyFromPassword(password, salt, params = DEFAULT_KDF_PARAMS) {
|
|
19198
|
-
const
|
|
19225
|
+
const hash2 = await argon2id({
|
|
19199
19226
|
password,
|
|
19200
19227
|
salt,
|
|
19201
19228
|
iterations: params.timeCost,
|
|
@@ -19204,7 +19231,7 @@ async function deriveKeyFromPassword(password, salt, params = DEFAULT_KDF_PARAMS
|
|
|
19204
19231
|
hashLength: ARGON2_HASH_LENGTH,
|
|
19205
19232
|
outputType: "binary"
|
|
19206
19233
|
});
|
|
19207
|
-
return Uint8Array.from(
|
|
19234
|
+
return Uint8Array.from(hash2);
|
|
19208
19235
|
}
|
|
19209
19236
|
__name(deriveKeyFromPassword, "deriveKeyFromPassword");
|
|
19210
19237
|
async function encryptWithPassword(plaintext, password) {
|
|
@@ -19358,21 +19385,21 @@ async function getOrCreateMasterKey() {
|
|
|
19358
19385
|
}
|
|
19359
19386
|
__name(getOrCreateMasterKey, "getOrCreateMasterKey");
|
|
19360
19387
|
function bufferToBase642(buf) {
|
|
19361
|
-
const
|
|
19388
|
+
const bytes3 = new Uint8Array(buf);
|
|
19362
19389
|
let binary = "";
|
|
19363
|
-
for (let i = 0; i <
|
|
19364
|
-
binary += String.fromCharCode(
|
|
19390
|
+
for (let i = 0; i < bytes3.byteLength; i++) {
|
|
19391
|
+
binary += String.fromCharCode(bytes3[i]);
|
|
19365
19392
|
}
|
|
19366
19393
|
return btoa(binary);
|
|
19367
19394
|
}
|
|
19368
19395
|
__name(bufferToBase642, "bufferToBase64");
|
|
19369
19396
|
function base64ToBuffer2(b64) {
|
|
19370
19397
|
const binary = atob(b64);
|
|
19371
|
-
const
|
|
19398
|
+
const bytes3 = new Uint8Array(binary.length);
|
|
19372
19399
|
for (let i = 0; i < binary.length; i++) {
|
|
19373
|
-
|
|
19400
|
+
bytes3[i] = binary.charCodeAt(i);
|
|
19374
19401
|
}
|
|
19375
|
-
return
|
|
19402
|
+
return bytes3.buffer;
|
|
19376
19403
|
}
|
|
19377
19404
|
__name(base64ToBuffer2, "base64ToBuffer");
|
|
19378
19405
|
async function encryptShare(share, id) {
|
|
@@ -19780,21 +19807,21 @@ async function getWordlist() {
|
|
|
19780
19807
|
return wordlistPromise;
|
|
19781
19808
|
}
|
|
19782
19809
|
__name(getWordlist, "getWordlist");
|
|
19783
|
-
function bytesToBits(
|
|
19784
|
-
return Array.from(
|
|
19810
|
+
function bytesToBits(bytes3) {
|
|
19811
|
+
return Array.from(bytes3).map((b) => b.toString(2).padStart(8, "0")).join("");
|
|
19785
19812
|
}
|
|
19786
19813
|
__name(bytesToBits, "bytesToBits");
|
|
19787
19814
|
function bitsToBytes(bits) {
|
|
19788
|
-
const
|
|
19789
|
-
for (let i = 0; i <
|
|
19790
|
-
|
|
19815
|
+
const bytes3 = new Uint8Array(Math.ceil(bits.length / 8));
|
|
19816
|
+
for (let i = 0; i < bytes3.length; i++) {
|
|
19817
|
+
bytes3[i] = parseInt(bits.slice(i * 8, (i + 1) * 8).padEnd(8, "0"), 2);
|
|
19791
19818
|
}
|
|
19792
|
-
return
|
|
19819
|
+
return bytes3;
|
|
19793
19820
|
}
|
|
19794
19821
|
__name(bitsToBytes, "bitsToBytes");
|
|
19795
19822
|
async function computeChecksum(data) {
|
|
19796
|
-
const
|
|
19797
|
-
const hashBits = bytesToBits(new Uint8Array(
|
|
19823
|
+
const hash2 = await crypto.subtle.digest("SHA-256", data);
|
|
19824
|
+
const hashBits = bytesToBits(new Uint8Array(hash2));
|
|
19798
19825
|
const checksumLength = Math.floor(data.length / 4);
|
|
19799
19826
|
return hashBits.slice(0, checksumLength);
|
|
19800
19827
|
}
|
|
@@ -19827,12 +19854,12 @@ async function recoveryPhraseToShare(phrase) {
|
|
|
19827
19854
|
bits += index.toString(2).padStart(11, "0");
|
|
19828
19855
|
}
|
|
19829
19856
|
let dataByteCount = 0;
|
|
19830
|
-
for (let
|
|
19831
|
-
const checksumBits2 = Math.floor(
|
|
19832
|
-
const totalBits =
|
|
19857
|
+
for (let bytes3 = 1; bytes3 <= 64; bytes3++) {
|
|
19858
|
+
const checksumBits2 = Math.floor(bytes3 / 4);
|
|
19859
|
+
const totalBits = bytes3 * 8 + checksumBits2;
|
|
19833
19860
|
const wordsNeeded = Math.ceil(totalBits / 11);
|
|
19834
19861
|
if (wordsNeeded === words.length) {
|
|
19835
|
-
dataByteCount =
|
|
19862
|
+
dataByteCount = bytes3;
|
|
19836
19863
|
} else if (wordsNeeded > words.length) {
|
|
19837
19864
|
break;
|
|
19838
19865
|
}
|
|
@@ -20126,9 +20153,9 @@ __name(createSSSKeyManager, "createSSSKeyManager");
|
|
|
20126
20153
|
var EMAIL_RELAY_ENVELOPE_VERSION = 1;
|
|
20127
20154
|
var EMAIL_RELAY_ALGORITHM = "P-256-HKDF-SHA256-AES-256-GCM";
|
|
20128
20155
|
var encodeUtf8 = /* @__PURE__ */ __name((value) => {
|
|
20129
|
-
const
|
|
20130
|
-
const copy = new Uint8Array(new ArrayBuffer(
|
|
20131
|
-
copy.set(
|
|
20156
|
+
const bytes3 = new TextEncoder().encode(value);
|
|
20157
|
+
const copy = new Uint8Array(new ArrayBuffer(bytes3.byteLength));
|
|
20158
|
+
copy.set(bytes3);
|
|
20132
20159
|
return copy;
|
|
20133
20160
|
}, "encodeUtf8");
|
|
20134
20161
|
var EMAIL_RELAY_INFO = encodeUtf8("learncard-email-relay-v1");
|
|
@@ -20147,7 +20174,7 @@ var parseBranding = /* @__PURE__ */ __name((value) => {
|
|
|
20147
20174
|
if (value === void 0) return void 0;
|
|
20148
20175
|
if (!isRecord(value)) throw new Error("Invalid email relay branding");
|
|
20149
20176
|
const branding = {};
|
|
20150
|
-
const
|
|
20177
|
+
const keys2 = [
|
|
20151
20178
|
"brandName",
|
|
20152
20179
|
"logoUrl",
|
|
20153
20180
|
"logoAlt",
|
|
@@ -20159,7 +20186,7 @@ var parseBranding = /* @__PURE__ */ __name((value) => {
|
|
|
20159
20186
|
"fromDomain",
|
|
20160
20187
|
"copyrightHolder"
|
|
20161
20188
|
];
|
|
20162
|
-
for (const key of
|
|
20189
|
+
for (const key of keys2) {
|
|
20163
20190
|
const field = value[key];
|
|
20164
20191
|
if (field === void 0) continue;
|
|
20165
20192
|
if (typeof field !== "string" || field.length > 2048) {
|
|
@@ -20212,7 +20239,7 @@ var parseEmailRelayPlaintext = /* @__PURE__ */ __name((value) => {
|
|
|
20212
20239
|
branding: parseBranding(value.branding)
|
|
20213
20240
|
};
|
|
20214
20241
|
}, "parseEmailRelayPlaintext");
|
|
20215
|
-
var getAad = /* @__PURE__ */ __name((
|
|
20242
|
+
var getAad = /* @__PURE__ */ __name((envelope2) => encodeUtf8(`${envelope2.version}|${envelope2.algorithm}|${envelope2.keyId}`), "getAad");
|
|
20216
20243
|
var deriveAesKey = /* @__PURE__ */ __name(async (sharedSecret, salt, usage) => {
|
|
20217
20244
|
const keyMaterial = await crypto.subtle.importKey("raw", sharedSecret, "HKDF", false, [
|
|
20218
20245
|
"deriveKey"
|
|
@@ -20284,7 +20311,7 @@ var encryptEmailRelayPayload = /* @__PURE__ */ __name(async (input, publicKeyBas
|
|
|
20284
20311
|
};
|
|
20285
20312
|
}, "encryptEmailRelayPayload");
|
|
20286
20313
|
var decryptEmailRelayPayload = /* @__PURE__ */ __name(async (value, privateKeyBase64) => {
|
|
20287
|
-
const
|
|
20314
|
+
const envelope2 = parseEmailRelayEnvelope(value);
|
|
20288
20315
|
const privateKey = await crypto.subtle.importKey(
|
|
20289
20316
|
"pkcs8",
|
|
20290
20317
|
base64ToBuffer(privateKeyBase64.trim()).buffer,
|
|
@@ -20294,7 +20321,7 @@ var decryptEmailRelayPayload = /* @__PURE__ */ __name(async (value, privateKeyBa
|
|
|
20294
20321
|
);
|
|
20295
20322
|
const ephemeralPublicKey = await crypto.subtle.importKey(
|
|
20296
20323
|
"raw",
|
|
20297
|
-
base64ToBuffer(
|
|
20324
|
+
base64ToBuffer(envelope2.ephemeralPublicKey).buffer,
|
|
20298
20325
|
{ name: "ECDH", namedCurve: "P-256" },
|
|
20299
20326
|
false,
|
|
20300
20327
|
[]
|
|
@@ -20304,13 +20331,13 @@ var decryptEmailRelayPayload = /* @__PURE__ */ __name(async (value, privateKeyBa
|
|
|
20304
20331
|
privateKey,
|
|
20305
20332
|
256
|
|
20306
20333
|
);
|
|
20307
|
-
const salt = base64ToBuffer(
|
|
20308
|
-
const iv = base64ToBuffer(
|
|
20334
|
+
const salt = base64ToBuffer(envelope2.salt);
|
|
20335
|
+
const iv = base64ToBuffer(envelope2.iv);
|
|
20309
20336
|
const aesKey = await deriveAesKey(sharedSecret, salt, "decrypt");
|
|
20310
20337
|
const decrypted = await crypto.subtle.decrypt(
|
|
20311
|
-
{ name: "AES-GCM", iv, additionalData: getAad(
|
|
20338
|
+
{ name: "AES-GCM", iv, additionalData: getAad(envelope2) },
|
|
20312
20339
|
aesKey,
|
|
20313
|
-
base64ToBuffer(
|
|
20340
|
+
base64ToBuffer(envelope2.ciphertext)
|
|
20314
20341
|
);
|
|
20315
20342
|
const parsed = JSON.parse(new TextDecoder().decode(decrypted));
|
|
20316
20343
|
return parseEmailRelayPlaintext(parsed);
|
|
@@ -20322,10 +20349,11 @@ var ESCROW_ALGORITHM = "P-256-HKDF-SHA256-AES-256-GCM";
|
|
|
20322
20349
|
var ESCROW_BLOB_INFO = "learncard-escrow-blob-v1";
|
|
20323
20350
|
var ESCROW_RELEASE_INFO = "learncard-escrow-release-v1";
|
|
20324
20351
|
var ESCROW_CLIENT_KEY_ID = "client";
|
|
20352
|
+
var RECOVERY_LANGUAGES = ["en", "es", "fr", "ar"];
|
|
20325
20353
|
var encodeUtf82 = /* @__PURE__ */ __name((value) => {
|
|
20326
|
-
const
|
|
20327
|
-
const copy = new Uint8Array(new ArrayBuffer(
|
|
20328
|
-
copy.set(
|
|
20354
|
+
const bytes3 = new TextEncoder().encode(value);
|
|
20355
|
+
const copy = new Uint8Array(new ArrayBuffer(bytes3.byteLength));
|
|
20356
|
+
copy.set(bytes3);
|
|
20329
20357
|
return copy;
|
|
20330
20358
|
}, "encodeUtf8");
|
|
20331
20359
|
var isRecord2 = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isRecord");
|
|
@@ -20361,6 +20389,22 @@ var parseEscrowBlobPlaintext = /* @__PURE__ */ __name((value) => {
|
|
|
20361
20389
|
if (typeof value.shareVersion !== "number" || !Number.isInteger(value.shareVersion) || value.shareVersion <= 0) {
|
|
20362
20390
|
throw new Error("Invalid escrow shareVersion");
|
|
20363
20391
|
}
|
|
20392
|
+
if (value.recoveryEmail !== void 0 !== (value.recoveryLanguage !== void 0)) {
|
|
20393
|
+
throw new Error("Invalid escrow recoveryEmail");
|
|
20394
|
+
}
|
|
20395
|
+
let recoveryContact = {};
|
|
20396
|
+
if (value.recoveryEmail !== void 0) {
|
|
20397
|
+
const email = requireString2(value, "recoveryEmail", { min: 3, max: 254 }).trim().toLowerCase();
|
|
20398
|
+
const at = email.split("@");
|
|
20399
|
+
if (!/^[\x21-\x7e]+$/.test(email) || at.length !== 2 || at[0].length === 0 || at[1].length === 0 || !at[1].includes(".") || at[1].startsWith(".") || at[1].endsWith(".")) {
|
|
20400
|
+
throw new Error("Invalid escrow recoveryEmail");
|
|
20401
|
+
}
|
|
20402
|
+
const language = requireString2(value, "recoveryLanguage", { min: 2, max: 2 });
|
|
20403
|
+
if (!RECOVERY_LANGUAGES.includes(language)) {
|
|
20404
|
+
throw new Error("Invalid escrow recoveryLanguage");
|
|
20405
|
+
}
|
|
20406
|
+
recoveryContact = { recoveryEmail: email, recoveryLanguage: language };
|
|
20407
|
+
}
|
|
20364
20408
|
return {
|
|
20365
20409
|
version: ESCROW_ENVELOPE_VERSION,
|
|
20366
20410
|
recoveryShare: requireString2(value, "recoveryShare", {
|
|
@@ -20376,7 +20420,8 @@ var parseEscrowBlobPlaintext = /* @__PURE__ */ __name((value) => {
|
|
|
20376
20420
|
max: 64,
|
|
20377
20421
|
pattern: /^[0-9a-f]{64}$/i
|
|
20378
20422
|
}).toLowerCase()
|
|
20379
|
-
} : {}
|
|
20423
|
+
} : {},
|
|
20424
|
+
...recoveryContact
|
|
20380
20425
|
};
|
|
20381
20426
|
}, "parseEscrowBlobPlaintext");
|
|
20382
20427
|
var parseEscrowReleasePlaintext = /* @__PURE__ */ __name((value) => {
|
|
@@ -20387,7 +20432,7 @@ var parseEscrowReleasePlaintext = /* @__PURE__ */ __name((value) => {
|
|
|
20387
20432
|
holdId: requireString2(value, "holdId", { max: 128, pattern: /^[A-Za-z0-9._-]+$/ })
|
|
20388
20433
|
};
|
|
20389
20434
|
}, "parseEscrowReleasePlaintext");
|
|
20390
|
-
var getAad2 = /* @__PURE__ */ __name((
|
|
20435
|
+
var getAad2 = /* @__PURE__ */ __name((envelope2) => encodeUtf82(`${envelope2.version}|${envelope2.algorithm}|${envelope2.keyId}`), "getAad");
|
|
20391
20436
|
var deriveAesKey2 = /* @__PURE__ */ __name(async (sharedSecret, salt, usage, info) => {
|
|
20392
20437
|
const keyMaterial = await crypto.subtle.importKey("raw", sharedSecret, "HKDF", false, [
|
|
20393
20438
|
"deriveKey"
|
|
@@ -20458,7 +20503,7 @@ var encryptToRecipient = /* @__PURE__ */ __name(async (plaintextJson, spki, keyI
|
|
|
20458
20503
|
};
|
|
20459
20504
|
}, "encryptToRecipient");
|
|
20460
20505
|
var decryptFromEnvelope = /* @__PURE__ */ __name(async (value, pkcs8, info) => {
|
|
20461
|
-
const
|
|
20506
|
+
const envelope2 = parseEscrowEnvelope(value);
|
|
20462
20507
|
const privateKey = await crypto.subtle.importKey(
|
|
20463
20508
|
"pkcs8",
|
|
20464
20509
|
base64ToBuffer(pkcs8.trim()),
|
|
@@ -20468,7 +20513,7 @@ var decryptFromEnvelope = /* @__PURE__ */ __name(async (value, pkcs8, info) => {
|
|
|
20468
20513
|
);
|
|
20469
20514
|
const ephemeralPublicKey = await crypto.subtle.importKey(
|
|
20470
20515
|
"raw",
|
|
20471
|
-
base64ToBuffer(
|
|
20516
|
+
base64ToBuffer(envelope2.ephemeralPublicKey),
|
|
20472
20517
|
{ name: "ECDH", namedCurve: "P-256" },
|
|
20473
20518
|
false,
|
|
20474
20519
|
[]
|
|
@@ -20478,13 +20523,13 @@ var decryptFromEnvelope = /* @__PURE__ */ __name(async (value, pkcs8, info) => {
|
|
|
20478
20523
|
privateKey,
|
|
20479
20524
|
256
|
|
20480
20525
|
);
|
|
20481
|
-
const salt = base64ToBuffer(
|
|
20482
|
-
const iv = base64ToBuffer(
|
|
20526
|
+
const salt = base64ToBuffer(envelope2.salt);
|
|
20527
|
+
const iv = base64ToBuffer(envelope2.iv);
|
|
20483
20528
|
const aesKey = await deriveAesKey2(sharedSecret, salt, "decrypt", info);
|
|
20484
20529
|
const decrypted = await crypto.subtle.decrypt(
|
|
20485
|
-
{ name: "AES-GCM", iv, additionalData: getAad2(
|
|
20530
|
+
{ name: "AES-GCM", iv, additionalData: getAad2(envelope2) },
|
|
20486
20531
|
aesKey,
|
|
20487
|
-
base64ToBuffer(
|
|
20532
|
+
base64ToBuffer(envelope2.ciphertext)
|
|
20488
20533
|
);
|
|
20489
20534
|
const parsed = JSON.parse(new TextDecoder().decode(decrypted));
|
|
20490
20535
|
return parsed;
|
|
@@ -20498,8 +20543,8 @@ var encryptEscrowBlob = /* @__PURE__ */ __name(async (input, enclavePublicKeySpk
|
|
|
20498
20543
|
ESCROW_BLOB_INFO
|
|
20499
20544
|
);
|
|
20500
20545
|
}, "encryptEscrowBlob");
|
|
20501
|
-
var decryptEscrowBlob = /* @__PURE__ */ __name(async (
|
|
20502
|
-
await decryptFromEnvelope(
|
|
20546
|
+
var decryptEscrowBlob = /* @__PURE__ */ __name(async (envelope2, enclavePrivateKeyPkcs8B64) => parseEscrowBlobPlaintext(
|
|
20547
|
+
await decryptFromEnvelope(envelope2, enclavePrivateKeyPkcs8B64, ESCROW_BLOB_INFO)
|
|
20503
20548
|
), "decryptEscrowBlob");
|
|
20504
20549
|
var sealEscrowRelease = /* @__PURE__ */ __name(async (input, clientEphemeralPublicKeySpkiB64) => {
|
|
20505
20550
|
const plaintext = parseEscrowReleasePlaintext({ ...input, version: ESCROW_ENVELOPE_VERSION });
|
|
@@ -20510,10 +20555,196 @@ var sealEscrowRelease = /* @__PURE__ */ __name(async (input, clientEphemeralPubl
|
|
|
20510
20555
|
ESCROW_RELEASE_INFO
|
|
20511
20556
|
);
|
|
20512
20557
|
}, "sealEscrowRelease");
|
|
20513
|
-
var openEscrowRelease = /* @__PURE__ */ __name(async (
|
|
20514
|
-
await decryptFromEnvelope(
|
|
20558
|
+
var openEscrowRelease = /* @__PURE__ */ __name(async (envelope2, clientEphemeralPrivateKeyPkcs8B64) => parseEscrowReleasePlaintext(
|
|
20559
|
+
await decryptFromEnvelope(envelope2, clientEphemeralPrivateKeyPkcs8B64, ESCROW_RELEASE_INFO)
|
|
20515
20560
|
), "openEscrowRelease");
|
|
20516
20561
|
|
|
20562
|
+
// src/escrow-enrollment-intent.ts
|
|
20563
|
+
import { ExtendedPoint, getPublicKeyAsync, signAsync } from "@noble/ed25519";
|
|
20564
|
+
var ESCROW_ENROLLMENT_INTENT_DOMAIN = "learncard-escrow-enrollment-intent-v2\0";
|
|
20565
|
+
var BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
20566
|
+
var FIELDS = [
|
|
20567
|
+
"version",
|
|
20568
|
+
"tenant",
|
|
20569
|
+
"did",
|
|
20570
|
+
"authorityGeneration",
|
|
20571
|
+
"expectedEnrollmentVersion",
|
|
20572
|
+
"action",
|
|
20573
|
+
"sourceBlobIdentity",
|
|
20574
|
+
"targetBlobIdentity",
|
|
20575
|
+
"pinAction",
|
|
20576
|
+
"shareVersion",
|
|
20577
|
+
"enrollmentEpoch",
|
|
20578
|
+
"requestId",
|
|
20579
|
+
"allowRewrap",
|
|
20580
|
+
"recoveryEmail",
|
|
20581
|
+
"recoveryLanguage"
|
|
20582
|
+
];
|
|
20583
|
+
var ACTIONS = ["enroll", "replace", "disable", "carry"];
|
|
20584
|
+
var PIN_ACTIONS = ["set", "change", "clear", "keep"];
|
|
20585
|
+
var RECOVERY_LANGUAGES2 = ["en", "es", "fr", "ar"];
|
|
20586
|
+
var requireIntent = /* @__PURE__ */ __name((condition) => {
|
|
20587
|
+
if (!condition) throw new Error("Invalid escrow enrollment intent");
|
|
20588
|
+
}, "requireIntent");
|
|
20589
|
+
var matches = /* @__PURE__ */ __name((value, pattern) => typeof value === "string" && pattern.exec(value)?.[0] === value, "matches");
|
|
20590
|
+
var utf8 = /* @__PURE__ */ __name((value) => new TextEncoder().encode(value), "utf8");
|
|
20591
|
+
var integer = /* @__PURE__ */ __name((value, width) => {
|
|
20592
|
+
requireIntent(
|
|
20593
|
+
Number.isSafeInteger(value) && value >= 0 && (width === 8 || value <= 4294967295)
|
|
20594
|
+
);
|
|
20595
|
+
const bytes3 = new Uint8Array(width);
|
|
20596
|
+
const view = new DataView(bytes3.buffer);
|
|
20597
|
+
if (width === 4) view.setUint32(0, value, false);
|
|
20598
|
+
else view.setBigUint64(0, BigInt(value), false);
|
|
20599
|
+
return bytes3;
|
|
20600
|
+
}, "integer");
|
|
20601
|
+
var join = /* @__PURE__ */ __name((fields) => {
|
|
20602
|
+
const result = new Uint8Array(fields.reduce((length, field) => length + field.length, 0));
|
|
20603
|
+
let offset = 0;
|
|
20604
|
+
for (const field of fields) {
|
|
20605
|
+
result.set(field, offset);
|
|
20606
|
+
offset += field.length;
|
|
20607
|
+
}
|
|
20608
|
+
return result;
|
|
20609
|
+
}, "join");
|
|
20610
|
+
var hashBytes = /* @__PURE__ */ __name((value) => {
|
|
20611
|
+
if (value === null) return new Uint8Array();
|
|
20612
|
+
requireIntent(matches(value, /^[0-9a-f]{64}$/));
|
|
20613
|
+
return new Uint8Array(hexToBytes(value));
|
|
20614
|
+
}, "hashBytes");
|
|
20615
|
+
var didPublicKey = /* @__PURE__ */ __name((did) => {
|
|
20616
|
+
requireIntent(typeof did === "string" && did.startsWith("did:key:z") && did.length === 56);
|
|
20617
|
+
let value = 0n;
|
|
20618
|
+
for (const char of did.slice(9)) {
|
|
20619
|
+
const digit = BASE58.indexOf(char);
|
|
20620
|
+
requireIntent(digit >= 0);
|
|
20621
|
+
value = value * 58n + BigInt(digit);
|
|
20622
|
+
}
|
|
20623
|
+
const bytes3 = new Uint8Array(34);
|
|
20624
|
+
for (let i = 33; i >= 0; i--) {
|
|
20625
|
+
bytes3[i] = Number(value & 255n);
|
|
20626
|
+
value >>= 8n;
|
|
20627
|
+
}
|
|
20628
|
+
requireIntent(value === 0n && bytes3[0] === 237 && bytes3[1] === 1);
|
|
20629
|
+
const key = bytes3.slice(2);
|
|
20630
|
+
try {
|
|
20631
|
+
requireIntent(!ExtendedPoint.fromHex(key, false).isSmallOrder());
|
|
20632
|
+
} catch {
|
|
20633
|
+
throw new Error("Invalid escrow enrollment intent");
|
|
20634
|
+
}
|
|
20635
|
+
return key;
|
|
20636
|
+
}, "didPublicKey");
|
|
20637
|
+
var encodeEscrowEnrollmentIntent = /* @__PURE__ */ __name((intent) => {
|
|
20638
|
+
requireIntent(typeof intent === "object" && intent !== null && !Array.isArray(intent));
|
|
20639
|
+
requireIntent(
|
|
20640
|
+
Object.keys(intent).length === FIELDS.length && FIELDS.every((field) => Object.prototype.hasOwnProperty.call(intent, field))
|
|
20641
|
+
);
|
|
20642
|
+
requireIntent(intent.version === 2 && typeof intent.allowRewrap === "boolean");
|
|
20643
|
+
requireIntent(matches(intent.tenant, /^[A-Za-z0-9_-]{1,128}$/));
|
|
20644
|
+
requireIntent(matches(intent.authorityGeneration, /^[A-Za-z0-9_-]{1,128}$/));
|
|
20645
|
+
requireIntent(matches(intent.requestId, /^[A-Za-z0-9._-]{1,112}$/));
|
|
20646
|
+
didPublicKey(intent.did);
|
|
20647
|
+
const action = ACTIONS.indexOf(intent.action);
|
|
20648
|
+
const pin = PIN_ACTIONS.indexOf(intent.pinAction);
|
|
20649
|
+
requireIntent(action >= 0 && pin >= 0 && intent.shareVersion > 0 && intent.enrollmentEpoch > 0);
|
|
20650
|
+
const source = hashBytes(intent.sourceBlobIdentity);
|
|
20651
|
+
const target = hashBytes(intent.targetBlobIdentity);
|
|
20652
|
+
if (intent.action === "enroll") requireIntent(source.length === 0 && target.length === 32);
|
|
20653
|
+
else if (intent.action === "disable")
|
|
20654
|
+
requireIntent(
|
|
20655
|
+
source.length === 32 && target.length === 0 && intent.pinAction === "keep" && !intent.allowRewrap
|
|
20656
|
+
);
|
|
20657
|
+
else
|
|
20658
|
+
requireIntent(
|
|
20659
|
+
source.length === 32 && target.length === 32 && intent.sourceBlobIdentity !== intent.targetBlobIdentity
|
|
20660
|
+
);
|
|
20661
|
+
if (intent.action === "carry") requireIntent(intent.pinAction === "keep");
|
|
20662
|
+
if (intent.recoveryEmail === null) {
|
|
20663
|
+
requireIntent(
|
|
20664
|
+
intent.recoveryLanguage === null && (intent.action === "disable" || intent.action === "carry")
|
|
20665
|
+
);
|
|
20666
|
+
} else {
|
|
20667
|
+
requireIntent(intent.action === "enroll" || intent.action === "replace");
|
|
20668
|
+
requireIntent(
|
|
20669
|
+
matches(intent.recoveryEmail, /^[\x21-\x7e]{3,254}$/) && intent.recoveryEmail === intent.recoveryEmail.trim().toLowerCase()
|
|
20670
|
+
);
|
|
20671
|
+
const at = intent.recoveryEmail.split("@");
|
|
20672
|
+
requireIntent(
|
|
20673
|
+
at.length === 2 && at[0].length > 0 && at[1].length > 0 && at[1].includes(".") && !at[1].startsWith(".") && !at[1].endsWith(".")
|
|
20674
|
+
);
|
|
20675
|
+
requireIntent(
|
|
20676
|
+
intent.recoveryLanguage !== null && RECOVERY_LANGUAGES2.includes(intent.recoveryLanguage)
|
|
20677
|
+
);
|
|
20678
|
+
}
|
|
20679
|
+
const fields = [
|
|
20680
|
+
integer(intent.version, 4),
|
|
20681
|
+
utf8(intent.tenant),
|
|
20682
|
+
utf8(intent.did),
|
|
20683
|
+
utf8(intent.authorityGeneration),
|
|
20684
|
+
integer(intent.expectedEnrollmentVersion, 8),
|
|
20685
|
+
Uint8Array.of(action),
|
|
20686
|
+
source,
|
|
20687
|
+
target,
|
|
20688
|
+
Uint8Array.of(pin),
|
|
20689
|
+
integer(intent.shareVersion, 4),
|
|
20690
|
+
integer(intent.enrollmentEpoch, 8),
|
|
20691
|
+
utf8(intent.requestId),
|
|
20692
|
+
Uint8Array.of(Number(intent.allowRewrap)),
|
|
20693
|
+
intent.recoveryEmail === null ? new Uint8Array() : utf8(intent.recoveryEmail),
|
|
20694
|
+
intent.recoveryLanguage === null ? new Uint8Array() : utf8(intent.recoveryLanguage)
|
|
20695
|
+
];
|
|
20696
|
+
return join([
|
|
20697
|
+
utf8(ESCROW_ENROLLMENT_INTENT_DOMAIN),
|
|
20698
|
+
...fields.flatMap((field) => [integer(field.length, 4), field])
|
|
20699
|
+
]);
|
|
20700
|
+
}, "encodeEscrowEnrollmentIntent");
|
|
20701
|
+
var signEscrowEnrollmentIntent = /* @__PURE__ */ __name(async (intent, privateKey) => {
|
|
20702
|
+
encodeEscrowEnrollmentIntent(intent);
|
|
20703
|
+
const snapshot = { ...intent };
|
|
20704
|
+
const message = encodeEscrowEnrollmentIntent(snapshot);
|
|
20705
|
+
requireIntent(matches(privateKey, /^[0-9a-f]{64}$/i));
|
|
20706
|
+
const seed = hexToBytes(privateKey);
|
|
20707
|
+
try {
|
|
20708
|
+
const publicKey = await getPublicKeyAsync(seed);
|
|
20709
|
+
const expected = didPublicKey(snapshot.did);
|
|
20710
|
+
requireIntent(publicKey.every((byte, index) => byte === expected[index]));
|
|
20711
|
+
const signature = await signAsync(message, seed);
|
|
20712
|
+
return { intent: snapshot, signature: bufferToBase64(new Uint8Array(signature).buffer) };
|
|
20713
|
+
} finally {
|
|
20714
|
+
seed.fill(0);
|
|
20715
|
+
}
|
|
20716
|
+
}, "signEscrowEnrollmentIntent");
|
|
20717
|
+
var getEscrowBlobIdentity = /* @__PURE__ */ __name(async (input) => {
|
|
20718
|
+
const envelope2 = parseEscrowEnvelope(input);
|
|
20719
|
+
const decode2 = /* @__PURE__ */ __name((value) => {
|
|
20720
|
+
const bytes3 = new Uint8Array(base64ToBuffer(value));
|
|
20721
|
+
requireIntent(bufferToBase64(bytes3.buffer) === value);
|
|
20722
|
+
return bytes3;
|
|
20723
|
+
}, "decode");
|
|
20724
|
+
const point = decode2(envelope2.ephemeralPublicKey);
|
|
20725
|
+
const salt = decode2(envelope2.salt);
|
|
20726
|
+
const iv = decode2(envelope2.iv);
|
|
20727
|
+
const ciphertext = decode2(envelope2.ciphertext);
|
|
20728
|
+
requireIntent(
|
|
20729
|
+
point.length === 65 && point[0] === 4 && salt.length === 32 && iv.length === 12 && ciphertext.length >= 16
|
|
20730
|
+
);
|
|
20731
|
+
await crypto.subtle.importKey("raw", point, { name: "ECDH", namedCurve: "P-256" }, false, []);
|
|
20732
|
+
const fields = [
|
|
20733
|
+
Uint8Array.of(1),
|
|
20734
|
+
utf8(envelope2.algorithm),
|
|
20735
|
+
utf8(envelope2.keyId),
|
|
20736
|
+
point.slice(1, 33),
|
|
20737
|
+
salt,
|
|
20738
|
+
iv,
|
|
20739
|
+
ciphertext
|
|
20740
|
+
];
|
|
20741
|
+
const message = join([
|
|
20742
|
+
utf8("learncard-escrow-blob-id-v1\0"),
|
|
20743
|
+
...fields.flatMap((field) => [integer(field.length, 8), field])
|
|
20744
|
+
]);
|
|
20745
|
+
return bytesToHex(new Uint8Array(await crypto.subtle.digest("SHA-256", message)));
|
|
20746
|
+
}, "getEscrowBlobIdentity");
|
|
20747
|
+
|
|
20517
20748
|
// src/escrow-nitro-attestation.ts
|
|
20518
20749
|
import "reflect-metadata";
|
|
20519
20750
|
import { decode, encode } from "cborg";
|
|
@@ -20537,15 +20768,15 @@ var AWS_ROOT_SHA256 = "641a0321a3e244efe456463195d606317ed7cdcc3c1756e09893f3c68
|
|
|
20537
20768
|
var fail = /* @__PURE__ */ __name((reason) => {
|
|
20538
20769
|
throw new NitroAttestationError(reason);
|
|
20539
20770
|
}, "fail");
|
|
20540
|
-
var hex = /* @__PURE__ */ __name((
|
|
20771
|
+
var hex = /* @__PURE__ */ __name((bytes3) => Array.from(bytes3, (byte) => byte.toString(16).padStart(2, "0")).join(""), "hex");
|
|
20541
20772
|
var bytes = /* @__PURE__ */ __name((value, reason) => value instanceof Uint8Array && value.length > 0 ? value : fail(reason), "bytes");
|
|
20542
20773
|
var map = /* @__PURE__ */ __name((value, reason) => value instanceof Map ? value : fail(reason), "map");
|
|
20543
|
-
var decodeCbor = /* @__PURE__ */ __name((value) => {
|
|
20774
|
+
var decodeCbor = /* @__PURE__ */ __name((value, { allowIndefinite = false } = {}) => {
|
|
20544
20775
|
try {
|
|
20545
20776
|
return decode(value, {
|
|
20546
20777
|
useMaps: true,
|
|
20547
20778
|
rejectDuplicateMapKeys: true,
|
|
20548
|
-
allowIndefinite
|
|
20779
|
+
allowIndefinite,
|
|
20549
20780
|
allowUndefined: false,
|
|
20550
20781
|
allowNaN: false,
|
|
20551
20782
|
allowInfinity: false,
|
|
@@ -20603,7 +20834,7 @@ var verifyNitroAttestationDocument = /* @__PURE__ */ __name(async (documentB64,
|
|
|
20603
20834
|
const payloadBytes = bytes(payloadValue, "cose");
|
|
20604
20835
|
const signature = bytes(signatureValue, "signature");
|
|
20605
20836
|
if (signature.length !== 96) fail("signature");
|
|
20606
|
-
const payload = map(decodeCbor(payloadBytes), "cbor");
|
|
20837
|
+
const payload = map(decodeCbor(payloadBytes, { allowIndefinite: true }), "cbor");
|
|
20607
20838
|
const moduleId = payload.get("module_id");
|
|
20608
20839
|
const timestamp = payload.get("timestamp");
|
|
20609
20840
|
if (typeof moduleId !== "string" || !moduleId || payload.get("digest") !== "SHA384")
|
|
@@ -20693,13 +20924,36 @@ var verifyNitroAttestationDocument = /* @__PURE__ */ __name(async (documentB64,
|
|
|
20693
20924
|
} catch {
|
|
20694
20925
|
return fail("user-data");
|
|
20695
20926
|
}
|
|
20927
|
+
const rawLedgerKey = payload.get("public_key");
|
|
20928
|
+
let ledgerPublicKey;
|
|
20929
|
+
let measurementHash;
|
|
20930
|
+
if (rawLedgerKey !== void 0 && rawLedgerKey !== null) {
|
|
20931
|
+
const ledger = new Uint8Array(bytes(rawLedgerKey, "user-data"));
|
|
20932
|
+
if (ledger.length !== 65 || ledger[0] !== 4) fail("user-data");
|
|
20933
|
+
try {
|
|
20934
|
+
await crypto.subtle.importKey(
|
|
20935
|
+
"raw",
|
|
20936
|
+
ledger,
|
|
20937
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
20938
|
+
false,
|
|
20939
|
+
["verify"]
|
|
20940
|
+
);
|
|
20941
|
+
} catch {
|
|
20942
|
+
return fail("user-data");
|
|
20943
|
+
}
|
|
20944
|
+
const tuple = new Uint8Array(144);
|
|
20945
|
+
for (let i = 0; i < 3; i++) tuple.set(bytes(rawPcrs.get(i), "pcr"), i * 48);
|
|
20946
|
+
measurementHash = hex(new Uint8Array(await crypto.subtle.digest("SHA-256", tuple)));
|
|
20947
|
+
ledgerPublicKey = bufferToBase64(ledger.buffer);
|
|
20948
|
+
}
|
|
20696
20949
|
return {
|
|
20697
20950
|
escrowPublicKeySpkiB64: bufferToBase64(new Uint8Array(spki).buffer),
|
|
20698
20951
|
keyId: newFormat?.keyId,
|
|
20699
20952
|
previousKeyIds: newFormat?.previousKeyIds ?? [],
|
|
20700
20953
|
pcrs,
|
|
20701
20954
|
timestamp,
|
|
20702
|
-
moduleId
|
|
20955
|
+
moduleId,
|
|
20956
|
+
...ledgerPublicKey ? { ledgerPublicKey, measurementHash } : {}
|
|
20703
20957
|
};
|
|
20704
20958
|
}, "verifyNitroAttestationDocument");
|
|
20705
20959
|
|
|
@@ -20753,7 +21007,13 @@ var verifyEnclaveAttestation = /* @__PURE__ */ __name(async (attestation, policy
|
|
|
20753
21007
|
publicKey: verified.escrowPublicKeySpkiB64,
|
|
20754
21008
|
keyId: attestation.keyId,
|
|
20755
21009
|
previousKeyIds: verified.previousKeyIds,
|
|
20756
|
-
mode: "nitro"
|
|
21010
|
+
mode: "nitro",
|
|
21011
|
+
...verified.keyId && verified.ledgerPublicKey && verified.measurementHash ? {
|
|
21012
|
+
authority: {
|
|
21013
|
+
ledgerPublicKey: verified.ledgerPublicKey,
|
|
21014
|
+
measurement: verified.measurementHash
|
|
21015
|
+
}
|
|
21016
|
+
} : {}
|
|
20757
21017
|
};
|
|
20758
21018
|
}
|
|
20759
21019
|
const publicKey = normalizePublicKey(attestation.publicKey);
|
|
@@ -20775,6 +21035,424 @@ var verifyEnclaveAttestation = /* @__PURE__ */ __name(async (attestation, policy
|
|
|
20775
21035
|
};
|
|
20776
21036
|
}, "verifyEnclaveAttestation");
|
|
20777
21037
|
|
|
21038
|
+
// src/escrow-authority.types.ts
|
|
21039
|
+
var EscrowEvidenceError = class extends Error {
|
|
21040
|
+
static {
|
|
21041
|
+
__name(this, "EscrowEvidenceError");
|
|
21042
|
+
}
|
|
21043
|
+
constructor() {
|
|
21044
|
+
super("Automatic recovery evidence could not be verified.");
|
|
21045
|
+
this.name = "EscrowEvidenceError";
|
|
21046
|
+
}
|
|
21047
|
+
};
|
|
21048
|
+
|
|
21049
|
+
// src/escrow-authority.ts
|
|
21050
|
+
var fail2 = /* @__PURE__ */ __name(() => {
|
|
21051
|
+
throw new EscrowEvidenceError();
|
|
21052
|
+
}, "fail");
|
|
21053
|
+
var verifyEscrowHoldState = /* @__PURE__ */ __name(async (response, nonce, expected, identity) => {
|
|
21054
|
+
requireEvidence(/^[0-9a-f]{64}$/.test(nonce));
|
|
21055
|
+
const { payload } = await verifyRecord(response.proof, "snapshot", identity);
|
|
21056
|
+
requireEvidence(Array.isArray(payload) && payload.length === 12);
|
|
21057
|
+
const p = payload;
|
|
21058
|
+
requireEvidence(
|
|
21059
|
+
p[0] === "learncard-authority-hold-state-v3" && p[1] === nonce && p[2] === expected.tenant && p[3] === expected.authorityGeneration && p[4] === expected.did && p[5] === expected.holdId && p[6] === expected.holdDigest
|
|
21060
|
+
);
|
|
21061
|
+
const status = p[7];
|
|
21062
|
+
if (status !== "awaitingConfirmation" && status !== "pending" && status !== "released" && status !== "cancelled")
|
|
21063
|
+
return fail2();
|
|
21064
|
+
const confirmedHiMs = p[8] === null ? null : integer2(p[8]);
|
|
21065
|
+
const releaseWarningSentHiMs = p[9] === null ? null : integer2(p[9]);
|
|
21066
|
+
const attemptsRemaining = integer2(p[10], 0, 5);
|
|
21067
|
+
const codeSendStatus = p[11];
|
|
21068
|
+
if (codeSendStatus !== "unknown" && codeSendStatus !== "notRequired") return fail2();
|
|
21069
|
+
requireEvidence(
|
|
21070
|
+
status !== "awaitingConfirmation" || confirmedHiMs === null && releaseWarningSentHiMs === null
|
|
21071
|
+
);
|
|
21072
|
+
requireEvidence(status !== "pending" && status !== "released" || confirmedHiMs !== null);
|
|
21073
|
+
return { status, confirmedHiMs, releaseWarningSentHiMs, attemptsRemaining, codeSendStatus };
|
|
21074
|
+
}, "verifyEscrowHoldState");
|
|
21075
|
+
var verifyEscrowCodeDelivery = /* @__PURE__ */ __name(async (delivery, expected, identity) => {
|
|
21076
|
+
const { payload } = await verifyRecord(delivery.proof, "snapshot", identity);
|
|
21077
|
+
requireEvidence(Array.isArray(payload) && payload.length === 5);
|
|
21078
|
+
const values = payload;
|
|
21079
|
+
requireEvidence(
|
|
21080
|
+
values[0] === "learncard-authority-code-delivery-v1" && values[1] === expected.tenant && values[2] === expected.authorityGeneration && values[3] === expected.holdDigest && typeof values[4] === "boolean" && values[4] === delivery.codeSent
|
|
21081
|
+
);
|
|
21082
|
+
return delivery.codeSent;
|
|
21083
|
+
}, "verifyEscrowCodeDelivery");
|
|
21084
|
+
var requireEvidence = /* @__PURE__ */ __name((condition) => {
|
|
21085
|
+
if (!condition) fail2();
|
|
21086
|
+
}, "requireEvidence");
|
|
21087
|
+
var object = /* @__PURE__ */ __name((value) => {
|
|
21088
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return fail2();
|
|
21089
|
+
return value;
|
|
21090
|
+
}, "object");
|
|
21091
|
+
var keys = /* @__PURE__ */ __name((value, names) => {
|
|
21092
|
+
requireEvidence(
|
|
21093
|
+
Object.keys(value).length === names.length && names.every((name) => Object.prototype.hasOwnProperty.call(value, name))
|
|
21094
|
+
);
|
|
21095
|
+
}, "keys");
|
|
21096
|
+
var integer2 = /* @__PURE__ */ __name((value, minimum = 0, maximum = Number.MAX_SAFE_INTEGER) => {
|
|
21097
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < minimum || value > maximum)
|
|
21098
|
+
return fail2();
|
|
21099
|
+
return value;
|
|
21100
|
+
}, "integer");
|
|
21101
|
+
var text = /* @__PURE__ */ __name((value, maximum) => {
|
|
21102
|
+
if (typeof value !== "string" || !value.length || value.length > maximum) return fail2();
|
|
21103
|
+
return value;
|
|
21104
|
+
}, "text");
|
|
21105
|
+
var bytes2 = /* @__PURE__ */ __name((value, length) => {
|
|
21106
|
+
if (!Array.isArray(value) || value.length !== length || !value.every(
|
|
21107
|
+
(byte) => typeof byte === "number" && Number.isInteger(byte) && byte >= 0 && byte <= 255
|
|
21108
|
+
))
|
|
21109
|
+
return fail2();
|
|
21110
|
+
return Uint8Array.from(value);
|
|
21111
|
+
}, "bytes");
|
|
21112
|
+
var base64 = /* @__PURE__ */ __name((value, maximum) => {
|
|
21113
|
+
const encoded = text(value, maximum);
|
|
21114
|
+
try {
|
|
21115
|
+
const decoded = new Uint8Array(base64ToBuffer(encoded));
|
|
21116
|
+
requireEvidence(bufferToBase64(decoded.buffer) === encoded);
|
|
21117
|
+
return decoded;
|
|
21118
|
+
} catch {
|
|
21119
|
+
return fail2();
|
|
21120
|
+
}
|
|
21121
|
+
}, "base64");
|
|
21122
|
+
var frame = /* @__PURE__ */ __name((value) => {
|
|
21123
|
+
const result = new Uint8Array(4 + value.length);
|
|
21124
|
+
new DataView(result.buffer).setUint32(0, value.length, false);
|
|
21125
|
+
result.set(value, 4);
|
|
21126
|
+
return result;
|
|
21127
|
+
}, "frame");
|
|
21128
|
+
var join2 = /* @__PURE__ */ __name((...values) => {
|
|
21129
|
+
const result = new Uint8Array(values.reduce((n, v) => n + v.length, 0));
|
|
21130
|
+
let offset = 0;
|
|
21131
|
+
for (const value of values) {
|
|
21132
|
+
result.set(value, offset);
|
|
21133
|
+
offset += value.length;
|
|
21134
|
+
}
|
|
21135
|
+
return result;
|
|
21136
|
+
}, "join");
|
|
21137
|
+
var hash = /* @__PURE__ */ __name(async (value) => bytesToHex(new Uint8Array(await crypto.subtle.digest("SHA-256", new Uint8Array(value)))), "hash");
|
|
21138
|
+
var utf82 = /* @__PURE__ */ __name((value) => new TextEncoder().encode(value), "utf8");
|
|
21139
|
+
var escrowAuthorityMeasurements = /* @__PURE__ */ __name(async (policy) => {
|
|
21140
|
+
if (policy.mode !== "nitro") return [];
|
|
21141
|
+
const hashes = [];
|
|
21142
|
+
for (const pin of policy.pinnedMeasurements) {
|
|
21143
|
+
const tuple = [pin.pcr0, pin.pcr1, pin.pcr2];
|
|
21144
|
+
if (!tuple.every((pcr) => typeof pcr === "string" && /^[0-9a-f]{96}$/i.test(pcr))) continue;
|
|
21145
|
+
if (pin.pcr0 === "00".repeat(48)) continue;
|
|
21146
|
+
const encoded = tuple.join("");
|
|
21147
|
+
const decoded = Uint8Array.from(
|
|
21148
|
+
{ length: 144 },
|
|
21149
|
+
(_, i) => parseInt(encoded.slice(i * 2, i * 2 + 2), 16)
|
|
21150
|
+
);
|
|
21151
|
+
hashes.push(await hash(decoded));
|
|
21152
|
+
}
|
|
21153
|
+
return hashes;
|
|
21154
|
+
}, "escrowAuthorityMeasurements");
|
|
21155
|
+
var P256_ORDER = BigInt("0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551");
|
|
21156
|
+
var verifyRecord = /* @__PURE__ */ __name(async (input, kind, identity, historical) => {
|
|
21157
|
+
requireEvidence(identity.mode === "nitro" && !!identity.authority);
|
|
21158
|
+
const raw = object(input);
|
|
21159
|
+
keys(raw, ["version", "kind", "keyId", "measurement", "payload", "signature"]);
|
|
21160
|
+
requireEvidence(raw.version === 1 && raw.kind === kind);
|
|
21161
|
+
const keyId = text(raw.keyId, 128);
|
|
21162
|
+
requireEvidence(
|
|
21163
|
+
historical ? [identity.keyId, ...identity.previousKeyIds].includes(keyId) : keyId === identity.keyId
|
|
21164
|
+
);
|
|
21165
|
+
const measurement = bytes2(raw.measurement, 32);
|
|
21166
|
+
requireEvidence(
|
|
21167
|
+
historical ? historical.allowedMeasurements.includes(bytesToHex(measurement)) : bytesToHex(measurement) === identity.authority?.measurement
|
|
21168
|
+
);
|
|
21169
|
+
const payloadB64 = text(raw.payload, kind === "snapshot" ? 49152 : 8192);
|
|
21170
|
+
const signatureB64 = text(raw.signature, 88);
|
|
21171
|
+
const payload = base64(payloadB64, kind === "snapshot" ? 49152 : 8192);
|
|
21172
|
+
const signature = base64(signatureB64, 88);
|
|
21173
|
+
const ledgerKey = base64(identity.authority?.ledgerPublicKey, 88);
|
|
21174
|
+
requireEvidence(ledgerKey.length === 65 && ledgerKey[0] === 4);
|
|
21175
|
+
requireEvidence(signature.length === 64);
|
|
21176
|
+
const s = BigInt(`0x${bytesToHex(signature.slice(32))}`);
|
|
21177
|
+
requireEvidence(s > 0n && s <= P256_ORDER / 2n);
|
|
21178
|
+
const message = join2(
|
|
21179
|
+
utf82("learncard-authority-signed-record-v1\0"),
|
|
21180
|
+
Uint8Array.of(kind === "snapshot" ? 2 : 1),
|
|
21181
|
+
frame(utf82(keyId)),
|
|
21182
|
+
measurement,
|
|
21183
|
+
frame(payload)
|
|
21184
|
+
);
|
|
21185
|
+
try {
|
|
21186
|
+
const key = await crypto.subtle.importKey(
|
|
21187
|
+
"raw",
|
|
21188
|
+
ledgerKey,
|
|
21189
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
21190
|
+
false,
|
|
21191
|
+
["verify"]
|
|
21192
|
+
);
|
|
21193
|
+
requireEvidence(
|
|
21194
|
+
await crypto.subtle.verify({ name: "ECDSA", hash: "SHA-256" }, key, signature, message)
|
|
21195
|
+
);
|
|
21196
|
+
const decoded = JSON.parse(
|
|
21197
|
+
new TextDecoder("utf-8", { fatal: true }).decode(payload)
|
|
21198
|
+
);
|
|
21199
|
+
const record = {
|
|
21200
|
+
version: 1,
|
|
21201
|
+
kind,
|
|
21202
|
+
keyId,
|
|
21203
|
+
measurement: Array.from(measurement),
|
|
21204
|
+
payload: payloadB64,
|
|
21205
|
+
signature: signatureB64
|
|
21206
|
+
};
|
|
21207
|
+
return { record, payload: decoded };
|
|
21208
|
+
} catch {
|
|
21209
|
+
return fail2();
|
|
21210
|
+
}
|
|
21211
|
+
}, "verifyRecord");
|
|
21212
|
+
var envelope = /* @__PURE__ */ __name((value) => {
|
|
21213
|
+
try {
|
|
21214
|
+
const e = parseEscrowEnvelope(value);
|
|
21215
|
+
return {
|
|
21216
|
+
version: e.version,
|
|
21217
|
+
algorithm: e.algorithm,
|
|
21218
|
+
keyId: e.keyId,
|
|
21219
|
+
ephemeralPublicKey: e.ephemeralPublicKey,
|
|
21220
|
+
salt: e.salt,
|
|
21221
|
+
iv: e.iv,
|
|
21222
|
+
ciphertext: e.ciphertext
|
|
21223
|
+
};
|
|
21224
|
+
} catch {
|
|
21225
|
+
return fail2();
|
|
21226
|
+
}
|
|
21227
|
+
}, "envelope");
|
|
21228
|
+
var state = /* @__PURE__ */ __name((value) => {
|
|
21229
|
+
const raw = object(value);
|
|
21230
|
+
keys(raw, [
|
|
21231
|
+
"tenant",
|
|
21232
|
+
"authorityGeneration",
|
|
21233
|
+
"did",
|
|
21234
|
+
"enrollmentVersion",
|
|
21235
|
+
"enrollmentEpoch",
|
|
21236
|
+
"status",
|
|
21237
|
+
"envelope",
|
|
21238
|
+
"shareVersion",
|
|
21239
|
+
"hasPin",
|
|
21240
|
+
"pinGeneration",
|
|
21241
|
+
"attemptsUsed"
|
|
21242
|
+
]);
|
|
21243
|
+
if (raw.status !== "empty" && raw.status !== "active" && raw.status !== "disabled")
|
|
21244
|
+
return fail2();
|
|
21245
|
+
if (typeof raw.hasPin !== "boolean") return fail2();
|
|
21246
|
+
const result = {
|
|
21247
|
+
tenant: text(raw.tenant, 128),
|
|
21248
|
+
authorityGeneration: text(raw.authorityGeneration, 128),
|
|
21249
|
+
did: text(raw.did, 8192),
|
|
21250
|
+
enrollmentVersion: integer2(raw.enrollmentVersion),
|
|
21251
|
+
enrollmentEpoch: integer2(raw.enrollmentEpoch),
|
|
21252
|
+
status: raw.status,
|
|
21253
|
+
envelope: raw.envelope === null ? null : envelope(raw.envelope),
|
|
21254
|
+
shareVersion: raw.shareVersion === null ? null : integer2(raw.shareVersion, 1, 4294967295),
|
|
21255
|
+
hasPin: raw.hasPin,
|
|
21256
|
+
pinGeneration: integer2(raw.pinGeneration),
|
|
21257
|
+
attemptsUsed: integer2(raw.attemptsUsed, 0, 10)
|
|
21258
|
+
};
|
|
21259
|
+
requireEvidence(
|
|
21260
|
+
result.pinGeneration <= result.enrollmentVersion && result.enrollmentEpoch <= result.enrollmentVersion && (!result.hasPin || result.pinGeneration > 0) && (result.hasPin || result.attemptsUsed === 0)
|
|
21261
|
+
);
|
|
21262
|
+
if (result.status === "empty")
|
|
21263
|
+
requireEvidence(
|
|
21264
|
+
result.enrollmentVersion === 0 && result.enrollmentEpoch === 0 && !result.envelope && result.shareVersion === null && !result.hasPin
|
|
21265
|
+
);
|
|
21266
|
+
else requireEvidence(result.enrollmentVersion > 0 && result.enrollmentEpoch > 0);
|
|
21267
|
+
if (result.status === "active")
|
|
21268
|
+
requireEvidence(!!result.envelope && result.shareVersion !== null);
|
|
21269
|
+
else requireEvidence(result.envelope === null && result.shareVersion === null);
|
|
21270
|
+
return result;
|
|
21271
|
+
}, "state");
|
|
21272
|
+
var verifyEscrowAuthorityState = /* @__PURE__ */ __name(async (response, nonce, tenant, did, identity) => {
|
|
21273
|
+
requireEvidence(/^[0-9a-f]{64}$/.test(nonce) && nonce.length === 64);
|
|
21274
|
+
const raw = object(response);
|
|
21275
|
+
keys(raw, ["state", "proof"]);
|
|
21276
|
+
const { payload } = await verifyRecord(raw.proof, "snapshot", identity);
|
|
21277
|
+
if (!Array.isArray(payload) || payload.length !== 2 || payload[0] !== nonce) return fail2();
|
|
21278
|
+
const signed = state(payload[1]);
|
|
21279
|
+
requireEvidence(signed.tenant === tenant && signed.did === did);
|
|
21280
|
+
requireEvidence(JSON.stringify(signed) === JSON.stringify(state(raw.state)));
|
|
21281
|
+
if (signed.envelope) {
|
|
21282
|
+
requireEvidence(
|
|
21283
|
+
[identity.keyId, ...identity.previousKeyIds].includes(signed.envelope.keyId)
|
|
21284
|
+
);
|
|
21285
|
+
await getEscrowBlobIdentity(signed.envelope);
|
|
21286
|
+
}
|
|
21287
|
+
return signed;
|
|
21288
|
+
}, "verifyEscrowAuthorityState");
|
|
21289
|
+
var verifyEscrowEnrollmentCommit = /* @__PURE__ */ __name(async (response, intent, identity) => {
|
|
21290
|
+
const raw = object(response);
|
|
21291
|
+
const { record, payload } = await verifyRecord(raw.receipt, "commit", identity);
|
|
21292
|
+
const data = object(payload);
|
|
21293
|
+
keys(data, ["commit", "eventHash", "requestDigest", "resultBlobIdentity", "enrollmentEpoch"]);
|
|
21294
|
+
const commit = object(data.commit);
|
|
21295
|
+
keys(commit, ["schemaVersion", "binding", "executionId", "revisions", "transactionDigest"]);
|
|
21296
|
+
const binding = object(commit.binding);
|
|
21297
|
+
keys(binding, ["tenant", "generation", "didHash"]);
|
|
21298
|
+
const revisions = object(commit.revisions);
|
|
21299
|
+
keys(revisions, ["operation", "enrollment"]);
|
|
21300
|
+
requireEvidence(
|
|
21301
|
+
commit.schemaVersion === 1 && binding.tenant === intent.tenant && binding.generation === intent.authorityGeneration
|
|
21302
|
+
);
|
|
21303
|
+
requireEvidence(bytesToHex(bytes2(binding.didHash, 32)) === await hash(utf82(intent.did)));
|
|
21304
|
+
requireEvidence(
|
|
21305
|
+
integer2(revisions.enrollment, 1) === intent.expectedEnrollmentVersion + 1 && integer2(revisions.operation, 1) >= integer2(revisions.enrollment, 1)
|
|
21306
|
+
);
|
|
21307
|
+
bytes2(commit.executionId, 16);
|
|
21308
|
+
bytes2(commit.transactionDigest, 32);
|
|
21309
|
+
bytes2(data.eventHash, 32);
|
|
21310
|
+
requireEvidence(integer2(data.enrollmentEpoch, 1) === intent.enrollmentEpoch);
|
|
21311
|
+
requireEvidence(
|
|
21312
|
+
bytesToHex(bytes2(data.requestDigest, 32)) === await hash(encodeEscrowEnrollmentIntent(intent))
|
|
21313
|
+
);
|
|
21314
|
+
if (intent.action === "disable") {
|
|
21315
|
+
requireEvidence(
|
|
21316
|
+
(raw.envelope === null || raw.envelope === void 0) && data.resultBlobIdentity === null
|
|
21317
|
+
);
|
|
21318
|
+
return { envelope: null, receipt: record };
|
|
21319
|
+
}
|
|
21320
|
+
const output = envelope(raw.envelope);
|
|
21321
|
+
requireEvidence(
|
|
21322
|
+
output.keyId === identity.keyId && bytesToHex(bytes2(data.resultBlobIdentity, 32)) === await getEscrowBlobIdentity(output)
|
|
21323
|
+
);
|
|
21324
|
+
return { envelope: output, receipt: record };
|
|
21325
|
+
}, "verifyEscrowEnrollmentCommit");
|
|
21326
|
+
var holdDigest = /* @__PURE__ */ __name(async (tenant, record) => {
|
|
21327
|
+
const h = record.hold;
|
|
21328
|
+
const didHash = await hash(utf82(h.did));
|
|
21329
|
+
return hash(
|
|
21330
|
+
utf82(
|
|
21331
|
+
JSON.stringify([
|
|
21332
|
+
"learncard-hold-v1",
|
|
21333
|
+
tenant,
|
|
21334
|
+
h.holdId,
|
|
21335
|
+
didHash,
|
|
21336
|
+
h.shareVersion,
|
|
21337
|
+
h.blobHash,
|
|
21338
|
+
h.enrollmentEpoch,
|
|
21339
|
+
h.releasePolicy,
|
|
21340
|
+
h.clientEphemeralPublicKey,
|
|
21341
|
+
h.createdLo,
|
|
21342
|
+
h.createdHi,
|
|
21343
|
+
record.holdDurationMs,
|
|
21344
|
+
h.policyVersion,
|
|
21345
|
+
record.ledgerSeq
|
|
21346
|
+
])
|
|
21347
|
+
)
|
|
21348
|
+
);
|
|
21349
|
+
}, "holdDigest");
|
|
21350
|
+
var verifyEscrowHoldRecord = /* @__PURE__ */ __name(async (record, expected, identity, historical) => {
|
|
21351
|
+
requireEvidence(
|
|
21352
|
+
record.hold.holdId === expected.holdId && record.hold.did === expected.did && record.hold.clientEphemeralPublicKey === expected.clientEphemeralPublicKey && record.hold.blobHash === expected.blobHash
|
|
21353
|
+
);
|
|
21354
|
+
let signed;
|
|
21355
|
+
try {
|
|
21356
|
+
signed = JSON.parse(
|
|
21357
|
+
new TextDecoder("utf-8", { fatal: true }).decode(base64(record.hold.signature, 8192))
|
|
21358
|
+
);
|
|
21359
|
+
} catch {
|
|
21360
|
+
return fail2();
|
|
21361
|
+
}
|
|
21362
|
+
const { record: receipt, payload } = await verifyRecord(signed, "commit", identity, historical);
|
|
21363
|
+
const data = object(payload);
|
|
21364
|
+
keys(data, ["commit", "eventHash", "requestDigest", "resultBlobIdentity", "enrollmentEpoch"]);
|
|
21365
|
+
const commit = object(data.commit);
|
|
21366
|
+
keys(commit, ["schemaVersion", "binding", "executionId", "revisions", "transactionDigest"]);
|
|
21367
|
+
const binding = object(commit.binding);
|
|
21368
|
+
keys(binding, ["tenant", "generation", "didHash"]);
|
|
21369
|
+
requireEvidence(commit.schemaVersion === 1 && binding.tenant === expected.tenant);
|
|
21370
|
+
const authorityGeneration = text(binding.generation, 128);
|
|
21371
|
+
if (historical) requireEvidence(authorityGeneration === historical.authorityGeneration);
|
|
21372
|
+
requireEvidence(bytesToHex(bytes2(binding.didHash, 32)) === await hash(utf82(expected.did)));
|
|
21373
|
+
requireEvidence(integer2(data.enrollmentEpoch, 1) === record.hold.enrollmentEpoch);
|
|
21374
|
+
requireEvidence(bytesToHex(bytes2(data.resultBlobIdentity, 32)) === record.hold.blobHash);
|
|
21375
|
+
const digest = await holdDigest(expected.tenant, record);
|
|
21376
|
+
requireEvidence(bytesToHex(bytes2(data.requestDigest, 32)) === digest);
|
|
21377
|
+
return { receipt, authorityGeneration, holdDigest: digest };
|
|
21378
|
+
}, "verifyEscrowHoldRecord");
|
|
21379
|
+
var verifyEscrowHoldConfirmation = /* @__PURE__ */ __name(async (receipt, record, expected, identity) => {
|
|
21380
|
+
const raw = object(receipt);
|
|
21381
|
+
const kind = raw.kind;
|
|
21382
|
+
if (kind !== "commit" && kind !== "snapshot") return fail2();
|
|
21383
|
+
const { record: verified, payload } = await verifyRecord(raw, kind, identity);
|
|
21384
|
+
if (kind === "snapshot") {
|
|
21385
|
+
if (!Array.isArray(payload) || payload.length !== 7) return fail2();
|
|
21386
|
+
const [tag, holdId, digestBytes] = payload;
|
|
21387
|
+
requireEvidence(
|
|
21388
|
+
tag === "learncard-authority-hold-snapshot-v2" && holdId === record.hold.holdId && payload[6] === expected.authorityGeneration
|
|
21389
|
+
);
|
|
21390
|
+
requireEvidence(
|
|
21391
|
+
bytesToHex(bytes2(digestBytes, 32)) === await holdDigest(expected.tenant, record)
|
|
21392
|
+
);
|
|
21393
|
+
requireEvidence(payload[3] === "pending");
|
|
21394
|
+
integer2(payload[4], 1);
|
|
21395
|
+
return verified;
|
|
21396
|
+
}
|
|
21397
|
+
const data = object(payload);
|
|
21398
|
+
keys(data, ["commit", "eventHash", "requestDigest", "resultBlobIdentity", "enrollmentEpoch"]);
|
|
21399
|
+
const commit = object(data.commit);
|
|
21400
|
+
keys(commit, ["schemaVersion", "binding", "executionId", "revisions", "transactionDigest"]);
|
|
21401
|
+
const binding = object(commit.binding);
|
|
21402
|
+
keys(binding, ["tenant", "generation", "didHash"]);
|
|
21403
|
+
requireEvidence(
|
|
21404
|
+
commit.schemaVersion === 1 && binding.tenant === expected.tenant && binding.generation === expected.authorityGeneration
|
|
21405
|
+
);
|
|
21406
|
+
requireEvidence(bytesToHex(bytes2(binding.didHash, 32)) === await hash(utf82(expected.did)));
|
|
21407
|
+
requireEvidence(integer2(data.enrollmentEpoch, 1) === record.hold.enrollmentEpoch);
|
|
21408
|
+
requireEvidence(bytesToHex(bytes2(data.resultBlobIdentity, 32)) === record.hold.blobHash);
|
|
21409
|
+
bytes2(data.requestDigest, 32);
|
|
21410
|
+
return verified;
|
|
21411
|
+
}, "verifyEscrowHoldConfirmation");
|
|
21412
|
+
var resolveEscrowEnrollmentAction = /* @__PURE__ */ __name((current, input) => {
|
|
21413
|
+
const disabling = input === "disable";
|
|
21414
|
+
const pinAction = disabling ? "keep" : input === "set" ? current.hasPin ? "change" : "set" : input === "clear" ? current.hasPin ? "clear" : "keep" : "keep";
|
|
21415
|
+
const action = disabling ? "disable" : current.status !== "active" ? "enroll" : current.hasPin && pinAction === "keep" ? "carry" : "replace";
|
|
21416
|
+
return { action, pinAction, bindsRecoveryContact: action === "enroll" || action === "replace" };
|
|
21417
|
+
}, "resolveEscrowEnrollmentAction");
|
|
21418
|
+
var violatesCarryContactRule = /* @__PURE__ */ __name((action, target) => action === "carry" && !!target && (!!target.recoveryEmail || !!target.recoveryLanguage), "violatesCarryContactRule");
|
|
21419
|
+
var createEscrowEnrollmentIntent = /* @__PURE__ */ __name(async (input) => {
|
|
21420
|
+
const current = state(input.state);
|
|
21421
|
+
const target = input.target === null ? null : envelope(input.target);
|
|
21422
|
+
const disabling = input.pinAction === "disable";
|
|
21423
|
+
requireEvidence(
|
|
21424
|
+
current.enrollmentVersion < Number.MAX_SAFE_INTEGER && (disabling || current.enrollmentEpoch < Number.MAX_SAFE_INTEGER)
|
|
21425
|
+
);
|
|
21426
|
+
if (disabling && current.status !== "active") return fail2();
|
|
21427
|
+
if (current.status === "disabled" && current.hasPin && input.pinAction === "automatic")
|
|
21428
|
+
return fail2();
|
|
21429
|
+
const { action, pinAction, bindsRecoveryContact } = resolveEscrowEnrollmentAction(
|
|
21430
|
+
current,
|
|
21431
|
+
input.pinAction
|
|
21432
|
+
);
|
|
21433
|
+
requireEvidence(!disabling || input.target === null);
|
|
21434
|
+
requireEvidence(disabling || input.target !== null);
|
|
21435
|
+
if (action === "carry") requireEvidence(input.shareVersion > (current.shareVersion ?? 0));
|
|
21436
|
+
const intent = {
|
|
21437
|
+
version: 2,
|
|
21438
|
+
tenant: current.tenant,
|
|
21439
|
+
did: current.did,
|
|
21440
|
+
authorityGeneration: current.authorityGeneration,
|
|
21441
|
+
expectedEnrollmentVersion: current.enrollmentVersion,
|
|
21442
|
+
action,
|
|
21443
|
+
sourceBlobIdentity: current.envelope ? await getEscrowBlobIdentity(current.envelope) : null,
|
|
21444
|
+
targetBlobIdentity: target ? await getEscrowBlobIdentity(target) : null,
|
|
21445
|
+
pinAction,
|
|
21446
|
+
shareVersion: disabling ? current.shareVersion : input.shareVersion,
|
|
21447
|
+
enrollmentEpoch: current.enrollmentEpoch + (disabling ? 0 : 1),
|
|
21448
|
+
requestId: crypto.randomUUID(),
|
|
21449
|
+
allowRewrap: !disabling,
|
|
21450
|
+
recoveryEmail: bindsRecoveryContact ? input.recoveryEmail : null,
|
|
21451
|
+
recoveryLanguage: bindsRecoveryContact ? input.recoveryLanguage : null
|
|
21452
|
+
};
|
|
21453
|
+
return signEscrowEnrollmentIntent(intent, input.privateKey);
|
|
21454
|
+
}, "createEscrowEnrollmentIntent");
|
|
21455
|
+
|
|
20778
21456
|
// src/types.ts
|
|
20779
21457
|
var import_types = __toESM(require_dist());
|
|
20780
21458
|
var EscrowPinUnavailableError = class extends Error {
|
|
@@ -21071,9 +21749,10 @@ var SERVER_REQUEST_TIMEOUT_MS = 3e4;
|
|
|
21071
21749
|
var requestTimeoutSignal = /* @__PURE__ */ __name((ms = SERVER_REQUEST_TIMEOUT_MS) => typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(ms) : void 0, "requestTimeoutSignal");
|
|
21072
21750
|
var describeHttpStatus = /* @__PURE__ */ __name((response) => response.statusText ? `${response.status} ${response.statusText}` : `${response.status}`, "describeHttpStatus");
|
|
21073
21751
|
var EscrowRequestError = class extends Error {
|
|
21074
|
-
constructor(status) {
|
|
21752
|
+
constructor(status, reason) {
|
|
21075
21753
|
super("Escrow request failed");
|
|
21076
21754
|
this.status = status;
|
|
21755
|
+
this.reason = reason;
|
|
21077
21756
|
this.name = "EscrowRequestError";
|
|
21078
21757
|
}
|
|
21079
21758
|
static {
|
|
@@ -21519,6 +22198,10 @@ function createSSSStrategy(config) {
|
|
|
21519
22198
|
const localWrites = /* @__PURE__ */ new Set();
|
|
21520
22199
|
const guardedStorage = /* @__PURE__ */ __name(() => {
|
|
21521
22200
|
const generation = storageGeneration;
|
|
22201
|
+
const assertCurrent = /* @__PURE__ */ __name(() => {
|
|
22202
|
+
if (generation !== storageGeneration)
|
|
22203
|
+
throw new Error("This recovery request was cancelled.");
|
|
22204
|
+
}, "assertCurrent");
|
|
21522
22205
|
const write = /* @__PURE__ */ __name((operation) => {
|
|
21523
22206
|
if (generation !== storageGeneration) {
|
|
21524
22207
|
return Promise.reject(new Error("This recovery request was cancelled."));
|
|
@@ -21529,6 +22212,7 @@ function createSSSStrategy(config) {
|
|
|
21529
22212
|
}, "write");
|
|
21530
22213
|
const guarded = {
|
|
21531
22214
|
...storage,
|
|
22215
|
+
assertCurrent,
|
|
21532
22216
|
storeDeviceShare: /* @__PURE__ */ __name((share, id) => write(() => storage.storeDeviceShare(share, id)), "storeDeviceShare"),
|
|
21533
22217
|
storeShareVersion: /* @__PURE__ */ __name((version, id) => write(() => storage.storeShareVersion(version, id)), "storeShareVersion"),
|
|
21534
22218
|
clearAllShares: /* @__PURE__ */ __name((id) => write(() => storage.clearAllShares(id)), "clearAllShares"),
|
|
@@ -21546,6 +22230,7 @@ function createSSSStrategy(config) {
|
|
|
21546
22230
|
let lastServerSnapshot = null;
|
|
21547
22231
|
let escrowEnrollmentInFlight;
|
|
21548
22232
|
let staleEscrowReenrollAttempted = false;
|
|
22233
|
+
let verifiedEscrowEnvelope;
|
|
21549
22234
|
let unenrolledRotation;
|
|
21550
22235
|
const escrowRequest = /* @__PURE__ */ __name(async (path, init, pinAttempt = false) => {
|
|
21551
22236
|
const response = await fetch(`${serverUrl}/keys/escrow${path}`, {
|
|
@@ -21553,6 +22238,14 @@ function createSSSStrategy(config) {
|
|
|
21553
22238
|
...init
|
|
21554
22239
|
});
|
|
21555
22240
|
if (!response.ok) {
|
|
22241
|
+
if (path === "/confirm" && response.status === 403) {
|
|
22242
|
+
const body = await response.json().catch(() => void 0);
|
|
22243
|
+
const reason = body && typeof body === "object" && "message" in body && typeof body.message === "string" ? body.message : void 0;
|
|
22244
|
+
throw new EscrowRequestError(
|
|
22245
|
+
response.status,
|
|
22246
|
+
reason === "codeMismatch" || reason === "codeExpired" || reason === "codeLocked" ? reason : void 0
|
|
22247
|
+
);
|
|
22248
|
+
}
|
|
21556
22249
|
if (!pinAttempt && path === "/recover" && response.status === 429) {
|
|
21557
22250
|
const body = await response.json().catch(() => void 0);
|
|
21558
22251
|
const message = body && typeof body === "object" && "message" in body && typeof body.message === "string" ? body.message : "";
|
|
@@ -21604,16 +22297,89 @@ function createSSSStrategy(config) {
|
|
|
21604
22297
|
);
|
|
21605
22298
|
return verifyEnclaveAttestation(attestation, config.escrow.attestation, nonce);
|
|
21606
22299
|
}, "fetchVerifiedEnclaveKey");
|
|
21607
|
-
const
|
|
22300
|
+
const fetchEscrowHoldStatus = /* @__PURE__ */ __name(async (params) => {
|
|
22301
|
+
const query = new URLSearchParams(
|
|
22302
|
+
"holdId" in params ? { holdId: params.holdId } : { providerType: params.providerType }
|
|
22303
|
+
);
|
|
22304
|
+
const secret = "holdId" in params ? params.resumeToken : params.token;
|
|
22305
|
+
const result = await escrowRequest(`/status?${query}`, {
|
|
22306
|
+
method: "GET",
|
|
22307
|
+
headers: {
|
|
22308
|
+
...buildHeaders("", void 0, tenantId),
|
|
22309
|
+
"X-Auth-Token": secret
|
|
22310
|
+
}
|
|
22311
|
+
});
|
|
22312
|
+
return result.hold;
|
|
22313
|
+
}, "fetchEscrowHoldStatus");
|
|
22314
|
+
const recoveryExpectations = /* @__PURE__ */ __name((holdId, expected) => {
|
|
22315
|
+
if (!expected || expected.holdId !== holdId || expected.tenant !== (tenantId ?? "learncard") || !expected.did || !expected.clientEphemeralPublicKey || !expected.blobHash || !expected.authorityGeneration || !expected.holdDigest || !expected.ledgerPublicKey || !expected.keyId)
|
|
22316
|
+
throw new EscrowEvidenceError();
|
|
22317
|
+
return { ...expected };
|
|
22318
|
+
}, "recoveryExpectations");
|
|
22319
|
+
const verifyPendingHold = /* @__PURE__ */ __name(async (status, expected, identity) => {
|
|
22320
|
+
if (!config.escrow || identity.mode !== "nitro" || !identity.authority || identity.authority.ledgerPublicKey !== expected.ledgerPublicKey || ![identity.keyId, ...identity.previousKeyIds].includes(expected.keyId) || status.holdId !== expected.holdId || !status.holdRecord)
|
|
22321
|
+
throw new EscrowEvidenceError();
|
|
22322
|
+
const record = status.holdRecord;
|
|
22323
|
+
const verified = await verifyEscrowHoldRecord(record, expected, identity, {
|
|
22324
|
+
historical: true,
|
|
22325
|
+
allowedMeasurements: await escrowAuthorityMeasurements(config.escrow.attestation),
|
|
22326
|
+
authorityGeneration: expected.authorityGeneration
|
|
22327
|
+
});
|
|
22328
|
+
if (verified.holdDigest !== expected.holdDigest || verified.receipt.keyId !== expected.keyId)
|
|
22329
|
+
throw new EscrowEvidenceError();
|
|
22330
|
+
return record;
|
|
22331
|
+
}, "verifyPendingHold");
|
|
22332
|
+
const fetchAuthorityState = /* @__PURE__ */ __name(async (token, providerType, privateKey, did, signer, identity, assertCurrent) => {
|
|
22333
|
+
assertCurrent();
|
|
22334
|
+
if (identity.mode !== "nitro" || !identity.authority)
|
|
22335
|
+
throw new Error("The enclave does not support verified enrollment.");
|
|
22336
|
+
const nonce = Array.from(
|
|
22337
|
+
crypto.getRandomValues(new Uint8Array(32)),
|
|
22338
|
+
(byte) => byte.toString(16).padStart(2, "0")
|
|
22339
|
+
).join("");
|
|
22340
|
+
const vp = await requestFreshDidAuthVp(serverUrl, privateKey, did, signer, tenantId);
|
|
22341
|
+
assertCurrent();
|
|
22342
|
+
const response = await escrowRequest("/authority-state", {
|
|
22343
|
+
method: "POST",
|
|
22344
|
+
headers: buildHeaders(token, vp, tenantId),
|
|
22345
|
+
body: JSON.stringify({ authToken: token, providerType, nonce })
|
|
22346
|
+
});
|
|
22347
|
+
const result = await verifyEscrowAuthorityState(
|
|
22348
|
+
response,
|
|
22349
|
+
nonce,
|
|
22350
|
+
tenantId ?? "learncard",
|
|
22351
|
+
did,
|
|
22352
|
+
identity
|
|
22353
|
+
);
|
|
22354
|
+
assertCurrent();
|
|
22355
|
+
return result;
|
|
22356
|
+
}, "fetchAuthorityState");
|
|
22357
|
+
const enrollEscrow = /* @__PURE__ */ __name(async (token, providerType, privateKey, primaryDid, shares, shareVersion, signDidAuthVp, verifiedKey, pinMaterial, clearPin = false, assertCurrent = guardedStorage().assertCurrent, recoveryEmail = "", recoveryLanguage = "") => {
|
|
21608
22358
|
if (!config.escrow?.enabled) throw new Error("Escrow enrollment is disabled");
|
|
21609
22359
|
if (!signDidAuthVp) throw new Error("DID proof signing is required for escrow enrollment");
|
|
21610
|
-
const
|
|
21611
|
-
|
|
22360
|
+
const identity = verifiedKey ?? await fetchVerifiedEnclaveKey();
|
|
22361
|
+
assertCurrent();
|
|
22362
|
+
const { publicKey, keyId } = identity;
|
|
22363
|
+
const authority = config.escrow.attestation.mode === "nitro" ? await fetchAuthorityState(
|
|
22364
|
+
token,
|
|
22365
|
+
providerType,
|
|
22366
|
+
privateKey,
|
|
22367
|
+
primaryDid,
|
|
22368
|
+
signDidAuthVp,
|
|
22369
|
+
identity,
|
|
22370
|
+
assertCurrent
|
|
22371
|
+
) : void 0;
|
|
22372
|
+
const bindsRecoveryContact = !authority || resolveEscrowEnrollmentAction(
|
|
22373
|
+
authority,
|
|
22374
|
+
pinMaterial ? "set" : clearPin ? "clear" : "automatic"
|
|
22375
|
+
).bindsRecoveryContact;
|
|
22376
|
+
const envelope2 = await encryptEscrowBlob(
|
|
21612
22377
|
{
|
|
21613
22378
|
recoveryShare: shares.recoveryShare,
|
|
21614
22379
|
did: primaryDid,
|
|
21615
22380
|
shareVersion,
|
|
21616
|
-
...pinMaterial ? { pinVerifier: pinMaterial.pinVerifier } : {}
|
|
22381
|
+
...pinMaterial ? { pinVerifier: pinMaterial.pinVerifier } : {},
|
|
22382
|
+
...authority && recoveryEmail && bindsRecoveryContact ? { recoveryEmail, recoveryLanguage } : {}
|
|
21617
22383
|
},
|
|
21618
22384
|
publicKey,
|
|
21619
22385
|
keyId
|
|
@@ -21625,19 +22391,40 @@ function createSSSStrategy(config) {
|
|
|
21625
22391
|
signDidAuthVp,
|
|
21626
22392
|
tenantId
|
|
21627
22393
|
);
|
|
21628
|
-
await
|
|
22394
|
+
const signedIntent = authority ? await createEscrowEnrollmentIntent({
|
|
22395
|
+
state: authority,
|
|
22396
|
+
target: envelope2,
|
|
22397
|
+
shareVersion,
|
|
22398
|
+
privateKey,
|
|
22399
|
+
pinAction: pinMaterial ? "set" : clearPin ? "clear" : "automatic",
|
|
22400
|
+
recoveryEmail,
|
|
22401
|
+
recoveryLanguage
|
|
22402
|
+
}) : void 0;
|
|
22403
|
+
assertCurrent();
|
|
22404
|
+
verifiedEscrowEnvelope = void 0;
|
|
22405
|
+
const response = await escrowRequest("", {
|
|
21629
22406
|
method: "POST",
|
|
21630
22407
|
headers: buildHeaders(token, vp, tenantId),
|
|
21631
22408
|
body: JSON.stringify({
|
|
21632
22409
|
authToken: token,
|
|
21633
22410
|
providerType,
|
|
21634
|
-
envelope,
|
|
22411
|
+
envelope: envelope2,
|
|
21635
22412
|
shareVersion,
|
|
21636
22413
|
enclaveKeyId: keyId,
|
|
21637
22414
|
...pinMaterial ? { pinSalt: pinMaterial.pinSalt } : {},
|
|
21638
|
-
...clearPin ? { clearPin: true } : {}
|
|
22415
|
+
...(signedIntent ? signedIntent.intent.pinAction === "clear" : clearPin) ? { clearPin: true } : {},
|
|
22416
|
+
...signedIntent ? { signedIntent, sourceEnvelope: authority?.envelope ?? null } : {}
|
|
21639
22417
|
})
|
|
21640
22418
|
});
|
|
22419
|
+
if (signedIntent) {
|
|
22420
|
+
const committed = await verifyEscrowEnrollmentCommit(
|
|
22421
|
+
response,
|
|
22422
|
+
signedIntent.intent,
|
|
22423
|
+
identity
|
|
22424
|
+
);
|
|
22425
|
+
assertCurrent();
|
|
22426
|
+
verifiedEscrowEnvelope = committed.envelope ?? void 0;
|
|
22427
|
+
}
|
|
21641
22428
|
}, "enrollEscrow");
|
|
21642
22429
|
const tryEnrollEscrow = /* @__PURE__ */ __name(async (...args) => {
|
|
21643
22430
|
if (!config.escrow?.enabled) return;
|
|
@@ -21652,9 +22439,12 @@ function createSSSStrategy(config) {
|
|
|
21652
22439
|
}
|
|
21653
22440
|
}
|
|
21654
22441
|
}, "tryEnrollEscrow");
|
|
21655
|
-
const ensureEscrowEnrollmentUnguarded = /* @__PURE__ */ __name(async (self, params, storage2, forceRotate = false) => {
|
|
22442
|
+
const ensureEscrowEnrollmentUnguarded = /* @__PURE__ */ __name(async (self, params, storage2, forceRotate = false, allowDisabledEnrollment = false) => {
|
|
22443
|
+
let clearPinForEnrollment = forceRotate;
|
|
21656
22444
|
if (!config.escrow?.enabled) return { enrolled: false, reason: "disabled" };
|
|
21657
22445
|
const pin = params.options?.pin;
|
|
22446
|
+
const recoveryEmail = params.options?.recoveryEmail ?? "";
|
|
22447
|
+
const recoveryLanguage = params.options?.recoveryLanguage ?? "";
|
|
21658
22448
|
if (pin !== void 0) {
|
|
21659
22449
|
const validation = validatePin(pin);
|
|
21660
22450
|
if (!validation.ok)
|
|
@@ -21663,12 +22453,35 @@ function createSSSStrategy(config) {
|
|
|
21663
22453
|
);
|
|
21664
22454
|
}
|
|
21665
22455
|
const status = await self.fetchServerKeyStatus(params.token, params.providerType);
|
|
22456
|
+
storage2.assertCurrent();
|
|
21666
22457
|
if (status.escrowOptedOut) return { enrolled: false, reason: "opted-out" };
|
|
21667
|
-
|
|
22458
|
+
let currentlyEnrolled = status.shareVersion !== null && status.recoveryMethods.some(
|
|
21668
22459
|
(method) => method.type === "escrow" && method.shareVersion === status.shareVersion && (Boolean(method.confirmedAt) || "confirmationStatus" in method && method.confirmationStatus === "confirmed")
|
|
21669
22460
|
);
|
|
21670
|
-
|
|
21671
|
-
if (
|
|
22461
|
+
let verifiedKey;
|
|
22462
|
+
if (config.escrow.attestation.mode === "nitro") {
|
|
22463
|
+
if (!status.primaryDid || !params.signDidAuthVp)
|
|
22464
|
+
throw new Error("Owner proof signing is required for escrow enrollment.");
|
|
22465
|
+
verifiedKey = await fetchVerifiedEnclaveKey();
|
|
22466
|
+
const current = await fetchAuthorityState(
|
|
22467
|
+
params.token,
|
|
22468
|
+
params.providerType,
|
|
22469
|
+
params.privateKey,
|
|
22470
|
+
status.primaryDid,
|
|
22471
|
+
params.signDidAuthVp,
|
|
22472
|
+
verifiedKey,
|
|
22473
|
+
storage2.assertCurrent
|
|
22474
|
+
);
|
|
22475
|
+
if (current.status === "disabled") {
|
|
22476
|
+
verifiedEscrowEnvelope = void 0;
|
|
22477
|
+
if (!allowDisabledEnrollment) return { enrolled: false, reason: "opted-out" };
|
|
22478
|
+
clearPinForEnrollment ||= current.hasPin && pin === void 0;
|
|
22479
|
+
}
|
|
22480
|
+
currentlyEnrolled = currentlyEnrolled && current.status === "active" && current.shareVersion === status.shareVersion && current.envelope?.keyId === verifiedKey.keyId;
|
|
22481
|
+
if (currentlyEnrolled) verifiedEscrowEnvelope = current.envelope ?? void 0;
|
|
22482
|
+
}
|
|
22483
|
+
const repairingStaleBlob = pin === void 0 && !clearPinForEnrollment && currentlyEnrolled && !!status.escrowStale && !staleEscrowReenrollAttempted;
|
|
22484
|
+
if (!clearPinForEnrollment && pin === void 0 && currentlyEnrolled && !repairingStaleBlob)
|
|
21672
22485
|
return { enrolled: true, changed: false };
|
|
21673
22486
|
if (repairingStaleBlob) staleEscrowReenrollAttempted = true;
|
|
21674
22487
|
if (!status.primaryDid) throw new Error("Cannot enroll escrow without a primary DID");
|
|
@@ -21676,7 +22489,7 @@ function createSSSStrategy(config) {
|
|
|
21676
22489
|
throw new Error("DID proof signing is required for escrow enrollment");
|
|
21677
22490
|
}
|
|
21678
22491
|
try {
|
|
21679
|
-
if (!
|
|
22492
|
+
if (!clearPinForEnrollment && pin === void 0 && unenrolledRotation && unenrolledRotation.shareVersion === status.shareVersion && unenrolledRotation.primaryDid === status.primaryDid) {
|
|
21680
22493
|
const retry = unenrolledRotation;
|
|
21681
22494
|
await enrollEscrow(
|
|
21682
22495
|
params.token,
|
|
@@ -21688,12 +22501,16 @@ function createSSSStrategy(config) {
|
|
|
21688
22501
|
params.signDidAuthVp,
|
|
21689
22502
|
void 0,
|
|
21690
22503
|
void 0,
|
|
21691
|
-
retry.clearPin
|
|
22504
|
+
retry.clearPin,
|
|
22505
|
+
storage2.assertCurrent,
|
|
22506
|
+
recoveryEmail,
|
|
22507
|
+
recoveryLanguage
|
|
21692
22508
|
);
|
|
21693
22509
|
unenrolledRotation = void 0;
|
|
21694
22510
|
return { enrolled: true, changed: true, shareVersion: retry.shareVersion };
|
|
21695
22511
|
}
|
|
21696
|
-
|
|
22512
|
+
verifiedKey ??= await fetchVerifiedEnclaveKey();
|
|
22513
|
+
storage2.assertCurrent();
|
|
21697
22514
|
const pinSalt = pin !== void 0 ? generatePinSalt() : void 0;
|
|
21698
22515
|
const pinMaterial = pin !== void 0 && pinSalt !== void 0 ? { pinSalt, pinVerifier: await derivePinProof(pin, pinSalt) } : void 0;
|
|
21699
22516
|
const storageId = activeStorageId;
|
|
@@ -21722,7 +22539,12 @@ function createSSSStrategy(config) {
|
|
|
21722
22539
|
authShare: shares.authShare,
|
|
21723
22540
|
primaryDid: status.primaryDid
|
|
21724
22541
|
};
|
|
21725
|
-
unenrolledRotation = pinMaterial ? void 0 : {
|
|
22542
|
+
unenrolledRotation = pinMaterial ? void 0 : {
|
|
22543
|
+
shares,
|
|
22544
|
+
shareVersion,
|
|
22545
|
+
primaryDid: status.primaryDid,
|
|
22546
|
+
clearPin: clearPinForEnrollment
|
|
22547
|
+
};
|
|
21726
22548
|
await enrollEscrow(
|
|
21727
22549
|
params.token,
|
|
21728
22550
|
params.providerType,
|
|
@@ -21733,12 +22555,15 @@ function createSSSStrategy(config) {
|
|
|
21733
22555
|
params.signDidAuthVp,
|
|
21734
22556
|
verifiedKey,
|
|
21735
22557
|
pinMaterial,
|
|
21736
|
-
|
|
22558
|
+
clearPinForEnrollment,
|
|
22559
|
+
storage2.assertCurrent,
|
|
22560
|
+
recoveryEmail,
|
|
22561
|
+
recoveryLanguage
|
|
21737
22562
|
);
|
|
21738
22563
|
unenrolledRotation = void 0;
|
|
21739
22564
|
return { enrolled: true, changed: true, shareVersion };
|
|
21740
22565
|
} catch (err) {
|
|
21741
|
-
if (!repairingStaleBlob) throw err;
|
|
22566
|
+
if (!repairingStaleBlob || config.escrow.attestation.mode === "nitro") throw err;
|
|
21742
22567
|
try {
|
|
21743
22568
|
if (config.onEscrowError) config.onEscrowError(err);
|
|
21744
22569
|
else console.warn("SSS: escrow enrollment failed");
|
|
@@ -21779,6 +22604,7 @@ function createSSSStrategy(config) {
|
|
|
21779
22604
|
},
|
|
21780
22605
|
// --- User scoping ---
|
|
21781
22606
|
setActiveUser(userId) {
|
|
22607
|
+
verifiedEscrowEnvelope = void 0;
|
|
21782
22608
|
if (activeStorageId !== `sss-device-share:${userId}`) storageGeneration++;
|
|
21783
22609
|
activeStorageId = `sss-device-share:${userId}`;
|
|
21784
22610
|
lastServerSnapshot = null;
|
|
@@ -21823,6 +22649,7 @@ function createSSSStrategy(config) {
|
|
|
21823
22649
|
);
|
|
21824
22650
|
}
|
|
21825
22651
|
storageGeneration++;
|
|
22652
|
+
verifiedEscrowEnvelope = void 0;
|
|
21826
22653
|
await Promise.allSettled(localWrites);
|
|
21827
22654
|
await clearPendingShareCandidates(storage, storageId);
|
|
21828
22655
|
return storage.clearAllShares(storageId);
|
|
@@ -22121,8 +22948,58 @@ function createSSSStrategy(config) {
|
|
|
22121
22948
|
return { state: enrolled ? "enrolled" : "not-enrolled", escrowPin: status.escrowPin };
|
|
22122
22949
|
},
|
|
22123
22950
|
async disableEscrowRecovery(params) {
|
|
22951
|
+
const assertCurrent = guardedStorage().assertCurrent;
|
|
22124
22952
|
const status = await this.fetchServerKeyStatus(params.token, params.providerType);
|
|
22125
22953
|
if (!status.primaryDid) throw new Error("Cannot disable escrow without a primary DID");
|
|
22954
|
+
if (config.escrow?.attestation.mode === "nitro") {
|
|
22955
|
+
const identity = await fetchVerifiedEnclaveKey();
|
|
22956
|
+
const current = await fetchAuthorityState(
|
|
22957
|
+
params.token,
|
|
22958
|
+
params.providerType,
|
|
22959
|
+
params.privateKey,
|
|
22960
|
+
status.primaryDid,
|
|
22961
|
+
params.signDidAuthVp,
|
|
22962
|
+
identity,
|
|
22963
|
+
assertCurrent
|
|
22964
|
+
);
|
|
22965
|
+
if (current.status === "disabled") {
|
|
22966
|
+
verifiedEscrowEnvelope = void 0;
|
|
22967
|
+
return;
|
|
22968
|
+
}
|
|
22969
|
+
const signedIntent = await createEscrowEnrollmentIntent({
|
|
22970
|
+
state: current,
|
|
22971
|
+
target: null,
|
|
22972
|
+
shareVersion: current.shareVersion ?? 0,
|
|
22973
|
+
privateKey: params.privateKey,
|
|
22974
|
+
pinAction: "disable",
|
|
22975
|
+
// Disable always nulls these server-side regardless of input.
|
|
22976
|
+
recoveryEmail: "",
|
|
22977
|
+
recoveryLanguage: ""
|
|
22978
|
+
});
|
|
22979
|
+
const vp2 = await requestFreshDidAuthVp(
|
|
22980
|
+
serverUrl,
|
|
22981
|
+
params.privateKey,
|
|
22982
|
+
status.primaryDid,
|
|
22983
|
+
params.signDidAuthVp,
|
|
22984
|
+
tenantId
|
|
22985
|
+
);
|
|
22986
|
+
assertCurrent();
|
|
22987
|
+
const response = await escrowRequest("/disable", {
|
|
22988
|
+
method: "POST",
|
|
22989
|
+
headers: buildHeaders(params.token, vp2, tenantId),
|
|
22990
|
+
body: JSON.stringify({
|
|
22991
|
+
authToken: params.token,
|
|
22992
|
+
providerType: params.providerType,
|
|
22993
|
+
optOut: true,
|
|
22994
|
+
signedIntent,
|
|
22995
|
+
sourceEnvelope: current.envelope
|
|
22996
|
+
})
|
|
22997
|
+
});
|
|
22998
|
+
await verifyEscrowEnrollmentCommit(response, signedIntent.intent, identity);
|
|
22999
|
+
assertCurrent();
|
|
23000
|
+
verifiedEscrowEnvelope = void 0;
|
|
23001
|
+
return;
|
|
23002
|
+
}
|
|
22126
23003
|
const vp = await requestFreshDidAuthVp(
|
|
22127
23004
|
serverUrl,
|
|
22128
23005
|
params.privateKey,
|
|
@@ -22163,13 +23040,29 @@ function createSSSStrategy(config) {
|
|
|
22163
23040
|
providerType: params.providerType
|
|
22164
23041
|
})
|
|
22165
23042
|
});
|
|
22166
|
-
return ensureEscrowEnrollmentUnguarded(this, params, storage2);
|
|
23043
|
+
return ensureEscrowEnrollmentUnguarded(this, params, storage2, false, true);
|
|
22167
23044
|
});
|
|
22168
23045
|
},
|
|
22169
23046
|
async setEscrowPin({ pin, ...params }) {
|
|
22170
23047
|
const storage2 = guardedStorage();
|
|
22171
23048
|
const result = await withRotationLock(
|
|
22172
|
-
() =>
|
|
23049
|
+
() => (
|
|
23050
|
+
// P9.1: preserve the caller's recoveryEmail/recoveryLanguage — do
|
|
23051
|
+
// not replace `params.options` wholesale, or nitro enroll/replace
|
|
23052
|
+
// loses its required recovery contact.
|
|
23053
|
+
ensureEscrowEnrollmentUnguarded(
|
|
23054
|
+
this,
|
|
23055
|
+
{
|
|
23056
|
+
...params,
|
|
23057
|
+
options: {
|
|
23058
|
+
pin,
|
|
23059
|
+
recoveryEmail: params.options?.recoveryEmail,
|
|
23060
|
+
recoveryLanguage: params.options?.recoveryLanguage
|
|
23061
|
+
}
|
|
23062
|
+
},
|
|
23063
|
+
storage2
|
|
23064
|
+
)
|
|
23065
|
+
)
|
|
22173
23066
|
);
|
|
22174
23067
|
if (!result.enrolled || !result.changed) {
|
|
22175
23068
|
throw new Error("Automatic recovery is not available for this account.");
|
|
@@ -22201,8 +23094,15 @@ function createSSSStrategy(config) {
|
|
|
22201
23094
|
escrowEnrollmentInFlight = void 0;
|
|
22202
23095
|
}
|
|
22203
23096
|
},
|
|
23097
|
+
getVerifiedEscrowEnvelope() {
|
|
23098
|
+
return verifiedEscrowEnvelope ? { ...verifiedEscrowEnvelope } : null;
|
|
23099
|
+
},
|
|
22204
23100
|
/** Start or explicitly restart a hold with fresh client-bound resume secrets. */
|
|
22205
23101
|
async startEscrowRecovery(params) {
|
|
23102
|
+
const expectedDid = params.expectedDid;
|
|
23103
|
+
const nitro = config.escrow?.attestation.mode === "nitro";
|
|
23104
|
+
if (nitro && (!expectedDid || (params.tenantId ?? tenantId) !== tenantId))
|
|
23105
|
+
throw new EscrowEvidenceError();
|
|
22206
23106
|
const sessionProof = params.recoverySessionToken !== void 0;
|
|
22207
23107
|
if (sessionProof ? params.token !== void 0 || params.providerType !== void 0 : !params.token || !params.providerType) {
|
|
22208
23108
|
throw new Error("Provide exactly one identity proof");
|
|
@@ -22222,25 +23122,102 @@ function createSSSStrategy(config) {
|
|
|
22222
23122
|
},
|
|
22223
23123
|
params.options?.releasePolicy === "pin"
|
|
22224
23124
|
);
|
|
22225
|
-
|
|
23125
|
+
let expectations;
|
|
23126
|
+
if (nitro && result.resumeToken !== null) {
|
|
23127
|
+
const identity = await fetchVerifiedEnclaveKey();
|
|
23128
|
+
if (identity.mode !== "nitro" || !identity.authority || !result.holdRecord || !expectedDid)
|
|
23129
|
+
throw new EscrowEvidenceError();
|
|
23130
|
+
const verified = await verifyEscrowHoldRecord(
|
|
23131
|
+
result.holdRecord,
|
|
23132
|
+
{
|
|
23133
|
+
tenant: tenantId ?? "learncard",
|
|
23134
|
+
did: expectedDid,
|
|
23135
|
+
holdId: result.holdId,
|
|
23136
|
+
clientEphemeralPublicKey: pair.publicKey,
|
|
23137
|
+
blobHash: result.holdRecord.hold.blobHash
|
|
23138
|
+
},
|
|
23139
|
+
identity
|
|
23140
|
+
);
|
|
23141
|
+
expectations = {
|
|
23142
|
+
tenant: tenantId ?? "learncard",
|
|
23143
|
+
did: expectedDid,
|
|
23144
|
+
holdId: result.holdId,
|
|
23145
|
+
clientEphemeralPublicKey: pair.publicKey,
|
|
23146
|
+
blobHash: result.holdRecord.hold.blobHash,
|
|
23147
|
+
authorityGeneration: verified.authorityGeneration,
|
|
23148
|
+
holdDigest: verified.holdDigest,
|
|
23149
|
+
ledgerPublicKey: identity.authority.ledgerPublicKey,
|
|
23150
|
+
keyId: verified.receipt.keyId
|
|
23151
|
+
};
|
|
23152
|
+
result.codeSent = result.delivery ? await verifyEscrowCodeDelivery(result.delivery, expectations, identity) : void 0;
|
|
23153
|
+
}
|
|
23154
|
+
return { ...result, clientEphemeralPrivateKey: pair.privateKey, expectations };
|
|
22226
23155
|
},
|
|
22227
23156
|
/** Read hold status; secrets (auth or resume token) never travel in a URL. */
|
|
22228
23157
|
async getEscrowRecoveryStatus(params) {
|
|
22229
|
-
const
|
|
22230
|
-
|
|
22231
|
-
)
|
|
22232
|
-
|
|
22233
|
-
|
|
22234
|
-
|
|
22235
|
-
|
|
22236
|
-
|
|
22237
|
-
|
|
22238
|
-
|
|
22239
|
-
|
|
22240
|
-
|
|
23158
|
+
const expected = config.escrow?.attestation.mode === "nitro" && "holdId" in params ? recoveryExpectations(params.holdId, params.expectations) : void 0;
|
|
23159
|
+
const status = await fetchEscrowHoldStatus(params);
|
|
23160
|
+
if (expected && status)
|
|
23161
|
+
await verifyPendingHold(status, expected, await fetchVerifiedEnclaveKey());
|
|
23162
|
+
return status;
|
|
23163
|
+
},
|
|
23164
|
+
/** Submit the confirmation code emailed by the enclave for an authority-mode hold. */
|
|
23165
|
+
async confirmEscrowRecovery(params) {
|
|
23166
|
+
let pending;
|
|
23167
|
+
if (config.escrow?.attestation.mode === "nitro") {
|
|
23168
|
+
const expected = recoveryExpectations(params.holdId, params.expectations);
|
|
23169
|
+
if ((params.tenantId ?? tenantId) !== tenantId) throw new EscrowEvidenceError();
|
|
23170
|
+
const identity = await fetchVerifiedEnclaveKey();
|
|
23171
|
+
const status = await fetchEscrowHoldStatus({
|
|
23172
|
+
holdId: params.holdId,
|
|
23173
|
+
resumeToken: params.resumeToken
|
|
23174
|
+
});
|
|
23175
|
+
if (!status?.holdRecord) {
|
|
23176
|
+
throw new EscrowEvidenceError();
|
|
22241
23177
|
}
|
|
22242
|
-
|
|
22243
|
-
|
|
23178
|
+
const holdRecord = await verifyPendingHold(status, expected, identity);
|
|
23179
|
+
pending = { identity, holdRecord, expected };
|
|
23180
|
+
}
|
|
23181
|
+
const confirm = /* @__PURE__ */ __name(() => escrowRequest("/confirm", {
|
|
23182
|
+
method: "POST",
|
|
23183
|
+
headers: buildHeaders("", void 0, params.tenantId ?? tenantId),
|
|
23184
|
+
body: JSON.stringify({
|
|
23185
|
+
holdId: params.holdId,
|
|
23186
|
+
resumeToken: params.resumeToken,
|
|
23187
|
+
code: params.code
|
|
23188
|
+
})
|
|
23189
|
+
}), "confirm");
|
|
23190
|
+
const result = await confirm();
|
|
23191
|
+
if (pending) {
|
|
23192
|
+
if (!result.receipt) {
|
|
23193
|
+
throw new EscrowEvidenceError();
|
|
23194
|
+
}
|
|
23195
|
+
const receipt = await verifyEscrowHoldConfirmation(
|
|
23196
|
+
result.receipt,
|
|
23197
|
+
pending.holdRecord,
|
|
23198
|
+
pending.expected,
|
|
23199
|
+
pending.identity
|
|
23200
|
+
);
|
|
23201
|
+
if (receipt.kind === "commit") {
|
|
23202
|
+
const readback = await confirm();
|
|
23203
|
+
const snapshot = await verifyEscrowHoldConfirmation(
|
|
23204
|
+
readback.receipt,
|
|
23205
|
+
pending.holdRecord,
|
|
23206
|
+
pending.expected,
|
|
23207
|
+
pending.identity
|
|
23208
|
+
);
|
|
23209
|
+
if (snapshot.kind !== "snapshot") throw new EscrowEvidenceError();
|
|
23210
|
+
}
|
|
23211
|
+
}
|
|
23212
|
+
return { success: true };
|
|
23213
|
+
},
|
|
23214
|
+
/** Request a fresh confirmation code for a hold awaiting confirmation. */
|
|
23215
|
+
async resendEscrowRecoveryCode(params) {
|
|
23216
|
+
return escrowRequest("/resend", {
|
|
23217
|
+
method: "POST",
|
|
23218
|
+
headers: buildHeaders("", void 0, params.tenantId ?? tenantId),
|
|
23219
|
+
body: JSON.stringify({ holdId: params.holdId, resumeToken: params.resumeToken })
|
|
23220
|
+
});
|
|
22244
23221
|
},
|
|
22245
23222
|
/** Cancel a pending hold with a fresh DID-owner proof. */
|
|
22246
23223
|
async cancelEscrowRecovery(params) {
|
|
@@ -22272,8 +23249,19 @@ function createSSSStrategy(config) {
|
|
|
22272
23249
|
const start = input.method === "escrow-pin" ? await this.startEscrowRecovery({
|
|
22273
23250
|
token,
|
|
22274
23251
|
providerType,
|
|
23252
|
+
expectedDid: input.expectedDid,
|
|
22275
23253
|
options: { releasePolicy: "pin" }
|
|
22276
23254
|
}) : input;
|
|
23255
|
+
const expected = config.escrow?.attestation.mode === "nitro" ? recoveryExpectations(start.holdId, start.expectations) : void 0;
|
|
23256
|
+
if (expected) {
|
|
23257
|
+
if (!start.resumeToken) throw new EscrowEvidenceError();
|
|
23258
|
+
const status = await fetchEscrowHoldStatus({
|
|
23259
|
+
holdId: start.holdId,
|
|
23260
|
+
resumeToken: start.resumeToken
|
|
23261
|
+
});
|
|
23262
|
+
if (!status) throw new EscrowEvidenceError();
|
|
23263
|
+
await verifyPendingHold(status, expected, await fetchVerifiedEnclaveKey());
|
|
23264
|
+
}
|
|
22277
23265
|
let pinProof;
|
|
22278
23266
|
if (input.method === "escrow-pin") {
|
|
22279
23267
|
if (!("pinSalt" in start) || !start.pinSalt || !start.resumeToken)
|
|
@@ -22297,6 +23285,8 @@ function createSSSStrategy(config) {
|
|
|
22297
23285
|
material.sealedShare,
|
|
22298
23286
|
start.clientEphemeralPrivateKey
|
|
22299
23287
|
);
|
|
23288
|
+
if (expected && (plaintext.did !== expected.did || plaintext.holdId !== expected.holdId))
|
|
23289
|
+
throw new EscrowEvidenceError();
|
|
22300
23290
|
if (plaintext.holdId !== start.holdId || plaintext.did !== material.primaryDid || plaintext.shareVersion !== material.shareVersion) {
|
|
22301
23291
|
throw new Error("Escrow recovery material does not match the request");
|
|
22302
23292
|
}
|
|
@@ -22710,10 +23700,10 @@ function createSSSStrategy(config) {
|
|
|
22710
23700
|
const pending = pendingPhraseConfirmation;
|
|
22711
23701
|
if (!pending) throw new Error("Generate a new recovery phrase to continue");
|
|
22712
23702
|
const phraseWords = pending.phrase.trim().toLowerCase().split(/\s+/);
|
|
22713
|
-
const
|
|
23703
|
+
const matches2 = input.challengeWords.length === pending.challengeWordIndices.length && pending.challengeWordIndices.every(
|
|
22714
23704
|
(wordIndex, answerIndex) => input.challengeWords[answerIndex]?.trim().toLowerCase() === phraseWords[wordIndex]
|
|
22715
23705
|
);
|
|
22716
|
-
if (!
|
|
23706
|
+
if (!matches2) {
|
|
22717
23707
|
throw new Error("Those words do not match. Check your phrase and try again.");
|
|
22718
23708
|
}
|
|
22719
23709
|
} else if (input.method === "backup") {
|
|
@@ -23099,6 +24089,7 @@ function createSSSStrategy(config) {
|
|
|
23099
24089
|
},
|
|
23100
24090
|
async cleanup() {
|
|
23101
24091
|
storageGeneration++;
|
|
24092
|
+
verifiedEscrowEnvelope = void 0;
|
|
23102
24093
|
await Promise.allSettled(localWrites);
|
|
23103
24094
|
}
|
|
23104
24095
|
};
|
|
@@ -23329,9 +24320,11 @@ export {
|
|
|
23329
24320
|
ESCROW_ALGORITHM,
|
|
23330
24321
|
ESCROW_BLOB_INFO,
|
|
23331
24322
|
ESCROW_CLIENT_KEY_ID,
|
|
24323
|
+
ESCROW_ENROLLMENT_INTENT_DOMAIN,
|
|
23332
24324
|
ESCROW_ENVELOPE_VERSION,
|
|
23333
24325
|
ESCROW_PIN_MAX_ATTEMPTS,
|
|
23334
24326
|
ESCROW_RELEASE_INFO,
|
|
24327
|
+
EscrowEvidenceError,
|
|
23335
24328
|
EscrowHoldRestartThrottledError,
|
|
23336
24329
|
EscrowPinLockedError,
|
|
23337
24330
|
EscrowPinMismatchError,
|
|
@@ -23359,6 +24352,7 @@ export {
|
|
|
23359
24352
|
constantTimeEqualHex,
|
|
23360
24353
|
countWords,
|
|
23361
24354
|
createAdaptiveStorage,
|
|
24355
|
+
createEscrowEnrollmentIntent,
|
|
23362
24356
|
createPasskeyCredential,
|
|
23363
24357
|
createQrLoginSession,
|
|
23364
24358
|
createSSSKeyManager,
|
|
@@ -23372,6 +24366,7 @@ export {
|
|
|
23372
24366
|
deriveKeyFromPasskey,
|
|
23373
24367
|
deriveKeyFromPassword,
|
|
23374
24368
|
derivePinProof,
|
|
24369
|
+
encodeEscrowEnrollmentIntent,
|
|
23375
24370
|
encryptEmailRelayPayload,
|
|
23376
24371
|
encryptEscrowBlob,
|
|
23377
24372
|
encryptShareForTransfer,
|
|
@@ -23384,6 +24379,7 @@ export {
|
|
|
23384
24379
|
generatePinSalt,
|
|
23385
24380
|
generateRecoveryPhrase,
|
|
23386
24381
|
getDeviceShare,
|
|
24382
|
+
getEscrowBlobIdentity,
|
|
23387
24383
|
getQrLoginSessionInfo,
|
|
23388
24384
|
getShareVersion,
|
|
23389
24385
|
hasDeviceShare,
|
|
@@ -23405,9 +24401,11 @@ export {
|
|
|
23405
24401
|
reconstructFromShares,
|
|
23406
24402
|
reconstructPrivateKey,
|
|
23407
24403
|
recoveryPhraseToShare,
|
|
24404
|
+
resolveEscrowEnrollmentAction,
|
|
23408
24405
|
sealEscrowRelease,
|
|
23409
24406
|
setPublicComputerMode,
|
|
23410
24407
|
shareToRecoveryPhrase,
|
|
24408
|
+
signEscrowEnrollmentIntent,
|
|
23411
24409
|
splitAndVerify,
|
|
23412
24410
|
splitPrivateKey,
|
|
23413
24411
|
storeDeviceShare,
|
|
@@ -23415,6 +24413,11 @@ export {
|
|
|
23415
24413
|
validatePin,
|
|
23416
24414
|
validateRecoveryPhrase,
|
|
23417
24415
|
verifyEnclaveAttestation,
|
|
24416
|
+
verifyEscrowAuthorityState,
|
|
24417
|
+
verifyEscrowCodeDelivery,
|
|
24418
|
+
verifyEscrowEnrollmentCommit,
|
|
24419
|
+
verifyEscrowHoldState,
|
|
23418
24420
|
verifyNitroAttestationDocument,
|
|
23419
|
-
verifyStoredShares
|
|
24421
|
+
verifyStoredShares,
|
|
24422
|
+
violatesCarryContactRule
|
|
23420
24423
|
};
|