@learncard/sss-key-manager 0.2.4 → 0.2.6
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/README.md +15 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/sss-key-manager.cjs.development.js +577 -134
- package/dist/sss-key-manager.cjs.development.js.map +3 -3
- package/dist/sss-key-manager.cjs.production.min.js +32 -32
- package/dist/sss-key-manager.cjs.production.min.js.map +3 -3
- package/dist/sss-key-manager.esm.js +577 -134
- package/dist/sss-key-manager.esm.js.map +3 -3
- package/dist/sss-strategy.d.ts +4 -0
- package/dist/sss-strategy.d.ts.map +1 -1
- package/dist/types.d.ts +11 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/critical-paths.test.ts +20 -24
- package/src/index.ts +3 -0
- package/src/sss-authority.test.ts +294 -1
- package/src/sss-strategy.test.ts +648 -8
- package/src/sss-strategy.ts +804 -159
- package/src/types.ts +20 -1
|
@@ -24025,7 +24025,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
24025
24025
|
state: external_exports.enum(["none", "enabled", "locked", "stale"]),
|
|
24026
24026
|
enabled: external_exports.boolean(),
|
|
24027
24027
|
attemptsRemaining: external_exports.number().int().nonnegative(),
|
|
24028
|
-
salt: external_exports.string().optional()
|
|
24028
|
+
salt: external_exports.string().optional(),
|
|
24029
|
+
/**
|
|
24030
|
+
* Verified wrong PIN entries against the current PIN (successful releases and
|
|
24031
|
+
* unresolved reservations are not counted). Omitted when the server cannot tell,
|
|
24032
|
+
* e.g. legacy records that predate the verified counter.
|
|
24033
|
+
*/
|
|
24034
|
+
wrongAttempts: external_exports.number().int().nonnegative().optional()
|
|
24029
24035
|
});
|
|
24030
24036
|
var BITSTRING_STATUS_PURPOSES = ["revocation", "suspension"];
|
|
24031
24037
|
var DEFAULT_BITSTRING_STATUS_LIST_SIZE = 131072;
|
|
@@ -27532,6 +27538,15 @@ var EscrowPinLockedError = class extends Error {
|
|
|
27532
27538
|
this.name = "EscrowPinLockedError";
|
|
27533
27539
|
}
|
|
27534
27540
|
};
|
|
27541
|
+
var PinSignInStaleError = class extends Error {
|
|
27542
|
+
static {
|
|
27543
|
+
__name(this, "PinSignInStaleError");
|
|
27544
|
+
}
|
|
27545
|
+
constructor() {
|
|
27546
|
+
super("Your account changed while signing in. Try again.");
|
|
27547
|
+
this.name = "PinSignInStaleError";
|
|
27548
|
+
}
|
|
27549
|
+
};
|
|
27535
27550
|
|
|
27536
27551
|
// src/escrow-pin.ts
|
|
27537
27552
|
var PIN_MIN_LENGTH = 6;
|
|
@@ -27790,6 +27805,15 @@ var EscrowRequestError = class extends Error {
|
|
|
27790
27805
|
__name(this, "EscrowRequestError");
|
|
27791
27806
|
}
|
|
27792
27807
|
};
|
|
27808
|
+
var DuplicateShareCoordinateError = class extends Error {
|
|
27809
|
+
static {
|
|
27810
|
+
__name(this, "DuplicateShareCoordinateError");
|
|
27811
|
+
}
|
|
27812
|
+
constructor() {
|
|
27813
|
+
super("Stored shares have the same coordinate and cannot be combined");
|
|
27814
|
+
this.name = "DuplicateShareCoordinateError";
|
|
27815
|
+
}
|
|
27816
|
+
};
|
|
27793
27817
|
var fetchAuthShareRaw = /* @__PURE__ */ __name(async (serverUrl, token, providerType, shareVersion, tenantId) => {
|
|
27794
27818
|
const response = await fetch(`${serverUrl}/keys/auth-share`, {
|
|
27795
27819
|
method: "POST",
|
|
@@ -28385,7 +28409,7 @@ function createSSSStrategy(config) {
|
|
|
28385
28409
|
assertCurrent();
|
|
28386
28410
|
return result;
|
|
28387
28411
|
}, "fetchAuthorityState");
|
|
28388
|
-
const enrollEscrow = /* @__PURE__ */ __name(async (token, providerType, privateKey, primaryDid, shares, shareVersion, signDidAuthVp, verifiedKey, pinMaterial, clearPin = false, assertCurrent = guardedStorage().assertCurrent, recoveryEmail = "", recoveryLanguage = "") => {
|
|
28412
|
+
const enrollEscrow = /* @__PURE__ */ __name(async (token, providerType, privateKey, primaryDid, shares, shareVersion, signDidAuthVp, verifiedKey, pinMaterial, clearPin = false, assertCurrent = guardedStorage().assertCurrent, recoveryEmail = "", recoveryLanguage = "", expectedPinCharges) => {
|
|
28389
28413
|
if (!config.escrow?.enabled) throw new Error("Escrow enrollment is disabled");
|
|
28390
28414
|
if (!signDidAuthVp) throw new Error("DID proof signing is required for escrow enrollment");
|
|
28391
28415
|
const identity = verifiedKey ?? await fetchVerifiedEnclaveKey();
|
|
@@ -28444,7 +28468,8 @@ function createSSSStrategy(config) {
|
|
|
28444
28468
|
enclaveKeyId: keyId,
|
|
28445
28469
|
...pinMaterial ? { pinSalt: pinMaterial.pinSalt } : {},
|
|
28446
28470
|
...(signedIntent ? signedIntent.intent.pinAction === "clear" : clearPin) ? { clearPin: true } : {},
|
|
28447
|
-
...signedIntent ? { signedIntent, sourceEnvelope: authority?.envelope ?? null } : {}
|
|
28471
|
+
...signedIntent ? { signedIntent, sourceEnvelope: authority?.envelope ?? null } : {},
|
|
28472
|
+
...expectedPinCharges ? { expectedPinCharges } : {}
|
|
28448
28473
|
})
|
|
28449
28474
|
});
|
|
28450
28475
|
if (signedIntent) {
|
|
@@ -28457,11 +28482,11 @@ function createSSSStrategy(config) {
|
|
|
28457
28482
|
verifiedEscrowEnvelope = committed.envelope ?? void 0;
|
|
28458
28483
|
}
|
|
28459
28484
|
}, "enrollEscrow");
|
|
28460
|
-
const
|
|
28461
|
-
if (!config.escrow?.enabled) return false;
|
|
28485
|
+
const attemptEnrollEscrow = /* @__PURE__ */ __name(async (...args) => {
|
|
28486
|
+
if (!config.escrow?.enabled) return { enrolled: false };
|
|
28462
28487
|
try {
|
|
28463
28488
|
await enrollEscrow(...args);
|
|
28464
|
-
return true;
|
|
28489
|
+
return { enrolled: true };
|
|
28465
28490
|
} catch (err) {
|
|
28466
28491
|
try {
|
|
28467
28492
|
if (config.onEscrowError) config.onEscrowError(err);
|
|
@@ -28469,9 +28494,10 @@ function createSSSStrategy(config) {
|
|
|
28469
28494
|
} catch {
|
|
28470
28495
|
console.warn("SSS: escrow error reporting failed");
|
|
28471
28496
|
}
|
|
28472
|
-
return false;
|
|
28497
|
+
return { enrolled: false, error: err };
|
|
28473
28498
|
}
|
|
28474
|
-
}, "
|
|
28499
|
+
}, "attemptEnrollEscrow");
|
|
28500
|
+
const tryEnrollEscrow = /* @__PURE__ */ __name(async (...args) => (await attemptEnrollEscrow(...args)).enrolled, "tryEnrollEscrow");
|
|
28475
28501
|
const withAutoClear = /* @__PURE__ */ __name((shareVersion, autoClearedFrom) => {
|
|
28476
28502
|
if (!autoClearedFrom) return { enrolled: true, changed: true, shareVersion };
|
|
28477
28503
|
try {
|
|
@@ -28532,7 +28558,22 @@ function createSSSStrategy(config) {
|
|
|
28532
28558
|
clearPinForEnrollment ||= current.hasPin && pin === void 0;
|
|
28533
28559
|
}
|
|
28534
28560
|
currentlyEnrolled = currentlyEnrolled && current.status === "active" && current.shareVersion === status.shareVersion && current.envelope?.keyId === verifiedKey.keyId;
|
|
28561
|
+
let identityMismatch = false;
|
|
28562
|
+
if (currentlyEnrolled && current.envelope && status.escrowBlobIdentity !== void 0) {
|
|
28563
|
+
const authorityIdentity = await getEscrowBlobIdentity(current.envelope);
|
|
28564
|
+
if (authorityIdentity !== status.escrowBlobIdentity) {
|
|
28565
|
+
const reread = await self.fetchServerKeyStatus(
|
|
28566
|
+
params.token,
|
|
28567
|
+
params.providerType
|
|
28568
|
+
);
|
|
28569
|
+
storage2.assertCurrent();
|
|
28570
|
+
identityMismatch = reread.escrowBlobIdentity !== authorityIdentity && reread.escrowUpdating !== true;
|
|
28571
|
+
}
|
|
28572
|
+
}
|
|
28573
|
+
if (identityMismatch) currentlyEnrolled = false;
|
|
28535
28574
|
if (currentlyEnrolled) verifiedEscrowEnvelope = current.envelope ?? void 0;
|
|
28575
|
+
if (identityMismatch && current.hasPin && pin === void 0 && !clearPinForEnrollment)
|
|
28576
|
+
return { enrolled: false, reason: "pin-reset-required" };
|
|
28536
28577
|
hasPin = current.hasPin;
|
|
28537
28578
|
const uncarryablePin = !clearPinForEnrollment && current.status === "active" && current.hasPin && pin === void 0 && !currentlyEnrolled && status.escrowPin?.state === "none";
|
|
28538
28579
|
if (uncarryablePin && (config.autoClearUncarryablePin ?? DEFAULT_AUTO_CLEAR_UNCARRYABLE_PIN) && current.shareVersion !== null && status.shareVersion !== null && current.shareVersion < status.shareVersion && !status.recoveryMethods.some(
|
|
@@ -28660,6 +28701,378 @@ function createSSSStrategy(config) {
|
|
|
28660
28701
|
}
|
|
28661
28702
|
};
|
|
28662
28703
|
}, "captureActiveUserGuard");
|
|
28704
|
+
const pinHasRecordedWrongAttempts = /* @__PURE__ */ __name((escrowPin) => {
|
|
28705
|
+
const status = escrowPin;
|
|
28706
|
+
if (status?.state === "none") return false;
|
|
28707
|
+
return typeof status?.wrongAttempts !== "number" || status.wrongAttempts > 0;
|
|
28708
|
+
}, "pinHasRecordedWrongAttempts");
|
|
28709
|
+
const refreshablePinCharges = /* @__PURE__ */ __name((before, after) => {
|
|
28710
|
+
const pre = before;
|
|
28711
|
+
const post = after;
|
|
28712
|
+
if (pinHasRecordedWrongAttempts(before) || pinHasRecordedWrongAttempts(after))
|
|
28713
|
+
return void 0;
|
|
28714
|
+
if (pre?.state !== "enabled" || post?.state !== "enabled") return void 0;
|
|
28715
|
+
if (typeof pre.attemptsRemaining !== "number" || typeof post.attemptsRemaining !== "number")
|
|
28716
|
+
return void 0;
|
|
28717
|
+
if (post.attemptsRemaining !== pre.attemptsRemaining - 1) return void 0;
|
|
28718
|
+
return { attemptsRemaining: post.attemptsRemaining, wrongAttempts: 0 };
|
|
28719
|
+
}, "refreshablePinCharges");
|
|
28720
|
+
const freshPinMaterial = /* @__PURE__ */ __name(async (pin) => {
|
|
28721
|
+
if (!validatePin(pin).ok) return void 0;
|
|
28722
|
+
try {
|
|
28723
|
+
const pinSalt = generatePinSalt();
|
|
28724
|
+
return { pinSalt, pinVerifier: await derivePinProof(pin, pinSalt) };
|
|
28725
|
+
} catch {
|
|
28726
|
+
return void 0;
|
|
28727
|
+
}
|
|
28728
|
+
}, "freshPinMaterial");
|
|
28729
|
+
const adoptReleasedShare = /* @__PURE__ */ __name(async (storage2, storageId, released, shareVersion, currentVersion) => {
|
|
28730
|
+
await storage2.storeDeviceShare(released.recoveryShare, storageId);
|
|
28731
|
+
await storage2.storeShareVersion(shareVersion, storageId);
|
|
28732
|
+
lastEmailShare = void 0;
|
|
28733
|
+
lastShareVersion = shareVersion;
|
|
28734
|
+
lastServerSnapshot = {
|
|
28735
|
+
currentVersion,
|
|
28736
|
+
resolvedVersion: shareVersion,
|
|
28737
|
+
authShare: released.authShare,
|
|
28738
|
+
primaryDid: released.primaryDid
|
|
28739
|
+
};
|
|
28740
|
+
}, "adoptReleasedShare");
|
|
28741
|
+
const completePinSignInKeep = /* @__PURE__ */ __name(async (params, released, pin, pinBefore) => {
|
|
28742
|
+
const storage2 = guardedStorage();
|
|
28743
|
+
const generation = storageGeneration;
|
|
28744
|
+
const storageId = activeStorageId;
|
|
28745
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
28746
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
28747
|
+
throw new Error("This recovery request was cancelled.");
|
|
28748
|
+
}
|
|
28749
|
+
}, "assertActive");
|
|
28750
|
+
const { mode, newPinRequired, refreshCharges } = await withShareUpdateLock(
|
|
28751
|
+
storage2,
|
|
28752
|
+
storageId,
|
|
28753
|
+
() => withRotationLock(async () => {
|
|
28754
|
+
assertActive();
|
|
28755
|
+
const current = await fetchAuthShareRaw(
|
|
28756
|
+
serverUrl,
|
|
28757
|
+
params.token,
|
|
28758
|
+
params.providerType,
|
|
28759
|
+
void 0,
|
|
28760
|
+
tenantId
|
|
28761
|
+
);
|
|
28762
|
+
assertActive();
|
|
28763
|
+
if (!current || current.primaryDid !== released.primaryDid || typeof current.shareVersion !== "number") {
|
|
28764
|
+
throw new PinSignInStaleError();
|
|
28765
|
+
}
|
|
28766
|
+
let mode2;
|
|
28767
|
+
if (current.shareVersion === released.shareVersion) {
|
|
28768
|
+
if (authShareToString(current.authShare) !== released.authShare) {
|
|
28769
|
+
throw new PinSignInStaleError();
|
|
28770
|
+
}
|
|
28771
|
+
mode2 = "kept";
|
|
28772
|
+
} else {
|
|
28773
|
+
const historical = current.shareVersion > released.shareVersion ? await fetchAuthShareRaw(
|
|
28774
|
+
serverUrl,
|
|
28775
|
+
params.token,
|
|
28776
|
+
params.providerType,
|
|
28777
|
+
released.shareVersion,
|
|
28778
|
+
tenantId
|
|
28779
|
+
) : null;
|
|
28780
|
+
if (authShareToString(historical?.authShare) !== released.authShare) {
|
|
28781
|
+
throw new PinSignInStaleError();
|
|
28782
|
+
}
|
|
28783
|
+
mode2 = "deferred-rotation";
|
|
28784
|
+
}
|
|
28785
|
+
assertActive();
|
|
28786
|
+
await adoptReleasedShare(
|
|
28787
|
+
storage2,
|
|
28788
|
+
storageId,
|
|
28789
|
+
released,
|
|
28790
|
+
released.shareVersion,
|
|
28791
|
+
current.shareVersion
|
|
28792
|
+
);
|
|
28793
|
+
pendingIdentityRecovery = void 0;
|
|
28794
|
+
return {
|
|
28795
|
+
mode: mode2,
|
|
28796
|
+
newPinRequired: pinHasRecordedWrongAttempts(pinBefore) || pinHasRecordedWrongAttempts(current.escrowPin),
|
|
28797
|
+
refreshCharges: refreshablePinCharges(pinBefore, current.escrowPin)
|
|
28798
|
+
};
|
|
28799
|
+
})
|
|
28800
|
+
);
|
|
28801
|
+
let pinRefreshed = false;
|
|
28802
|
+
let pinRefreshFailed = false;
|
|
28803
|
+
if (mode === "kept" && !newPinRequired && refreshCharges && params.signDidAuthVp) {
|
|
28804
|
+
const pinMaterial = await freshPinMaterial(pin);
|
|
28805
|
+
pinRefreshed = pinMaterial !== void 0 && await tryEnrollEscrow(
|
|
28806
|
+
params.token,
|
|
28807
|
+
params.providerType,
|
|
28808
|
+
released.privateKey,
|
|
28809
|
+
released.primaryDid,
|
|
28810
|
+
{ recoveryShare: released.recoveryShare },
|
|
28811
|
+
released.shareVersion,
|
|
28812
|
+
params.signDidAuthVp,
|
|
28813
|
+
void 0,
|
|
28814
|
+
pinMaterial,
|
|
28815
|
+
false,
|
|
28816
|
+
storage2.assertCurrent,
|
|
28817
|
+
params.options?.recoveryEmail,
|
|
28818
|
+
params.options?.recoveryLanguage,
|
|
28819
|
+
refreshCharges
|
|
28820
|
+
);
|
|
28821
|
+
pinRefreshFailed = pinMaterial !== void 0 && !pinRefreshed;
|
|
28822
|
+
}
|
|
28823
|
+
assertActive();
|
|
28824
|
+
return {
|
|
28825
|
+
privateKey: released.privateKey,
|
|
28826
|
+
did: released.primaryDid,
|
|
28827
|
+
escrowEnrolled: true,
|
|
28828
|
+
escrowRecovery: true,
|
|
28829
|
+
pinSignIn: {
|
|
28830
|
+
mode,
|
|
28831
|
+
pinRefreshed,
|
|
28832
|
+
newPinRequired,
|
|
28833
|
+
...pinRefreshFailed ? { pinRefreshFailed: true } : {}
|
|
28834
|
+
}
|
|
28835
|
+
};
|
|
28836
|
+
}, "completePinSignInKeep");
|
|
28837
|
+
const completePinSignInRelink = /* @__PURE__ */ __name(async (params, pending, signDidAuthVp) => {
|
|
28838
|
+
const storage2 = guardedStorage();
|
|
28839
|
+
const generation = storageGeneration;
|
|
28840
|
+
const storageId = activeStorageId;
|
|
28841
|
+
const shareVersion = pending.pinKeep.shareVersion;
|
|
28842
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
28843
|
+
if (activeStorageId !== storageId || pendingIdentityRecovery !== pending || storageGeneration !== generation) {
|
|
28844
|
+
throw new Error("This recovery request was cancelled.");
|
|
28845
|
+
}
|
|
28846
|
+
}, "assertActive");
|
|
28847
|
+
await withShareUpdateLock(
|
|
28848
|
+
storage2,
|
|
28849
|
+
storageId,
|
|
28850
|
+
() => withRotationLock(async () => {
|
|
28851
|
+
assertActive();
|
|
28852
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
28853
|
+
serverUrl,
|
|
28854
|
+
pending.privateKey,
|
|
28855
|
+
pending.primaryDid,
|
|
28856
|
+
signDidAuthVp,
|
|
28857
|
+
tenantId
|
|
28858
|
+
);
|
|
28859
|
+
assertActive();
|
|
28860
|
+
try {
|
|
28861
|
+
const response = await postJson(
|
|
28862
|
+
`${serverUrl}/keys/recovery-session/pin-sign-in`,
|
|
28863
|
+
{
|
|
28864
|
+
recoverySessionToken: pending.rebindSessionToken,
|
|
28865
|
+
providerType: params.providerType,
|
|
28866
|
+
primaryDid: pending.primaryDid
|
|
28867
|
+
},
|
|
28868
|
+
{
|
|
28869
|
+
...buildHeaders("", didAuthVp, tenantId),
|
|
28870
|
+
"X-Auth-Token": params.token
|
|
28871
|
+
}
|
|
28872
|
+
);
|
|
28873
|
+
if (response.shareVersion !== shareVersion) throw new PinSignInStaleError();
|
|
28874
|
+
} catch (error) {
|
|
28875
|
+
const current = await fetchAuthShareRaw(
|
|
28876
|
+
serverUrl,
|
|
28877
|
+
params.token,
|
|
28878
|
+
params.providerType,
|
|
28879
|
+
void 0,
|
|
28880
|
+
tenantId
|
|
28881
|
+
).catch(() => null);
|
|
28882
|
+
if (!current || current.primaryDid !== pending.primaryDid || current.shareVersion !== shareVersion || authShareToString(current.authShare) !== pending.authShare) {
|
|
28883
|
+
throw error;
|
|
28884
|
+
}
|
|
28885
|
+
}
|
|
28886
|
+
assertActive();
|
|
28887
|
+
await adoptReleasedShare(storage2, storageId, pending, shareVersion, shareVersion);
|
|
28888
|
+
pendingIdentityRecovery = void 0;
|
|
28889
|
+
})
|
|
28890
|
+
);
|
|
28891
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
28892
|
+
throw new Error("This recovery request was cancelled.");
|
|
28893
|
+
}
|
|
28894
|
+
const status = await fetchAuthShareRaw(
|
|
28895
|
+
serverUrl,
|
|
28896
|
+
params.token,
|
|
28897
|
+
params.providerType,
|
|
28898
|
+
void 0,
|
|
28899
|
+
tenantId
|
|
28900
|
+
).catch(() => null);
|
|
28901
|
+
return {
|
|
28902
|
+
privateKey: pending.privateKey,
|
|
28903
|
+
did: pending.primaryDid,
|
|
28904
|
+
escrowEnrolled: true,
|
|
28905
|
+
escrowRecovery: true,
|
|
28906
|
+
pinSignIn: {
|
|
28907
|
+
mode: "relinked",
|
|
28908
|
+
pinRefreshed: false,
|
|
28909
|
+
newPinRequired: pinHasRecordedWrongAttempts(status?.escrowPin)
|
|
28910
|
+
}
|
|
28911
|
+
};
|
|
28912
|
+
}, "completePinSignInRelink");
|
|
28913
|
+
const completeIdentityRecoveryWith = /* @__PURE__ */ __name(async (params) => {
|
|
28914
|
+
const storage2 = guardedStorage();
|
|
28915
|
+
const generation = storageGeneration;
|
|
28916
|
+
const pending = pendingIdentityRecovery;
|
|
28917
|
+
const signDidAuthVp = params.signDidAuthVp;
|
|
28918
|
+
if (!pending) throw new Error("No identity recovery is waiting for a new sign-in");
|
|
28919
|
+
if (!signDidAuthVp) {
|
|
28920
|
+
throw new Error("DID proof signing is required to bind a new sign-in");
|
|
28921
|
+
}
|
|
28922
|
+
if (pending.pinKeep) return completePinSignInRelink(params, pending, signDidAuthVp);
|
|
28923
|
+
const storageId = activeStorageId;
|
|
28924
|
+
const { shares, shareVersion } = await withShareUpdateLock(
|
|
28925
|
+
storage2,
|
|
28926
|
+
storageId,
|
|
28927
|
+
() => withRotationLock(async () => {
|
|
28928
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
28929
|
+
if (activeStorageId !== storageId || pendingIdentityRecovery !== pending || storageGeneration !== generation) {
|
|
28930
|
+
throw new Error("This recovery request was cancelled.");
|
|
28931
|
+
}
|
|
28932
|
+
}, "assertActive");
|
|
28933
|
+
assertActive();
|
|
28934
|
+
const candidates = await readPendingShareCandidates(storage2, storageId);
|
|
28935
|
+
if (pending.rebind && pending.rebind.storageId !== storageId) {
|
|
28936
|
+
throw new Error("Active account changed during identity recovery");
|
|
28937
|
+
}
|
|
28938
|
+
if (candidates.some(
|
|
28939
|
+
(candidate) => candidate.share !== pending.rebind?.shares.deviceShare
|
|
28940
|
+
)) {
|
|
28941
|
+
throw new Error("Reconcile the pending share update before binding a sign-in");
|
|
28942
|
+
}
|
|
28943
|
+
let shareVersion2;
|
|
28944
|
+
const retry = pending.rebind?.attempted ?? false;
|
|
28945
|
+
if (retry && pending.rebind) {
|
|
28946
|
+
const current = await fetchAuthShareRaw(
|
|
28947
|
+
serverUrl,
|
|
28948
|
+
params.token,
|
|
28949
|
+
params.providerType,
|
|
28950
|
+
void 0,
|
|
28951
|
+
tenantId
|
|
28952
|
+
);
|
|
28953
|
+
const authShare = authShareToString(current?.authShare);
|
|
28954
|
+
if (authShare && current?.shareVersion != null) {
|
|
28955
|
+
const health = await verifyStoredShares(
|
|
28956
|
+
{
|
|
28957
|
+
getDevice: /* @__PURE__ */ __name(async () => pending.rebind.shares.deviceShare, "getDevice"),
|
|
28958
|
+
getAuth: /* @__PURE__ */ __name(async () => authShare, "getAuth")
|
|
28959
|
+
},
|
|
28960
|
+
pending.primaryDid,
|
|
28961
|
+
async (key) => key === pending.privateKey ? pending.primaryDid : ""
|
|
28962
|
+
);
|
|
28963
|
+
if (health.healthy) shareVersion2 = current.shareVersion;
|
|
28964
|
+
}
|
|
28965
|
+
}
|
|
28966
|
+
assertActive();
|
|
28967
|
+
if (shareVersion2 === void 0) {
|
|
28968
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
28969
|
+
serverUrl,
|
|
28970
|
+
pending.privateKey,
|
|
28971
|
+
pending.primaryDid,
|
|
28972
|
+
signDidAuthVp,
|
|
28973
|
+
tenantId
|
|
28974
|
+
);
|
|
28975
|
+
assertActive();
|
|
28976
|
+
pending.rebind ??= {
|
|
28977
|
+
shares: (await splitAndVerify(pending.privateKey)).shares,
|
|
28978
|
+
storageId,
|
|
28979
|
+
attempted: false
|
|
28980
|
+
};
|
|
28981
|
+
const rebind = pending.rebind;
|
|
28982
|
+
if (!candidates.some((candidate) => candidate.share === rebind.shares.deviceShare)) {
|
|
28983
|
+
await addPendingShareCandidate(
|
|
28984
|
+
storage2,
|
|
28985
|
+
{ share: rebind.shares.deviceShare, createdAt: Date.now() },
|
|
28986
|
+
storageId
|
|
28987
|
+
);
|
|
28988
|
+
}
|
|
28989
|
+
assertActive();
|
|
28990
|
+
rebind.attempted = true;
|
|
28991
|
+
try {
|
|
28992
|
+
const response = await postJson(
|
|
28993
|
+
`${serverUrl}/keys/recovery-session/rebind`,
|
|
28994
|
+
{
|
|
28995
|
+
recoverySessionToken: pending.rebindSessionToken,
|
|
28996
|
+
providerType: params.providerType,
|
|
28997
|
+
primaryDid: pending.primaryDid,
|
|
28998
|
+
authShare: {
|
|
28999
|
+
encryptedData: rebind.shares.authShare,
|
|
29000
|
+
encryptedDek: "",
|
|
29001
|
+
iv: ""
|
|
29002
|
+
}
|
|
29003
|
+
},
|
|
29004
|
+
{
|
|
29005
|
+
...buildHeaders("", didAuthVp, tenantId),
|
|
29006
|
+
"X-Auth-Token": params.token
|
|
29007
|
+
}
|
|
29008
|
+
);
|
|
29009
|
+
shareVersion2 = response.shareVersion;
|
|
29010
|
+
} catch (error) {
|
|
29011
|
+
if (error instanceof ShareWriteRejectedError && !retry) {
|
|
29012
|
+
await removePendingShareCandidate(
|
|
29013
|
+
storage2,
|
|
29014
|
+
rebind.shares.deviceShare,
|
|
29015
|
+
storageId
|
|
29016
|
+
);
|
|
29017
|
+
pending.rebind = void 0;
|
|
29018
|
+
}
|
|
29019
|
+
throw error;
|
|
29020
|
+
}
|
|
29021
|
+
}
|
|
29022
|
+
if (shareVersion2 === void 0 || !pending.rebind) {
|
|
29023
|
+
throw new Error("Server did not confirm the new share");
|
|
29024
|
+
}
|
|
29025
|
+
assertActive();
|
|
29026
|
+
const shares2 = pending.rebind.shares;
|
|
29027
|
+
await storage2.storeDeviceShare(shares2.deviceShare, storageId);
|
|
29028
|
+
await storage2.storeShareVersion(shareVersion2, storageId);
|
|
29029
|
+
await clearPendingShareCandidates(storage2, storageId);
|
|
29030
|
+
assertActive();
|
|
29031
|
+
lastEmailShare = shares2.emailShare;
|
|
29032
|
+
lastShareVersion = shareVersion2;
|
|
29033
|
+
lastServerSnapshot = {
|
|
29034
|
+
currentVersion: shareVersion2,
|
|
29035
|
+
resolvedVersion: shareVersion2,
|
|
29036
|
+
authShare: shares2.authShare,
|
|
29037
|
+
primaryDid: pending.primaryDid
|
|
29038
|
+
};
|
|
29039
|
+
pendingIdentityRecovery = void 0;
|
|
29040
|
+
return { shares: shares2, shareVersion: shareVersion2 };
|
|
29041
|
+
})
|
|
29042
|
+
);
|
|
29043
|
+
const enrolled = pending.fromEscrow && await tryEnrollEscrow(
|
|
29044
|
+
params.token,
|
|
29045
|
+
params.providerType,
|
|
29046
|
+
pending.privateKey,
|
|
29047
|
+
pending.primaryDid,
|
|
29048
|
+
shares,
|
|
29049
|
+
shareVersion,
|
|
29050
|
+
signDidAuthVp,
|
|
29051
|
+
void 0,
|
|
29052
|
+
void 0,
|
|
29053
|
+
true,
|
|
29054
|
+
storage2.assertCurrent,
|
|
29055
|
+
params.options?.recoveryEmail,
|
|
29056
|
+
params.options?.recoveryLanguage
|
|
29057
|
+
);
|
|
29058
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
29059
|
+
throw new Error("This recovery request was cancelled.");
|
|
29060
|
+
}
|
|
29061
|
+
if (!enrolled) {
|
|
29062
|
+
unenrolledRotation = {
|
|
29063
|
+
shares,
|
|
29064
|
+
shareVersion,
|
|
29065
|
+
primaryDid: pending.primaryDid,
|
|
29066
|
+
clearPin: true
|
|
29067
|
+
};
|
|
29068
|
+
}
|
|
29069
|
+
return {
|
|
29070
|
+
privateKey: pending.privateKey,
|
|
29071
|
+
did: pending.primaryDid,
|
|
29072
|
+
escrowEnrolled: enrolled,
|
|
29073
|
+
escrowRecovery: pending.fromEscrow
|
|
29074
|
+
};
|
|
29075
|
+
}, "completeIdentityRecoveryWith");
|
|
28663
29076
|
return {
|
|
28664
29077
|
name: "sss",
|
|
28665
29078
|
capabilities: {
|
|
@@ -28729,6 +29142,10 @@ function createSSSStrategy(config) {
|
|
|
28729
29142
|
};
|
|
28730
29143
|
},
|
|
28731
29144
|
async reconstructKey(localKey, remoteKey) {
|
|
29145
|
+
const coordinate = localKey.slice(-2).toLowerCase();
|
|
29146
|
+
if (localKey.length === remoteKey.length && /^(?:[0-9a-f]{2}){2,}$/i.test(localKey) && /^(?:[0-9a-f]{2}){2,}$/i.test(remoteKey) && coordinate !== "00" && coordinate === remoteKey.slice(-2).toLowerCase()) {
|
|
29147
|
+
throw new DuplicateShareCoordinateError();
|
|
29148
|
+
}
|
|
28732
29149
|
return reconstructFromShares([localKey, remoteKey]);
|
|
28733
29150
|
},
|
|
28734
29151
|
async verifyKeys(localKey, remoteKey, expectedDid, didFromPrivateKey) {
|
|
@@ -28957,6 +29374,8 @@ function createSSSStrategy(config) {
|
|
|
28957
29374
|
escrowOptedOut: data.escrowOptedOut === true,
|
|
28958
29375
|
escrowPin: data.escrowPin,
|
|
28959
29376
|
escrowStale: data.escrowStale,
|
|
29377
|
+
...typeof data.escrowBlobIdentity === "string" ? { escrowBlobIdentity: data.escrowBlobIdentity } : {},
|
|
29378
|
+
...data.escrowUpdating === true ? { escrowUpdating: true } : {},
|
|
28960
29379
|
sssActivationState: data.sssActivationState ?? "active",
|
|
28961
29380
|
...typeof data.priorEscrowEnrollment === "boolean" ? { priorEscrowEnrollment: data.priorEscrowEnrollment } : {}
|
|
28962
29381
|
};
|
|
@@ -29331,9 +29750,20 @@ function createSSSStrategy(config) {
|
|
|
29331
29750
|
if (input.method === "escrow" || input.method === "escrow-pin") {
|
|
29332
29751
|
if (!didFromPrivateKey)
|
|
29333
29752
|
throw new Error("DID verification is required for escrow recovery");
|
|
29334
|
-
|
|
29753
|
+
if (input.method === "escrow-pin" && !token && !input.recoverySessionToken)
|
|
29754
|
+
throw new Error("PIN recovery requires signing in first.");
|
|
29755
|
+
const pinBefore = input.method === "escrow-pin" && token ? await fetchAuthShareRaw(
|
|
29756
|
+
serverUrl,
|
|
29335
29757
|
token,
|
|
29336
29758
|
providerType,
|
|
29759
|
+
void 0,
|
|
29760
|
+
tenantId
|
|
29761
|
+
).then(
|
|
29762
|
+
(current) => current?.escrowPin,
|
|
29763
|
+
() => void 0
|
|
29764
|
+
) : void 0;
|
|
29765
|
+
const start = input.method === "escrow-pin" ? await this.startEscrowRecovery({
|
|
29766
|
+
...token ? { token, providerType } : { recoverySessionToken: input.recoverySessionToken },
|
|
29337
29767
|
expectedDid: input.expectedDid,
|
|
29338
29768
|
options: { releasePolicy: "pin" }
|
|
29339
29769
|
}) : input;
|
|
@@ -29385,16 +29815,32 @@ function createSSSStrategy(config) {
|
|
|
29385
29815
|
"Recovery produced an incorrect key. Try another recovery method."
|
|
29386
29816
|
);
|
|
29387
29817
|
}
|
|
29818
|
+
if (input.method === "escrow-pin" && token) {
|
|
29819
|
+
return completePinSignInKeep(
|
|
29820
|
+
{ token, providerType, signDidAuthVp, options: params.options },
|
|
29821
|
+
{
|
|
29822
|
+
privateKey: privateKey2,
|
|
29823
|
+
primaryDid: material.primaryDid,
|
|
29824
|
+
recoveryShare: plaintext.recoveryShare,
|
|
29825
|
+
authShare,
|
|
29826
|
+
shareVersion: material.shareVersion
|
|
29827
|
+
},
|
|
29828
|
+
input.pin,
|
|
29829
|
+
pinBefore
|
|
29830
|
+
);
|
|
29831
|
+
}
|
|
29388
29832
|
pendingIdentityRecovery = {
|
|
29389
29833
|
privateKey: privateKey2,
|
|
29390
29834
|
primaryDid: material.primaryDid,
|
|
29391
29835
|
recoveryShare: plaintext.recoveryShare,
|
|
29392
29836
|
authShare,
|
|
29393
29837
|
rebindSessionToken: material.rebindSessionToken,
|
|
29394
|
-
fromEscrow: true
|
|
29838
|
+
fromEscrow: true,
|
|
29839
|
+
// The PIN itself is not kept across the new-login step.
|
|
29840
|
+
...input.method === "escrow-pin" ? { pinKeep: { shareVersion: material.shareVersion } } : {}
|
|
29395
29841
|
};
|
|
29396
29842
|
if (!token) return { privateKey: privateKey2, did: material.primaryDid };
|
|
29397
|
-
return
|
|
29843
|
+
return completeIdentityRecoveryWith({
|
|
29398
29844
|
token,
|
|
29399
29845
|
providerType,
|
|
29400
29846
|
signDidAuthVp,
|
|
@@ -29969,125 +30415,128 @@ function createSSSStrategy(config) {
|
|
|
29969
30415
|
pendingIdentityRecovery = void 0;
|
|
29970
30416
|
},
|
|
29971
30417
|
async completeIdentityRecovery(params) {
|
|
29972
|
-
|
|
29973
|
-
|
|
29974
|
-
|
|
29975
|
-
|
|
29976
|
-
|
|
29977
|
-
|
|
29978
|
-
|
|
30418
|
+
return completeIdentityRecoveryWith(params);
|
|
30419
|
+
},
|
|
30420
|
+
/**
|
|
30421
|
+
* "Secure my account": one atomic server update re-splits the key and drops all
|
|
30422
|
+
* older auth share versions, signing out other devices and turning off the old
|
|
30423
|
+
* phrase/backup/passkey/email key. Staged through the pending-candidate slot, so
|
|
30424
|
+
* a lost acknowledgement is promoted by the usual reconciliation. Escrow is then
|
|
30425
|
+
* re-enrolled with `pin` (fresh salt) or, for `null`, without a PIN. The PIN is
|
|
30426
|
+
* used in this call only and never kept in retry state.
|
|
30427
|
+
*/
|
|
30428
|
+
async revokeOtherDevices(params) {
|
|
30429
|
+
const { token, providerType, privateKey, did, signDidAuthVp, pin } = params;
|
|
30430
|
+
if (!signDidAuthVp) throw new Error("DID proof signing is required");
|
|
30431
|
+
if (pin !== null) {
|
|
30432
|
+
const validation = validatePin(pin);
|
|
30433
|
+
if (!validation.ok)
|
|
30434
|
+
throw new Error(
|
|
30435
|
+
validation.reason === "length" ? "PIN must contain 6\u201312 digits." : "Choose a PIN without trivial or sequential patterns."
|
|
30436
|
+
);
|
|
29979
30437
|
}
|
|
30438
|
+
const storage2 = guardedStorage();
|
|
29980
30439
|
const storageId = activeStorageId;
|
|
30440
|
+
const assertUser = captureActiveUserGuard();
|
|
30441
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
30442
|
+
assertUser();
|
|
30443
|
+
storage2.assertCurrent();
|
|
30444
|
+
}, "assertActive");
|
|
30445
|
+
const before = await fetchAuthShareRaw(
|
|
30446
|
+
serverUrl,
|
|
30447
|
+
token,
|
|
30448
|
+
providerType,
|
|
30449
|
+
void 0,
|
|
30450
|
+
tenantId
|
|
30451
|
+
);
|
|
30452
|
+
if (!before || before.primaryDid !== did) {
|
|
30453
|
+
throw new Error("This account could not be found. Sign in again.");
|
|
30454
|
+
}
|
|
30455
|
+
const hadEscrow = !before.escrowOptedOut && (before.priorEscrowEnrollment === true || Array.isArray(before.recoveryMethods) && before.recoveryMethods.some(
|
|
30456
|
+
(method) => method?.type === "escrow"
|
|
30457
|
+
));
|
|
30458
|
+
const didFromKey = /* @__PURE__ */ __name(async (key) => key === privateKey ? did : `${did}:mismatch`, "didFromKey");
|
|
29981
30459
|
const { shares, shareVersion } = await withShareUpdateLock(
|
|
29982
30460
|
storage2,
|
|
29983
30461
|
storageId,
|
|
29984
30462
|
() => withRotationLock(async () => {
|
|
29985
|
-
const
|
|
29986
|
-
|
|
29987
|
-
|
|
29988
|
-
|
|
29989
|
-
|
|
29990
|
-
|
|
29991
|
-
|
|
29992
|
-
|
|
29993
|
-
|
|
29994
|
-
|
|
29995
|
-
if (candidates.some(
|
|
29996
|
-
(candidate) => candidate.share !== pending.rebind?.shares.deviceShare
|
|
29997
|
-
)) {
|
|
29998
|
-
throw new Error(
|
|
29999
|
-
"Reconcile the pending share update before binding a sign-in"
|
|
30000
|
-
);
|
|
30001
|
-
}
|
|
30002
|
-
let shareVersion2;
|
|
30003
|
-
const retry = pending.rebind?.attempted ?? false;
|
|
30004
|
-
if (retry && pending.rebind) {
|
|
30005
|
-
const current = await fetchAuthShareRaw(
|
|
30006
|
-
serverUrl,
|
|
30007
|
-
params.token,
|
|
30008
|
-
params.providerType,
|
|
30009
|
-
void 0,
|
|
30010
|
-
tenantId
|
|
30011
|
-
);
|
|
30012
|
-
const authShare = authShareToString(current?.authShare);
|
|
30013
|
-
if (authShare && current?.shareVersion != null) {
|
|
30014
|
-
const health = await verifyStoredShares(
|
|
30015
|
-
{
|
|
30016
|
-
getDevice: /* @__PURE__ */ __name(async () => pending.rebind.shares.deviceShare, "getDevice"),
|
|
30017
|
-
getAuth: /* @__PURE__ */ __name(async () => authShare, "getAuth")
|
|
30018
|
-
},
|
|
30019
|
-
pending.primaryDid,
|
|
30020
|
-
async (key) => key === pending.privateKey ? pending.primaryDid : ""
|
|
30463
|
+
const { snapshot } = await resolvePendingShareCandidates(
|
|
30464
|
+
storage2,
|
|
30465
|
+
storageId,
|
|
30466
|
+
async () => {
|
|
30467
|
+
const data = await fetchAuthShareRaw(
|
|
30468
|
+
serverUrl,
|
|
30469
|
+
token,
|
|
30470
|
+
providerType,
|
|
30471
|
+
void 0,
|
|
30472
|
+
tenantId
|
|
30021
30473
|
);
|
|
30022
|
-
|
|
30023
|
-
|
|
30474
|
+
return {
|
|
30475
|
+
currentVersion: data?.shareVersion ?? null,
|
|
30476
|
+
authShare: authShareToString(data?.authShare)
|
|
30477
|
+
};
|
|
30478
|
+
},
|
|
30479
|
+
did,
|
|
30480
|
+
didFromKey,
|
|
30481
|
+
assertActive,
|
|
30482
|
+
recordPromotion(did),
|
|
30483
|
+
async (version) => authShareToString(
|
|
30484
|
+
(await fetchAuthShareRaw(
|
|
30485
|
+
serverUrl,
|
|
30486
|
+
token,
|
|
30487
|
+
providerType,
|
|
30488
|
+
version,
|
|
30489
|
+
tenantId
|
|
30490
|
+
))?.authShare
|
|
30491
|
+
)
|
|
30492
|
+
);
|
|
30493
|
+
if (!snapshot.currentVersion) {
|
|
30494
|
+
throw new Error("This account could not be found. Sign in again.");
|
|
30024
30495
|
}
|
|
30496
|
+
const expectedShareVersion = snapshot.currentVersion;
|
|
30497
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
30498
|
+
serverUrl,
|
|
30499
|
+
privateKey,
|
|
30500
|
+
did,
|
|
30501
|
+
signDidAuthVp,
|
|
30502
|
+
tenantId
|
|
30503
|
+
);
|
|
30025
30504
|
assertActive();
|
|
30026
|
-
|
|
30027
|
-
|
|
30028
|
-
|
|
30029
|
-
|
|
30030
|
-
|
|
30031
|
-
|
|
30032
|
-
tenantId
|
|
30033
|
-
);
|
|
30034
|
-
assertActive();
|
|
30035
|
-
pending.rebind ??= {
|
|
30036
|
-
shares: (await splitAndVerify(pending.privateKey)).shares,
|
|
30037
|
-
storageId,
|
|
30038
|
-
attempted: false
|
|
30039
|
-
};
|
|
30040
|
-
const rebind = pending.rebind;
|
|
30041
|
-
if (!candidates.some(
|
|
30042
|
-
(candidate) => candidate.share === rebind.shares.deviceShare
|
|
30043
|
-
)) {
|
|
30505
|
+
let shareVersion2;
|
|
30506
|
+
let stagedShare = "";
|
|
30507
|
+
const shares2 = await atomicShareUpdate(privateKey, {
|
|
30508
|
+
storeDevice: /* @__PURE__ */ __name(async (share) => {
|
|
30509
|
+
assertActive();
|
|
30510
|
+
stagedShare = share;
|
|
30044
30511
|
await addPendingShareCandidate(
|
|
30045
30512
|
storage2,
|
|
30046
|
-
{ share
|
|
30513
|
+
{ share, createdAt: Date.now() },
|
|
30047
30514
|
storageId
|
|
30048
30515
|
);
|
|
30049
|
-
}
|
|
30050
|
-
|
|
30051
|
-
|
|
30052
|
-
|
|
30516
|
+
}, "storeDevice"),
|
|
30517
|
+
clearDevice: /* @__PURE__ */ __name(() => removePendingShareCandidate(storage2, stagedShare, storageId), "clearDevice"),
|
|
30518
|
+
storeAuth: /* @__PURE__ */ __name(async (share) => {
|
|
30519
|
+
assertActive();
|
|
30053
30520
|
const response = await postJson(
|
|
30054
|
-
`${serverUrl}/keys/
|
|
30521
|
+
`${serverUrl}/keys/revoke-other-devices`,
|
|
30055
30522
|
{
|
|
30056
|
-
|
|
30057
|
-
providerType
|
|
30058
|
-
primaryDid:
|
|
30059
|
-
authShare: {
|
|
30060
|
-
|
|
30061
|
-
encryptedDek: "",
|
|
30062
|
-
iv: ""
|
|
30063
|
-
}
|
|
30523
|
+
authToken: token,
|
|
30524
|
+
providerType,
|
|
30525
|
+
primaryDid: did,
|
|
30526
|
+
authShare: { encryptedData: share, encryptedDek: "", iv: "" },
|
|
30527
|
+
expectedShareVersion
|
|
30064
30528
|
},
|
|
30065
|
-
|
|
30066
|
-
...buildHeaders("", didAuthVp, tenantId),
|
|
30067
|
-
"X-Auth-Token": params.token
|
|
30068
|
-
}
|
|
30529
|
+
buildHeaders(token, didAuthVp, tenantId)
|
|
30069
30530
|
);
|
|
30070
30531
|
shareVersion2 = response.shareVersion;
|
|
30071
|
-
}
|
|
30072
|
-
|
|
30073
|
-
|
|
30074
|
-
|
|
30075
|
-
rebind.shares.deviceShare,
|
|
30076
|
-
storageId
|
|
30077
|
-
);
|
|
30078
|
-
pending.rebind = void 0;
|
|
30079
|
-
}
|
|
30080
|
-
throw error;
|
|
30081
|
-
}
|
|
30082
|
-
}
|
|
30083
|
-
if (shareVersion2 === void 0 || !pending.rebind) {
|
|
30084
|
-
throw new Error("Server did not confirm the new share");
|
|
30532
|
+
}, "storeAuth")
|
|
30533
|
+
});
|
|
30534
|
+
if (shareVersion2 === void 0) {
|
|
30535
|
+
throw new Error("Server did not return a share version");
|
|
30085
30536
|
}
|
|
30086
|
-
assertActive();
|
|
30087
|
-
const shares2 = pending.rebind.shares;
|
|
30088
30537
|
await storage2.storeDeviceShare(shares2.deviceShare, storageId);
|
|
30089
30538
|
await storage2.storeShareVersion(shareVersion2, storageId);
|
|
30090
|
-
await
|
|
30539
|
+
await removePendingShareCandidate(storage2, shares2.deviceShare, storageId);
|
|
30091
30540
|
assertActive();
|
|
30092
30541
|
lastEmailShare = shares2.emailShare;
|
|
30093
30542
|
lastShareVersion = shareVersion2;
|
|
@@ -30095,44 +30544,36 @@ function createSSSStrategy(config) {
|
|
|
30095
30544
|
currentVersion: shareVersion2,
|
|
30096
30545
|
resolvedVersion: shareVersion2,
|
|
30097
30546
|
authShare: shares2.authShare,
|
|
30098
|
-
primaryDid:
|
|
30547
|
+
primaryDid: did
|
|
30099
30548
|
};
|
|
30100
|
-
pendingIdentityRecovery = void 0;
|
|
30101
30549
|
return { shares: shares2, shareVersion: shareVersion2 };
|
|
30102
30550
|
})
|
|
30103
30551
|
);
|
|
30104
|
-
|
|
30105
|
-
|
|
30106
|
-
|
|
30107
|
-
|
|
30108
|
-
|
|
30552
|
+
if (!hadEscrow || !config.escrow?.enabled) {
|
|
30553
|
+
return { shareVersion, escrowEnrolled: false, pinKept: false };
|
|
30554
|
+
}
|
|
30555
|
+
const pinMaterial = pin === null ? void 0 : await freshPinMaterial(pin);
|
|
30556
|
+
const enrollArgs = [
|
|
30557
|
+
token,
|
|
30558
|
+
providerType,
|
|
30559
|
+
privateKey,
|
|
30560
|
+
did,
|
|
30109
30561
|
shares,
|
|
30110
30562
|
shareVersion,
|
|
30111
30563
|
signDidAuthVp,
|
|
30112
30564
|
void 0,
|
|
30113
|
-
|
|
30114
|
-
|
|
30565
|
+
pinMaterial,
|
|
30566
|
+
!pinMaterial,
|
|
30115
30567
|
storage2.assertCurrent,
|
|
30116
30568
|
params.options?.recoveryEmail,
|
|
30117
30569
|
params.options?.recoveryLanguage
|
|
30118
|
-
|
|
30119
|
-
|
|
30120
|
-
|
|
30121
|
-
}
|
|
30570
|
+
];
|
|
30571
|
+
const attempt = await attemptEnrollEscrow(...enrollArgs);
|
|
30572
|
+
const enrolled = attempt.enrolled || attempt.error instanceof EscrowRequestError && attempt.error.status === 403 && await tryEnrollEscrow(...enrollArgs);
|
|
30122
30573
|
if (!enrolled) {
|
|
30123
|
-
unenrolledRotation = {
|
|
30124
|
-
shares,
|
|
30125
|
-
shareVersion,
|
|
30126
|
-
primaryDid: pending.primaryDid,
|
|
30127
|
-
clearPin: true
|
|
30128
|
-
};
|
|
30574
|
+
unenrolledRotation = { shares, shareVersion, primaryDid: did, clearPin: true };
|
|
30129
30575
|
}
|
|
30130
|
-
return {
|
|
30131
|
-
privateKey: pending.privateKey,
|
|
30132
|
-
did: pending.primaryDid,
|
|
30133
|
-
escrowEnrolled: enrolled,
|
|
30134
|
-
escrowRecovery: pending.fromEscrow
|
|
30135
|
-
};
|
|
30576
|
+
return { shareVersion, escrowEnrolled: enrolled, pinKept: enrolled && !!pinMaterial };
|
|
30136
30577
|
},
|
|
30137
30578
|
// --- Contact method management ---
|
|
30138
30579
|
async upgradeContactMethod(token, providerType, previousPhone, email, code) {
|
|
@@ -30423,6 +30864,7 @@ export {
|
|
|
30423
30864
|
AtomicUpdateError,
|
|
30424
30865
|
export_AuthSessionError as AuthSessionError,
|
|
30425
30866
|
DEFAULT_KDF_PARAMS,
|
|
30867
|
+
DuplicateShareCoordinateError,
|
|
30426
30868
|
EMAIL_RELAY_ALGORITHM,
|
|
30427
30869
|
EMAIL_RELAY_ENVELOPE_VERSION,
|
|
30428
30870
|
ESCROW_ALGORITHM,
|
|
@@ -30443,6 +30885,7 @@ export {
|
|
|
30443
30885
|
NitroAttestationError,
|
|
30444
30886
|
PIN_MAX_LENGTH,
|
|
30445
30887
|
PIN_MIN_LENGTH,
|
|
30888
|
+
PinSignInStaleError,
|
|
30446
30889
|
SSSApiClient,
|
|
30447
30890
|
SSSKeyManager,
|
|
30448
30891
|
SSS_THRESHOLD,
|