@learncard/sss-key-manager 0.2.5 → 0.2.7
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/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/sss-key-manager.cjs.development.js +603 -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 +603 -134
- package/dist/sss-key-manager.esm.js.map +3 -3
- package/dist/sss-strategy.d.ts.map +1 -1
- package/dist/types.d.ts +39 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +8 -1
- package/src/sss-authority.test.ts +294 -1
- package/src/sss-strategy.test.ts +875 -8
- package/src/sss-strategy.ts +869 -159
- package/src/types.ts +49 -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,7 @@ var EscrowRequestError = class extends Error {
|
|
|
27790
27805
|
__name(this, "EscrowRequestError");
|
|
27791
27806
|
}
|
|
27792
27807
|
};
|
|
27808
|
+
var isConflictRefusal = /* @__PURE__ */ __name((error) => error instanceof EscrowRequestError && error.status === 409, "isConflictRefusal");
|
|
27793
27809
|
var DuplicateShareCoordinateError = class extends Error {
|
|
27794
27810
|
static {
|
|
27795
27811
|
__name(this, "DuplicateShareCoordinateError");
|
|
@@ -28394,7 +28410,7 @@ function createSSSStrategy(config) {
|
|
|
28394
28410
|
assertCurrent();
|
|
28395
28411
|
return result;
|
|
28396
28412
|
}, "fetchAuthorityState");
|
|
28397
|
-
const enrollEscrow = /* @__PURE__ */ __name(async (token, providerType, privateKey, primaryDid, shares, shareVersion, signDidAuthVp, verifiedKey, pinMaterial, clearPin = false, assertCurrent = guardedStorage().assertCurrent, recoveryEmail = "", recoveryLanguage = "") => {
|
|
28413
|
+
const enrollEscrow = /* @__PURE__ */ __name(async (token, providerType, privateKey, primaryDid, shares, shareVersion, signDidAuthVp, verifiedKey, pinMaterial, clearPin = false, assertCurrent = guardedStorage().assertCurrent, recoveryEmail = "", recoveryLanguage = "", expectedPinCharges) => {
|
|
28398
28414
|
if (!config.escrow?.enabled) throw new Error("Escrow enrollment is disabled");
|
|
28399
28415
|
if (!signDidAuthVp) throw new Error("DID proof signing is required for escrow enrollment");
|
|
28400
28416
|
const identity = verifiedKey ?? await fetchVerifiedEnclaveKey();
|
|
@@ -28453,7 +28469,8 @@ function createSSSStrategy(config) {
|
|
|
28453
28469
|
enclaveKeyId: keyId,
|
|
28454
28470
|
...pinMaterial ? { pinSalt: pinMaterial.pinSalt } : {},
|
|
28455
28471
|
...(signedIntent ? signedIntent.intent.pinAction === "clear" : clearPin) ? { clearPin: true } : {},
|
|
28456
|
-
...signedIntent ? { signedIntent, sourceEnvelope: authority?.envelope ?? null } : {}
|
|
28472
|
+
...signedIntent ? { signedIntent, sourceEnvelope: authority?.envelope ?? null } : {},
|
|
28473
|
+
...expectedPinCharges ? { expectedPinCharges } : {}
|
|
28457
28474
|
})
|
|
28458
28475
|
});
|
|
28459
28476
|
if (signedIntent) {
|
|
@@ -28466,11 +28483,11 @@ function createSSSStrategy(config) {
|
|
|
28466
28483
|
verifiedEscrowEnvelope = committed.envelope ?? void 0;
|
|
28467
28484
|
}
|
|
28468
28485
|
}, "enrollEscrow");
|
|
28469
|
-
const
|
|
28470
|
-
if (!config.escrow?.enabled) return false;
|
|
28486
|
+
const attemptEnrollEscrow = /* @__PURE__ */ __name(async (...args) => {
|
|
28487
|
+
if (!config.escrow?.enabled) return { enrolled: false };
|
|
28471
28488
|
try {
|
|
28472
28489
|
await enrollEscrow(...args);
|
|
28473
|
-
return true;
|
|
28490
|
+
return { enrolled: true };
|
|
28474
28491
|
} catch (err) {
|
|
28475
28492
|
try {
|
|
28476
28493
|
if (config.onEscrowError) config.onEscrowError(err);
|
|
@@ -28478,9 +28495,10 @@ function createSSSStrategy(config) {
|
|
|
28478
28495
|
} catch {
|
|
28479
28496
|
console.warn("SSS: escrow error reporting failed");
|
|
28480
28497
|
}
|
|
28481
|
-
return false;
|
|
28498
|
+
return { enrolled: false, error: err };
|
|
28482
28499
|
}
|
|
28483
|
-
}, "
|
|
28500
|
+
}, "attemptEnrollEscrow");
|
|
28501
|
+
const tryEnrollEscrow = /* @__PURE__ */ __name(async (...args) => (await attemptEnrollEscrow(...args)).enrolled, "tryEnrollEscrow");
|
|
28484
28502
|
const withAutoClear = /* @__PURE__ */ __name((shareVersion, autoClearedFrom) => {
|
|
28485
28503
|
if (!autoClearedFrom) return { enrolled: true, changed: true, shareVersion };
|
|
28486
28504
|
try {
|
|
@@ -28541,7 +28559,22 @@ function createSSSStrategy(config) {
|
|
|
28541
28559
|
clearPinForEnrollment ||= current.hasPin && pin === void 0;
|
|
28542
28560
|
}
|
|
28543
28561
|
currentlyEnrolled = currentlyEnrolled && current.status === "active" && current.shareVersion === status.shareVersion && current.envelope?.keyId === verifiedKey.keyId;
|
|
28562
|
+
let identityMismatch = false;
|
|
28563
|
+
if (currentlyEnrolled && current.envelope && status.escrowBlobIdentity !== void 0) {
|
|
28564
|
+
const authorityIdentity = await getEscrowBlobIdentity(current.envelope);
|
|
28565
|
+
if (authorityIdentity !== status.escrowBlobIdentity) {
|
|
28566
|
+
const reread = await self.fetchServerKeyStatus(
|
|
28567
|
+
params.token,
|
|
28568
|
+
params.providerType
|
|
28569
|
+
);
|
|
28570
|
+
storage2.assertCurrent();
|
|
28571
|
+
identityMismatch = reread.escrowBlobIdentity !== authorityIdentity && reread.escrowUpdating !== true;
|
|
28572
|
+
}
|
|
28573
|
+
}
|
|
28574
|
+
if (identityMismatch) currentlyEnrolled = false;
|
|
28544
28575
|
if (currentlyEnrolled) verifiedEscrowEnvelope = current.envelope ?? void 0;
|
|
28576
|
+
if (identityMismatch && current.hasPin && pin === void 0 && !clearPinForEnrollment)
|
|
28577
|
+
return { enrolled: false, reason: "pin-reset-required" };
|
|
28545
28578
|
hasPin = current.hasPin;
|
|
28546
28579
|
const uncarryablePin = !clearPinForEnrollment && current.status === "active" && current.hasPin && pin === void 0 && !currentlyEnrolled && status.escrowPin?.state === "none";
|
|
28547
28580
|
if (uncarryablePin && (config.autoClearUncarryablePin ?? DEFAULT_AUTO_CLEAR_UNCARRYABLE_PIN) && current.shareVersion !== null && status.shareVersion !== null && current.shareVersion < status.shareVersion && !status.recoveryMethods.some(
|
|
@@ -28669,6 +28702,411 @@ function createSSSStrategy(config) {
|
|
|
28669
28702
|
}
|
|
28670
28703
|
};
|
|
28671
28704
|
}, "captureActiveUserGuard");
|
|
28705
|
+
const recordedWrongPinAttempts = /* @__PURE__ */ __name((escrowPin) => {
|
|
28706
|
+
const status = escrowPin;
|
|
28707
|
+
if (status?.state === "none") return 0;
|
|
28708
|
+
const count = status?.wrongAttempts;
|
|
28709
|
+
return typeof count === "number" && Number.isSafeInteger(count) && count >= 0 ? count : void 0;
|
|
28710
|
+
}, "recordedWrongPinAttempts");
|
|
28711
|
+
const attemptCount = /* @__PURE__ */ __name((value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0, "attemptCount");
|
|
28712
|
+
const pinSignInClean = /* @__PURE__ */ __name((observed, flowAttempts) => {
|
|
28713
|
+
const flowSalt = flowAttempts?.pinSalt;
|
|
28714
|
+
const sameGeneration = typeof flowSalt !== "string" || observed.every((status) => {
|
|
28715
|
+
const salt = status?.salt;
|
|
28716
|
+
return typeof salt !== "string" || salt === flowSalt;
|
|
28717
|
+
});
|
|
28718
|
+
const attempts = sameGeneration ? flowAttempts : void 0;
|
|
28719
|
+
const own = attempts ? attemptCount(attempts.ownWrongAttempts) : 0;
|
|
28720
|
+
if (own === void 0) return { clean: false, ownWrongAttempts: 0 };
|
|
28721
|
+
const prior = attempts ? attemptCount(attempts.priorWrongAttempts) : recordedWrongPinAttempts(observed[0]);
|
|
28722
|
+
const clean = prior === 0 && observed.length > 0 && observed.every((status) => recordedWrongPinAttempts(status) === own);
|
|
28723
|
+
return { clean, ownWrongAttempts: own };
|
|
28724
|
+
}, "pinSignInClean");
|
|
28725
|
+
const refreshablePinCharges = /* @__PURE__ */ __name((before, after, ownWrongAttempts) => {
|
|
28726
|
+
const pre = before;
|
|
28727
|
+
const post = after;
|
|
28728
|
+
if (pre?.state !== "enabled" || post?.state !== "enabled") return void 0;
|
|
28729
|
+
if (typeof pre.attemptsRemaining !== "number" || typeof post.attemptsRemaining !== "number")
|
|
28730
|
+
return void 0;
|
|
28731
|
+
if (post.attemptsRemaining !== pre.attemptsRemaining - 1) return void 0;
|
|
28732
|
+
return { attemptsRemaining: post.attemptsRemaining, wrongAttempts: ownWrongAttempts };
|
|
28733
|
+
}, "refreshablePinCharges");
|
|
28734
|
+
const freshPinMaterial = /* @__PURE__ */ __name(async (pin) => {
|
|
28735
|
+
if (!validatePin(pin).ok) return void 0;
|
|
28736
|
+
try {
|
|
28737
|
+
const pinSalt = generatePinSalt();
|
|
28738
|
+
return { pinSalt, pinVerifier: await derivePinProof(pin, pinSalt) };
|
|
28739
|
+
} catch {
|
|
28740
|
+
return void 0;
|
|
28741
|
+
}
|
|
28742
|
+
}, "freshPinMaterial");
|
|
28743
|
+
const adoptReleasedShare = /* @__PURE__ */ __name(async (storage2, storageId, released, shareVersion, currentVersion) => {
|
|
28744
|
+
await storage2.storeDeviceShare(released.recoveryShare, storageId);
|
|
28745
|
+
await storage2.storeShareVersion(shareVersion, storageId);
|
|
28746
|
+
lastEmailShare = void 0;
|
|
28747
|
+
lastShareVersion = shareVersion;
|
|
28748
|
+
lastServerSnapshot = {
|
|
28749
|
+
currentVersion,
|
|
28750
|
+
resolvedVersion: shareVersion,
|
|
28751
|
+
authShare: released.authShare,
|
|
28752
|
+
primaryDid: released.primaryDid
|
|
28753
|
+
};
|
|
28754
|
+
}, "adoptReleasedShare");
|
|
28755
|
+
const completePinSignInKeep = /* @__PURE__ */ __name(async (params, released, pin, pinBefore, pinAttempts) => {
|
|
28756
|
+
const storage2 = guardedStorage();
|
|
28757
|
+
const generation = storageGeneration;
|
|
28758
|
+
const storageId = activeStorageId;
|
|
28759
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
28760
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
28761
|
+
throw new Error("This recovery request was cancelled.");
|
|
28762
|
+
}
|
|
28763
|
+
}, "assertActive");
|
|
28764
|
+
const {
|
|
28765
|
+
mode,
|
|
28766
|
+
newPinRequired: newPinRequiredAtRelease,
|
|
28767
|
+
refreshCharges
|
|
28768
|
+
} = await withShareUpdateLock(
|
|
28769
|
+
storage2,
|
|
28770
|
+
storageId,
|
|
28771
|
+
() => withRotationLock(async () => {
|
|
28772
|
+
assertActive();
|
|
28773
|
+
const current = await fetchAuthShareRaw(
|
|
28774
|
+
serverUrl,
|
|
28775
|
+
params.token,
|
|
28776
|
+
params.providerType,
|
|
28777
|
+
void 0,
|
|
28778
|
+
tenantId
|
|
28779
|
+
);
|
|
28780
|
+
assertActive();
|
|
28781
|
+
if (!current || current.primaryDid !== released.primaryDid || typeof current.shareVersion !== "number") {
|
|
28782
|
+
throw new PinSignInStaleError();
|
|
28783
|
+
}
|
|
28784
|
+
let mode2;
|
|
28785
|
+
if (current.shareVersion === released.shareVersion) {
|
|
28786
|
+
if (authShareToString(current.authShare) !== released.authShare) {
|
|
28787
|
+
throw new PinSignInStaleError();
|
|
28788
|
+
}
|
|
28789
|
+
mode2 = "kept";
|
|
28790
|
+
} else {
|
|
28791
|
+
const historical = current.shareVersion > released.shareVersion ? await fetchAuthShareRaw(
|
|
28792
|
+
serverUrl,
|
|
28793
|
+
params.token,
|
|
28794
|
+
params.providerType,
|
|
28795
|
+
released.shareVersion,
|
|
28796
|
+
tenantId
|
|
28797
|
+
) : null;
|
|
28798
|
+
if (authShareToString(historical?.authShare) !== released.authShare) {
|
|
28799
|
+
throw new PinSignInStaleError();
|
|
28800
|
+
}
|
|
28801
|
+
mode2 = "deferred-rotation";
|
|
28802
|
+
}
|
|
28803
|
+
assertActive();
|
|
28804
|
+
await adoptReleasedShare(
|
|
28805
|
+
storage2,
|
|
28806
|
+
storageId,
|
|
28807
|
+
released,
|
|
28808
|
+
released.shareVersion,
|
|
28809
|
+
current.shareVersion
|
|
28810
|
+
);
|
|
28811
|
+
pendingIdentityRecovery = void 0;
|
|
28812
|
+
const { clean, ownWrongAttempts } = pinSignInClean(
|
|
28813
|
+
[pinBefore, current.escrowPin],
|
|
28814
|
+
pinAttempts
|
|
28815
|
+
);
|
|
28816
|
+
return {
|
|
28817
|
+
mode: mode2,
|
|
28818
|
+
newPinRequired: !clean,
|
|
28819
|
+
refreshCharges: clean ? refreshablePinCharges(pinBefore, current.escrowPin, ownWrongAttempts) : void 0
|
|
28820
|
+
};
|
|
28821
|
+
})
|
|
28822
|
+
);
|
|
28823
|
+
let pinRefreshed = false;
|
|
28824
|
+
let pinRefreshFailed = false;
|
|
28825
|
+
let newPinRequired = newPinRequiredAtRelease;
|
|
28826
|
+
if (mode === "kept" && !newPinRequired && refreshCharges && params.signDidAuthVp) {
|
|
28827
|
+
const pinMaterial = await freshPinMaterial(pin);
|
|
28828
|
+
const refresh = pinMaterial === void 0 ? void 0 : await attemptEnrollEscrow(
|
|
28829
|
+
params.token,
|
|
28830
|
+
params.providerType,
|
|
28831
|
+
released.privateKey,
|
|
28832
|
+
released.primaryDid,
|
|
28833
|
+
{ recoveryShare: released.recoveryShare },
|
|
28834
|
+
released.shareVersion,
|
|
28835
|
+
params.signDidAuthVp,
|
|
28836
|
+
void 0,
|
|
28837
|
+
pinMaterial,
|
|
28838
|
+
false,
|
|
28839
|
+
storage2.assertCurrent,
|
|
28840
|
+
params.options?.recoveryEmail,
|
|
28841
|
+
params.options?.recoveryLanguage,
|
|
28842
|
+
refreshCharges
|
|
28843
|
+
);
|
|
28844
|
+
pinRefreshed = refresh?.enrolled === true;
|
|
28845
|
+
pinRefreshFailed = pinMaterial !== void 0 && !pinRefreshed;
|
|
28846
|
+
if (pinRefreshFailed) {
|
|
28847
|
+
const latest = await fetchAuthShareRaw(
|
|
28848
|
+
serverUrl,
|
|
28849
|
+
params.token,
|
|
28850
|
+
params.providerType,
|
|
28851
|
+
void 0,
|
|
28852
|
+
tenantId
|
|
28853
|
+
).catch(() => void 0);
|
|
28854
|
+
newPinRequired = latest ? !pinSignInClean([pinBefore, latest.escrowPin], pinAttempts).clean : isConflictRefusal(refresh && !refresh.enrolled ? refresh.error : void 0);
|
|
28855
|
+
}
|
|
28856
|
+
}
|
|
28857
|
+
assertActive();
|
|
28858
|
+
return {
|
|
28859
|
+
privateKey: released.privateKey,
|
|
28860
|
+
did: released.primaryDid,
|
|
28861
|
+
escrowEnrolled: true,
|
|
28862
|
+
escrowRecovery: true,
|
|
28863
|
+
pinSignIn: {
|
|
28864
|
+
mode,
|
|
28865
|
+
pinRefreshed,
|
|
28866
|
+
newPinRequired,
|
|
28867
|
+
...pinRefreshFailed ? { pinRefreshFailed: true } : {}
|
|
28868
|
+
}
|
|
28869
|
+
};
|
|
28870
|
+
}, "completePinSignInKeep");
|
|
28871
|
+
const completePinSignInRelink = /* @__PURE__ */ __name(async (params, pending, signDidAuthVp) => {
|
|
28872
|
+
const storage2 = guardedStorage();
|
|
28873
|
+
const generation = storageGeneration;
|
|
28874
|
+
const storageId = activeStorageId;
|
|
28875
|
+
const shareVersion = pending.pinKeep.shareVersion;
|
|
28876
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
28877
|
+
if (activeStorageId !== storageId || pendingIdentityRecovery !== pending || storageGeneration !== generation) {
|
|
28878
|
+
throw new Error("This recovery request was cancelled.");
|
|
28879
|
+
}
|
|
28880
|
+
}, "assertActive");
|
|
28881
|
+
await withShareUpdateLock(
|
|
28882
|
+
storage2,
|
|
28883
|
+
storageId,
|
|
28884
|
+
() => withRotationLock(async () => {
|
|
28885
|
+
assertActive();
|
|
28886
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
28887
|
+
serverUrl,
|
|
28888
|
+
pending.privateKey,
|
|
28889
|
+
pending.primaryDid,
|
|
28890
|
+
signDidAuthVp,
|
|
28891
|
+
tenantId
|
|
28892
|
+
);
|
|
28893
|
+
assertActive();
|
|
28894
|
+
try {
|
|
28895
|
+
const response = await postJson(
|
|
28896
|
+
`${serverUrl}/keys/recovery-session/pin-sign-in`,
|
|
28897
|
+
{
|
|
28898
|
+
recoverySessionToken: pending.rebindSessionToken,
|
|
28899
|
+
providerType: params.providerType,
|
|
28900
|
+
primaryDid: pending.primaryDid
|
|
28901
|
+
},
|
|
28902
|
+
{
|
|
28903
|
+
...buildHeaders("", didAuthVp, tenantId),
|
|
28904
|
+
"X-Auth-Token": params.token
|
|
28905
|
+
}
|
|
28906
|
+
);
|
|
28907
|
+
if (response.shareVersion !== shareVersion) throw new PinSignInStaleError();
|
|
28908
|
+
} catch (error) {
|
|
28909
|
+
const current = await fetchAuthShareRaw(
|
|
28910
|
+
serverUrl,
|
|
28911
|
+
params.token,
|
|
28912
|
+
params.providerType,
|
|
28913
|
+
void 0,
|
|
28914
|
+
tenantId
|
|
28915
|
+
).catch(() => null);
|
|
28916
|
+
if (!current || current.primaryDid !== pending.primaryDid || current.shareVersion !== shareVersion || authShareToString(current.authShare) !== pending.authShare) {
|
|
28917
|
+
throw error;
|
|
28918
|
+
}
|
|
28919
|
+
}
|
|
28920
|
+
assertActive();
|
|
28921
|
+
await adoptReleasedShare(storage2, storageId, pending, shareVersion, shareVersion);
|
|
28922
|
+
pendingIdentityRecovery = void 0;
|
|
28923
|
+
})
|
|
28924
|
+
);
|
|
28925
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
28926
|
+
throw new Error("This recovery request was cancelled.");
|
|
28927
|
+
}
|
|
28928
|
+
const status = await fetchAuthShareRaw(
|
|
28929
|
+
serverUrl,
|
|
28930
|
+
params.token,
|
|
28931
|
+
params.providerType,
|
|
28932
|
+
void 0,
|
|
28933
|
+
tenantId
|
|
28934
|
+
).catch(() => null);
|
|
28935
|
+
return {
|
|
28936
|
+
privateKey: pending.privateKey,
|
|
28937
|
+
did: pending.primaryDid,
|
|
28938
|
+
escrowEnrolled: true,
|
|
28939
|
+
escrowRecovery: true,
|
|
28940
|
+
pinSignIn: {
|
|
28941
|
+
mode: "relinked",
|
|
28942
|
+
pinRefreshed: false,
|
|
28943
|
+
newPinRequired: !pinSignInClean([status?.escrowPin], pending.pinKeep?.pinAttempts).clean
|
|
28944
|
+
}
|
|
28945
|
+
};
|
|
28946
|
+
}, "completePinSignInRelink");
|
|
28947
|
+
const completeIdentityRecoveryWith = /* @__PURE__ */ __name(async (params) => {
|
|
28948
|
+
const storage2 = guardedStorage();
|
|
28949
|
+
const generation = storageGeneration;
|
|
28950
|
+
const pending = pendingIdentityRecovery;
|
|
28951
|
+
const signDidAuthVp = params.signDidAuthVp;
|
|
28952
|
+
if (!pending) throw new Error("No identity recovery is waiting for a new sign-in");
|
|
28953
|
+
if (!signDidAuthVp) {
|
|
28954
|
+
throw new Error("DID proof signing is required to bind a new sign-in");
|
|
28955
|
+
}
|
|
28956
|
+
if (pending.pinKeep) return completePinSignInRelink(params, pending, signDidAuthVp);
|
|
28957
|
+
const storageId = activeStorageId;
|
|
28958
|
+
const { shares, shareVersion } = await withShareUpdateLock(
|
|
28959
|
+
storage2,
|
|
28960
|
+
storageId,
|
|
28961
|
+
() => withRotationLock(async () => {
|
|
28962
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
28963
|
+
if (activeStorageId !== storageId || pendingIdentityRecovery !== pending || storageGeneration !== generation) {
|
|
28964
|
+
throw new Error("This recovery request was cancelled.");
|
|
28965
|
+
}
|
|
28966
|
+
}, "assertActive");
|
|
28967
|
+
assertActive();
|
|
28968
|
+
const candidates = await readPendingShareCandidates(storage2, storageId);
|
|
28969
|
+
if (pending.rebind && pending.rebind.storageId !== storageId) {
|
|
28970
|
+
throw new Error("Active account changed during identity recovery");
|
|
28971
|
+
}
|
|
28972
|
+
if (candidates.some(
|
|
28973
|
+
(candidate) => candidate.share !== pending.rebind?.shares.deviceShare
|
|
28974
|
+
)) {
|
|
28975
|
+
throw new Error("Reconcile the pending share update before binding a sign-in");
|
|
28976
|
+
}
|
|
28977
|
+
let shareVersion2;
|
|
28978
|
+
const retry = pending.rebind?.attempted ?? false;
|
|
28979
|
+
if (retry && pending.rebind) {
|
|
28980
|
+
const current = await fetchAuthShareRaw(
|
|
28981
|
+
serverUrl,
|
|
28982
|
+
params.token,
|
|
28983
|
+
params.providerType,
|
|
28984
|
+
void 0,
|
|
28985
|
+
tenantId
|
|
28986
|
+
);
|
|
28987
|
+
const authShare = authShareToString(current?.authShare);
|
|
28988
|
+
if (authShare && current?.shareVersion != null) {
|
|
28989
|
+
const health = await verifyStoredShares(
|
|
28990
|
+
{
|
|
28991
|
+
getDevice: /* @__PURE__ */ __name(async () => pending.rebind.shares.deviceShare, "getDevice"),
|
|
28992
|
+
getAuth: /* @__PURE__ */ __name(async () => authShare, "getAuth")
|
|
28993
|
+
},
|
|
28994
|
+
pending.primaryDid,
|
|
28995
|
+
async (key) => key === pending.privateKey ? pending.primaryDid : ""
|
|
28996
|
+
);
|
|
28997
|
+
if (health.healthy) shareVersion2 = current.shareVersion;
|
|
28998
|
+
}
|
|
28999
|
+
}
|
|
29000
|
+
assertActive();
|
|
29001
|
+
if (shareVersion2 === void 0) {
|
|
29002
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
29003
|
+
serverUrl,
|
|
29004
|
+
pending.privateKey,
|
|
29005
|
+
pending.primaryDid,
|
|
29006
|
+
signDidAuthVp,
|
|
29007
|
+
tenantId
|
|
29008
|
+
);
|
|
29009
|
+
assertActive();
|
|
29010
|
+
pending.rebind ??= {
|
|
29011
|
+
shares: (await splitAndVerify(pending.privateKey)).shares,
|
|
29012
|
+
storageId,
|
|
29013
|
+
attempted: false
|
|
29014
|
+
};
|
|
29015
|
+
const rebind = pending.rebind;
|
|
29016
|
+
if (!candidates.some((candidate) => candidate.share === rebind.shares.deviceShare)) {
|
|
29017
|
+
await addPendingShareCandidate(
|
|
29018
|
+
storage2,
|
|
29019
|
+
{ share: rebind.shares.deviceShare, createdAt: Date.now() },
|
|
29020
|
+
storageId
|
|
29021
|
+
);
|
|
29022
|
+
}
|
|
29023
|
+
assertActive();
|
|
29024
|
+
rebind.attempted = true;
|
|
29025
|
+
try {
|
|
29026
|
+
const response = await postJson(
|
|
29027
|
+
`${serverUrl}/keys/recovery-session/rebind`,
|
|
29028
|
+
{
|
|
29029
|
+
recoverySessionToken: pending.rebindSessionToken,
|
|
29030
|
+
providerType: params.providerType,
|
|
29031
|
+
primaryDid: pending.primaryDid,
|
|
29032
|
+
authShare: {
|
|
29033
|
+
encryptedData: rebind.shares.authShare,
|
|
29034
|
+
encryptedDek: "",
|
|
29035
|
+
iv: ""
|
|
29036
|
+
}
|
|
29037
|
+
},
|
|
29038
|
+
{
|
|
29039
|
+
...buildHeaders("", didAuthVp, tenantId),
|
|
29040
|
+
"X-Auth-Token": params.token
|
|
29041
|
+
}
|
|
29042
|
+
);
|
|
29043
|
+
shareVersion2 = response.shareVersion;
|
|
29044
|
+
} catch (error) {
|
|
29045
|
+
if (error instanceof ShareWriteRejectedError && !retry) {
|
|
29046
|
+
await removePendingShareCandidate(
|
|
29047
|
+
storage2,
|
|
29048
|
+
rebind.shares.deviceShare,
|
|
29049
|
+
storageId
|
|
29050
|
+
);
|
|
29051
|
+
pending.rebind = void 0;
|
|
29052
|
+
}
|
|
29053
|
+
throw error;
|
|
29054
|
+
}
|
|
29055
|
+
}
|
|
29056
|
+
if (shareVersion2 === void 0 || !pending.rebind) {
|
|
29057
|
+
throw new Error("Server did not confirm the new share");
|
|
29058
|
+
}
|
|
29059
|
+
assertActive();
|
|
29060
|
+
const shares2 = pending.rebind.shares;
|
|
29061
|
+
await storage2.storeDeviceShare(shares2.deviceShare, storageId);
|
|
29062
|
+
await storage2.storeShareVersion(shareVersion2, storageId);
|
|
29063
|
+
await clearPendingShareCandidates(storage2, storageId);
|
|
29064
|
+
assertActive();
|
|
29065
|
+
lastEmailShare = shares2.emailShare;
|
|
29066
|
+
lastShareVersion = shareVersion2;
|
|
29067
|
+
lastServerSnapshot = {
|
|
29068
|
+
currentVersion: shareVersion2,
|
|
29069
|
+
resolvedVersion: shareVersion2,
|
|
29070
|
+
authShare: shares2.authShare,
|
|
29071
|
+
primaryDid: pending.primaryDid
|
|
29072
|
+
};
|
|
29073
|
+
pendingIdentityRecovery = void 0;
|
|
29074
|
+
return { shares: shares2, shareVersion: shareVersion2 };
|
|
29075
|
+
})
|
|
29076
|
+
);
|
|
29077
|
+
const enrolled = pending.fromEscrow && await tryEnrollEscrow(
|
|
29078
|
+
params.token,
|
|
29079
|
+
params.providerType,
|
|
29080
|
+
pending.privateKey,
|
|
29081
|
+
pending.primaryDid,
|
|
29082
|
+
shares,
|
|
29083
|
+
shareVersion,
|
|
29084
|
+
signDidAuthVp,
|
|
29085
|
+
void 0,
|
|
29086
|
+
void 0,
|
|
29087
|
+
true,
|
|
29088
|
+
storage2.assertCurrent,
|
|
29089
|
+
params.options?.recoveryEmail,
|
|
29090
|
+
params.options?.recoveryLanguage
|
|
29091
|
+
);
|
|
29092
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
29093
|
+
throw new Error("This recovery request was cancelled.");
|
|
29094
|
+
}
|
|
29095
|
+
if (!enrolled) {
|
|
29096
|
+
unenrolledRotation = {
|
|
29097
|
+
shares,
|
|
29098
|
+
shareVersion,
|
|
29099
|
+
primaryDid: pending.primaryDid,
|
|
29100
|
+
clearPin: true
|
|
29101
|
+
};
|
|
29102
|
+
}
|
|
29103
|
+
return {
|
|
29104
|
+
privateKey: pending.privateKey,
|
|
29105
|
+
did: pending.primaryDid,
|
|
29106
|
+
escrowEnrolled: enrolled,
|
|
29107
|
+
escrowRecovery: pending.fromEscrow
|
|
29108
|
+
};
|
|
29109
|
+
}, "completeIdentityRecoveryWith");
|
|
28672
29110
|
return {
|
|
28673
29111
|
name: "sss",
|
|
28674
29112
|
capabilities: {
|
|
@@ -28970,6 +29408,8 @@ function createSSSStrategy(config) {
|
|
|
28970
29408
|
escrowOptedOut: data.escrowOptedOut === true,
|
|
28971
29409
|
escrowPin: data.escrowPin,
|
|
28972
29410
|
escrowStale: data.escrowStale,
|
|
29411
|
+
...typeof data.escrowBlobIdentity === "string" ? { escrowBlobIdentity: data.escrowBlobIdentity } : {},
|
|
29412
|
+
...data.escrowUpdating === true ? { escrowUpdating: true } : {},
|
|
28973
29413
|
sssActivationState: data.sssActivationState ?? "active",
|
|
28974
29414
|
...typeof data.priorEscrowEnrollment === "boolean" ? { priorEscrowEnrollment: data.priorEscrowEnrollment } : {}
|
|
28975
29415
|
};
|
|
@@ -29344,9 +29784,20 @@ function createSSSStrategy(config) {
|
|
|
29344
29784
|
if (input.method === "escrow" || input.method === "escrow-pin") {
|
|
29345
29785
|
if (!didFromPrivateKey)
|
|
29346
29786
|
throw new Error("DID verification is required for escrow recovery");
|
|
29347
|
-
|
|
29787
|
+
if (input.method === "escrow-pin" && !token && !input.recoverySessionToken)
|
|
29788
|
+
throw new Error("PIN recovery requires signing in first.");
|
|
29789
|
+
const pinBefore = input.method === "escrow-pin" && token ? await fetchAuthShareRaw(
|
|
29790
|
+
serverUrl,
|
|
29348
29791
|
token,
|
|
29349
29792
|
providerType,
|
|
29793
|
+
void 0,
|
|
29794
|
+
tenantId
|
|
29795
|
+
).then(
|
|
29796
|
+
(current) => current?.escrowPin,
|
|
29797
|
+
() => void 0
|
|
29798
|
+
) : void 0;
|
|
29799
|
+
const start = input.method === "escrow-pin" ? await this.startEscrowRecovery({
|
|
29800
|
+
...token ? { token, providerType } : { recoverySessionToken: input.recoverySessionToken },
|
|
29350
29801
|
expectedDid: input.expectedDid,
|
|
29351
29802
|
options: { releasePolicy: "pin" }
|
|
29352
29803
|
}) : input;
|
|
@@ -29398,16 +29849,38 @@ function createSSSStrategy(config) {
|
|
|
29398
29849
|
"Recovery produced an incorrect key. Try another recovery method."
|
|
29399
29850
|
);
|
|
29400
29851
|
}
|
|
29852
|
+
if (input.method === "escrow-pin" && token) {
|
|
29853
|
+
return completePinSignInKeep(
|
|
29854
|
+
{ token, providerType, signDidAuthVp, options: params.options },
|
|
29855
|
+
{
|
|
29856
|
+
privateKey: privateKey2,
|
|
29857
|
+
primaryDid: material.primaryDid,
|
|
29858
|
+
recoveryShare: plaintext.recoveryShare,
|
|
29859
|
+
authShare,
|
|
29860
|
+
shareVersion: material.shareVersion
|
|
29861
|
+
},
|
|
29862
|
+
input.pin,
|
|
29863
|
+
pinBefore,
|
|
29864
|
+
input.pinAttempts
|
|
29865
|
+
);
|
|
29866
|
+
}
|
|
29401
29867
|
pendingIdentityRecovery = {
|
|
29402
29868
|
privateKey: privateKey2,
|
|
29403
29869
|
primaryDid: material.primaryDid,
|
|
29404
29870
|
recoveryShare: plaintext.recoveryShare,
|
|
29405
29871
|
authShare,
|
|
29406
29872
|
rebindSessionToken: material.rebindSessionToken,
|
|
29407
|
-
fromEscrow: true
|
|
29873
|
+
fromEscrow: true,
|
|
29874
|
+
// The PIN itself is not kept across the new-login step.
|
|
29875
|
+
...input.method === "escrow-pin" ? {
|
|
29876
|
+
pinKeep: {
|
|
29877
|
+
shareVersion: material.shareVersion,
|
|
29878
|
+
...input.pinAttempts ? { pinAttempts: { ...input.pinAttempts } } : {}
|
|
29879
|
+
}
|
|
29880
|
+
} : {}
|
|
29408
29881
|
};
|
|
29409
29882
|
if (!token) return { privateKey: privateKey2, did: material.primaryDid };
|
|
29410
|
-
return
|
|
29883
|
+
return completeIdentityRecoveryWith({
|
|
29411
29884
|
token,
|
|
29412
29885
|
providerType,
|
|
29413
29886
|
signDidAuthVp,
|
|
@@ -29982,125 +30455,128 @@ function createSSSStrategy(config) {
|
|
|
29982
30455
|
pendingIdentityRecovery = void 0;
|
|
29983
30456
|
},
|
|
29984
30457
|
async completeIdentityRecovery(params) {
|
|
29985
|
-
|
|
29986
|
-
|
|
29987
|
-
|
|
29988
|
-
|
|
29989
|
-
|
|
29990
|
-
|
|
29991
|
-
|
|
30458
|
+
return completeIdentityRecoveryWith(params);
|
|
30459
|
+
},
|
|
30460
|
+
/**
|
|
30461
|
+
* "Secure my account": one atomic server update re-splits the key and drops all
|
|
30462
|
+
* older auth share versions, signing out other devices and turning off the old
|
|
30463
|
+
* phrase/backup/passkey/email key. Staged through the pending-candidate slot, so
|
|
30464
|
+
* a lost acknowledgement is promoted by the usual reconciliation. Escrow is then
|
|
30465
|
+
* re-enrolled with `pin` (fresh salt) or, for `null`, without a PIN. The PIN is
|
|
30466
|
+
* used in this call only and never kept in retry state.
|
|
30467
|
+
*/
|
|
30468
|
+
async revokeOtherDevices(params) {
|
|
30469
|
+
const { token, providerType, privateKey, did, signDidAuthVp, pin } = params;
|
|
30470
|
+
if (!signDidAuthVp) throw new Error("DID proof signing is required");
|
|
30471
|
+
if (pin !== null) {
|
|
30472
|
+
const validation = validatePin(pin);
|
|
30473
|
+
if (!validation.ok)
|
|
30474
|
+
throw new Error(
|
|
30475
|
+
validation.reason === "length" ? "PIN must contain 6\u201312 digits." : "Choose a PIN without trivial or sequential patterns."
|
|
30476
|
+
);
|
|
29992
30477
|
}
|
|
30478
|
+
const storage2 = guardedStorage();
|
|
29993
30479
|
const storageId = activeStorageId;
|
|
30480
|
+
const assertUser = captureActiveUserGuard();
|
|
30481
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
30482
|
+
assertUser();
|
|
30483
|
+
storage2.assertCurrent();
|
|
30484
|
+
}, "assertActive");
|
|
30485
|
+
const before = await fetchAuthShareRaw(
|
|
30486
|
+
serverUrl,
|
|
30487
|
+
token,
|
|
30488
|
+
providerType,
|
|
30489
|
+
void 0,
|
|
30490
|
+
tenantId
|
|
30491
|
+
);
|
|
30492
|
+
if (!before || before.primaryDid !== did) {
|
|
30493
|
+
throw new Error("This account could not be found. Sign in again.");
|
|
30494
|
+
}
|
|
30495
|
+
const hadEscrow = !before.escrowOptedOut && (before.priorEscrowEnrollment === true || Array.isArray(before.recoveryMethods) && before.recoveryMethods.some(
|
|
30496
|
+
(method) => method?.type === "escrow"
|
|
30497
|
+
));
|
|
30498
|
+
const didFromKey = /* @__PURE__ */ __name(async (key) => key === privateKey ? did : `${did}:mismatch`, "didFromKey");
|
|
29994
30499
|
const { shares, shareVersion } = await withShareUpdateLock(
|
|
29995
30500
|
storage2,
|
|
29996
30501
|
storageId,
|
|
29997
30502
|
() => withRotationLock(async () => {
|
|
29998
|
-
const
|
|
29999
|
-
|
|
30000
|
-
|
|
30001
|
-
|
|
30002
|
-
|
|
30003
|
-
|
|
30004
|
-
|
|
30005
|
-
|
|
30006
|
-
|
|
30007
|
-
|
|
30008
|
-
if (candidates.some(
|
|
30009
|
-
(candidate) => candidate.share !== pending.rebind?.shares.deviceShare
|
|
30010
|
-
)) {
|
|
30011
|
-
throw new Error(
|
|
30012
|
-
"Reconcile the pending share update before binding a sign-in"
|
|
30013
|
-
);
|
|
30014
|
-
}
|
|
30015
|
-
let shareVersion2;
|
|
30016
|
-
const retry = pending.rebind?.attempted ?? false;
|
|
30017
|
-
if (retry && pending.rebind) {
|
|
30018
|
-
const current = await fetchAuthShareRaw(
|
|
30019
|
-
serverUrl,
|
|
30020
|
-
params.token,
|
|
30021
|
-
params.providerType,
|
|
30022
|
-
void 0,
|
|
30023
|
-
tenantId
|
|
30024
|
-
);
|
|
30025
|
-
const authShare = authShareToString(current?.authShare);
|
|
30026
|
-
if (authShare && current?.shareVersion != null) {
|
|
30027
|
-
const health = await verifyStoredShares(
|
|
30028
|
-
{
|
|
30029
|
-
getDevice: /* @__PURE__ */ __name(async () => pending.rebind.shares.deviceShare, "getDevice"),
|
|
30030
|
-
getAuth: /* @__PURE__ */ __name(async () => authShare, "getAuth")
|
|
30031
|
-
},
|
|
30032
|
-
pending.primaryDid,
|
|
30033
|
-
async (key) => key === pending.privateKey ? pending.primaryDid : ""
|
|
30503
|
+
const { snapshot } = await resolvePendingShareCandidates(
|
|
30504
|
+
storage2,
|
|
30505
|
+
storageId,
|
|
30506
|
+
async () => {
|
|
30507
|
+
const data = await fetchAuthShareRaw(
|
|
30508
|
+
serverUrl,
|
|
30509
|
+
token,
|
|
30510
|
+
providerType,
|
|
30511
|
+
void 0,
|
|
30512
|
+
tenantId
|
|
30034
30513
|
);
|
|
30035
|
-
|
|
30036
|
-
|
|
30514
|
+
return {
|
|
30515
|
+
currentVersion: data?.shareVersion ?? null,
|
|
30516
|
+
authShare: authShareToString(data?.authShare)
|
|
30517
|
+
};
|
|
30518
|
+
},
|
|
30519
|
+
did,
|
|
30520
|
+
didFromKey,
|
|
30521
|
+
assertActive,
|
|
30522
|
+
recordPromotion(did),
|
|
30523
|
+
async (version) => authShareToString(
|
|
30524
|
+
(await fetchAuthShareRaw(
|
|
30525
|
+
serverUrl,
|
|
30526
|
+
token,
|
|
30527
|
+
providerType,
|
|
30528
|
+
version,
|
|
30529
|
+
tenantId
|
|
30530
|
+
))?.authShare
|
|
30531
|
+
)
|
|
30532
|
+
);
|
|
30533
|
+
if (!snapshot.currentVersion) {
|
|
30534
|
+
throw new Error("This account could not be found. Sign in again.");
|
|
30037
30535
|
}
|
|
30536
|
+
const expectedShareVersion = snapshot.currentVersion;
|
|
30537
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
30538
|
+
serverUrl,
|
|
30539
|
+
privateKey,
|
|
30540
|
+
did,
|
|
30541
|
+
signDidAuthVp,
|
|
30542
|
+
tenantId
|
|
30543
|
+
);
|
|
30038
30544
|
assertActive();
|
|
30039
|
-
|
|
30040
|
-
|
|
30041
|
-
|
|
30042
|
-
|
|
30043
|
-
|
|
30044
|
-
|
|
30045
|
-
tenantId
|
|
30046
|
-
);
|
|
30047
|
-
assertActive();
|
|
30048
|
-
pending.rebind ??= {
|
|
30049
|
-
shares: (await splitAndVerify(pending.privateKey)).shares,
|
|
30050
|
-
storageId,
|
|
30051
|
-
attempted: false
|
|
30052
|
-
};
|
|
30053
|
-
const rebind = pending.rebind;
|
|
30054
|
-
if (!candidates.some(
|
|
30055
|
-
(candidate) => candidate.share === rebind.shares.deviceShare
|
|
30056
|
-
)) {
|
|
30545
|
+
let shareVersion2;
|
|
30546
|
+
let stagedShare = "";
|
|
30547
|
+
const shares2 = await atomicShareUpdate(privateKey, {
|
|
30548
|
+
storeDevice: /* @__PURE__ */ __name(async (share) => {
|
|
30549
|
+
assertActive();
|
|
30550
|
+
stagedShare = share;
|
|
30057
30551
|
await addPendingShareCandidate(
|
|
30058
30552
|
storage2,
|
|
30059
|
-
{ share
|
|
30553
|
+
{ share, createdAt: Date.now() },
|
|
30060
30554
|
storageId
|
|
30061
30555
|
);
|
|
30062
|
-
}
|
|
30063
|
-
|
|
30064
|
-
|
|
30065
|
-
|
|
30556
|
+
}, "storeDevice"),
|
|
30557
|
+
clearDevice: /* @__PURE__ */ __name(() => removePendingShareCandidate(storage2, stagedShare, storageId), "clearDevice"),
|
|
30558
|
+
storeAuth: /* @__PURE__ */ __name(async (share) => {
|
|
30559
|
+
assertActive();
|
|
30066
30560
|
const response = await postJson(
|
|
30067
|
-
`${serverUrl}/keys/
|
|
30561
|
+
`${serverUrl}/keys/revoke-other-devices`,
|
|
30068
30562
|
{
|
|
30069
|
-
|
|
30070
|
-
providerType
|
|
30071
|
-
primaryDid:
|
|
30072
|
-
authShare: {
|
|
30073
|
-
|
|
30074
|
-
encryptedDek: "",
|
|
30075
|
-
iv: ""
|
|
30076
|
-
}
|
|
30563
|
+
authToken: token,
|
|
30564
|
+
providerType,
|
|
30565
|
+
primaryDid: did,
|
|
30566
|
+
authShare: { encryptedData: share, encryptedDek: "", iv: "" },
|
|
30567
|
+
expectedShareVersion
|
|
30077
30568
|
},
|
|
30078
|
-
|
|
30079
|
-
...buildHeaders("", didAuthVp, tenantId),
|
|
30080
|
-
"X-Auth-Token": params.token
|
|
30081
|
-
}
|
|
30569
|
+
buildHeaders(token, didAuthVp, tenantId)
|
|
30082
30570
|
);
|
|
30083
30571
|
shareVersion2 = response.shareVersion;
|
|
30084
|
-
}
|
|
30085
|
-
|
|
30086
|
-
|
|
30087
|
-
|
|
30088
|
-
rebind.shares.deviceShare,
|
|
30089
|
-
storageId
|
|
30090
|
-
);
|
|
30091
|
-
pending.rebind = void 0;
|
|
30092
|
-
}
|
|
30093
|
-
throw error;
|
|
30094
|
-
}
|
|
30095
|
-
}
|
|
30096
|
-
if (shareVersion2 === void 0 || !pending.rebind) {
|
|
30097
|
-
throw new Error("Server did not confirm the new share");
|
|
30572
|
+
}, "storeAuth")
|
|
30573
|
+
});
|
|
30574
|
+
if (shareVersion2 === void 0) {
|
|
30575
|
+
throw new Error("Server did not return a share version");
|
|
30098
30576
|
}
|
|
30099
|
-
assertActive();
|
|
30100
|
-
const shares2 = pending.rebind.shares;
|
|
30101
30577
|
await storage2.storeDeviceShare(shares2.deviceShare, storageId);
|
|
30102
30578
|
await storage2.storeShareVersion(shareVersion2, storageId);
|
|
30103
|
-
await
|
|
30579
|
+
await removePendingShareCandidate(storage2, shares2.deviceShare, storageId);
|
|
30104
30580
|
assertActive();
|
|
30105
30581
|
lastEmailShare = shares2.emailShare;
|
|
30106
30582
|
lastShareVersion = shareVersion2;
|
|
@@ -30108,44 +30584,36 @@ function createSSSStrategy(config) {
|
|
|
30108
30584
|
currentVersion: shareVersion2,
|
|
30109
30585
|
resolvedVersion: shareVersion2,
|
|
30110
30586
|
authShare: shares2.authShare,
|
|
30111
|
-
primaryDid:
|
|
30587
|
+
primaryDid: did
|
|
30112
30588
|
};
|
|
30113
|
-
pendingIdentityRecovery = void 0;
|
|
30114
30589
|
return { shares: shares2, shareVersion: shareVersion2 };
|
|
30115
30590
|
})
|
|
30116
30591
|
);
|
|
30117
|
-
|
|
30118
|
-
|
|
30119
|
-
|
|
30120
|
-
|
|
30121
|
-
|
|
30592
|
+
if (!hadEscrow || !config.escrow?.enabled) {
|
|
30593
|
+
return { shareVersion, escrowEnrolled: false, pinKept: false };
|
|
30594
|
+
}
|
|
30595
|
+
const pinMaterial = pin === null ? void 0 : await freshPinMaterial(pin);
|
|
30596
|
+
const enrollArgs = [
|
|
30597
|
+
token,
|
|
30598
|
+
providerType,
|
|
30599
|
+
privateKey,
|
|
30600
|
+
did,
|
|
30122
30601
|
shares,
|
|
30123
30602
|
shareVersion,
|
|
30124
30603
|
signDidAuthVp,
|
|
30125
30604
|
void 0,
|
|
30126
|
-
|
|
30127
|
-
|
|
30605
|
+
pinMaterial,
|
|
30606
|
+
!pinMaterial,
|
|
30128
30607
|
storage2.assertCurrent,
|
|
30129
30608
|
params.options?.recoveryEmail,
|
|
30130
30609
|
params.options?.recoveryLanguage
|
|
30131
|
-
|
|
30132
|
-
|
|
30133
|
-
|
|
30134
|
-
}
|
|
30610
|
+
];
|
|
30611
|
+
const attempt = await attemptEnrollEscrow(...enrollArgs);
|
|
30612
|
+
const enrolled = attempt.enrolled || attempt.error instanceof EscrowRequestError && attempt.error.status === 403 && await tryEnrollEscrow(...enrollArgs);
|
|
30135
30613
|
if (!enrolled) {
|
|
30136
|
-
unenrolledRotation = {
|
|
30137
|
-
shares,
|
|
30138
|
-
shareVersion,
|
|
30139
|
-
primaryDid: pending.primaryDid,
|
|
30140
|
-
clearPin: true
|
|
30141
|
-
};
|
|
30614
|
+
unenrolledRotation = { shares, shareVersion, primaryDid: did, clearPin: true };
|
|
30142
30615
|
}
|
|
30143
|
-
return {
|
|
30144
|
-
privateKey: pending.privateKey,
|
|
30145
|
-
did: pending.primaryDid,
|
|
30146
|
-
escrowEnrolled: enrolled,
|
|
30147
|
-
escrowRecovery: pending.fromEscrow
|
|
30148
|
-
};
|
|
30616
|
+
return { shareVersion, escrowEnrolled: enrolled, pinKept: enrolled && !!pinMaterial };
|
|
30149
30617
|
},
|
|
30150
30618
|
// --- Contact method management ---
|
|
30151
30619
|
async upgradeContactMethod(token, providerType, previousPhone, email, code) {
|
|
@@ -30457,6 +30925,7 @@ export {
|
|
|
30457
30925
|
NitroAttestationError,
|
|
30458
30926
|
PIN_MAX_LENGTH,
|
|
30459
30927
|
PIN_MIN_LENGTH,
|
|
30928
|
+
PinSignInStaleError,
|
|
30460
30929
|
SSSApiClient,
|
|
30461
30930
|
SSSKeyManager,
|
|
30462
30931
|
SSS_THRESHOLD,
|