@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
|
@@ -24031,7 +24031,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
24031
24031
|
state: external_exports.enum(["none", "enabled", "locked", "stale"]),
|
|
24032
24032
|
enabled: external_exports.boolean(),
|
|
24033
24033
|
attemptsRemaining: external_exports.number().int().nonnegative(),
|
|
24034
|
-
salt: external_exports.string().optional()
|
|
24034
|
+
salt: external_exports.string().optional(),
|
|
24035
|
+
/**
|
|
24036
|
+
* Verified wrong PIN entries against the current PIN (successful releases and
|
|
24037
|
+
* unresolved reservations are not counted). Omitted when the server cannot tell,
|
|
24038
|
+
* e.g. legacy records that predate the verified counter.
|
|
24039
|
+
*/
|
|
24040
|
+
wrongAttempts: external_exports.number().int().nonnegative().optional()
|
|
24035
24041
|
});
|
|
24036
24042
|
var BITSTRING_STATUS_PURPOSES = ["revocation", "suspension"];
|
|
24037
24043
|
var DEFAULT_BITSTRING_STATUS_LIST_SIZE = 131072;
|
|
@@ -25098,6 +25104,7 @@ __export(index_exports, {
|
|
|
25098
25104
|
NitroAttestationError: () => NitroAttestationError,
|
|
25099
25105
|
PIN_MAX_LENGTH: () => PIN_MAX_LENGTH,
|
|
25100
25106
|
PIN_MIN_LENGTH: () => PIN_MIN_LENGTH,
|
|
25107
|
+
PinSignInStaleError: () => PinSignInStaleError,
|
|
25101
25108
|
SSSApiClient: () => SSSApiClient,
|
|
25102
25109
|
SSSKeyManager: () => SSSKeyManager,
|
|
25103
25110
|
SSS_THRESHOLD: () => SSS_THRESHOLD,
|
|
@@ -30154,6 +30161,15 @@ var EscrowPinLockedError = class extends Error {
|
|
|
30154
30161
|
this.name = "EscrowPinLockedError";
|
|
30155
30162
|
}
|
|
30156
30163
|
};
|
|
30164
|
+
var PinSignInStaleError = class extends Error {
|
|
30165
|
+
static {
|
|
30166
|
+
__name(this, "PinSignInStaleError");
|
|
30167
|
+
}
|
|
30168
|
+
constructor() {
|
|
30169
|
+
super("Your account changed while signing in. Try again.");
|
|
30170
|
+
this.name = "PinSignInStaleError";
|
|
30171
|
+
}
|
|
30172
|
+
};
|
|
30157
30173
|
|
|
30158
30174
|
// src/escrow-pin.ts
|
|
30159
30175
|
var PIN_MIN_LENGTH = 6;
|
|
@@ -30412,6 +30428,7 @@ var EscrowRequestError = class extends Error {
|
|
|
30412
30428
|
__name(this, "EscrowRequestError");
|
|
30413
30429
|
}
|
|
30414
30430
|
};
|
|
30431
|
+
var isConflictRefusal = /* @__PURE__ */ __name((error) => error instanceof EscrowRequestError && error.status === 409, "isConflictRefusal");
|
|
30415
30432
|
var DuplicateShareCoordinateError = class extends Error {
|
|
30416
30433
|
static {
|
|
30417
30434
|
__name(this, "DuplicateShareCoordinateError");
|
|
@@ -31016,7 +31033,7 @@ function createSSSStrategy(config) {
|
|
|
31016
31033
|
assertCurrent();
|
|
31017
31034
|
return result;
|
|
31018
31035
|
}, "fetchAuthorityState");
|
|
31019
|
-
const enrollEscrow = /* @__PURE__ */ __name(async (token, providerType, privateKey, primaryDid, shares, shareVersion, signDidAuthVp, verifiedKey, pinMaterial, clearPin = false, assertCurrent = guardedStorage().assertCurrent, recoveryEmail = "", recoveryLanguage = "") => {
|
|
31036
|
+
const enrollEscrow = /* @__PURE__ */ __name(async (token, providerType, privateKey, primaryDid, shares, shareVersion, signDidAuthVp, verifiedKey, pinMaterial, clearPin = false, assertCurrent = guardedStorage().assertCurrent, recoveryEmail = "", recoveryLanguage = "", expectedPinCharges) => {
|
|
31020
31037
|
if (!config.escrow?.enabled) throw new Error("Escrow enrollment is disabled");
|
|
31021
31038
|
if (!signDidAuthVp) throw new Error("DID proof signing is required for escrow enrollment");
|
|
31022
31039
|
const identity = verifiedKey ?? await fetchVerifiedEnclaveKey();
|
|
@@ -31075,7 +31092,8 @@ function createSSSStrategy(config) {
|
|
|
31075
31092
|
enclaveKeyId: keyId,
|
|
31076
31093
|
...pinMaterial ? { pinSalt: pinMaterial.pinSalt } : {},
|
|
31077
31094
|
...(signedIntent ? signedIntent.intent.pinAction === "clear" : clearPin) ? { clearPin: true } : {},
|
|
31078
|
-
...signedIntent ? { signedIntent, sourceEnvelope: authority?.envelope ?? null } : {}
|
|
31095
|
+
...signedIntent ? { signedIntent, sourceEnvelope: authority?.envelope ?? null } : {},
|
|
31096
|
+
...expectedPinCharges ? { expectedPinCharges } : {}
|
|
31079
31097
|
})
|
|
31080
31098
|
});
|
|
31081
31099
|
if (signedIntent) {
|
|
@@ -31088,11 +31106,11 @@ function createSSSStrategy(config) {
|
|
|
31088
31106
|
verifiedEscrowEnvelope = committed.envelope ?? void 0;
|
|
31089
31107
|
}
|
|
31090
31108
|
}, "enrollEscrow");
|
|
31091
|
-
const
|
|
31092
|
-
if (!config.escrow?.enabled) return false;
|
|
31109
|
+
const attemptEnrollEscrow = /* @__PURE__ */ __name(async (...args) => {
|
|
31110
|
+
if (!config.escrow?.enabled) return { enrolled: false };
|
|
31093
31111
|
try {
|
|
31094
31112
|
await enrollEscrow(...args);
|
|
31095
|
-
return true;
|
|
31113
|
+
return { enrolled: true };
|
|
31096
31114
|
} catch (err2) {
|
|
31097
31115
|
try {
|
|
31098
31116
|
if (config.onEscrowError) config.onEscrowError(err2);
|
|
@@ -31100,9 +31118,10 @@ function createSSSStrategy(config) {
|
|
|
31100
31118
|
} catch {
|
|
31101
31119
|
console.warn("SSS: escrow error reporting failed");
|
|
31102
31120
|
}
|
|
31103
|
-
return false;
|
|
31121
|
+
return { enrolled: false, error: err2 };
|
|
31104
31122
|
}
|
|
31105
|
-
}, "
|
|
31123
|
+
}, "attemptEnrollEscrow");
|
|
31124
|
+
const tryEnrollEscrow = /* @__PURE__ */ __name(async (...args) => (await attemptEnrollEscrow(...args)).enrolled, "tryEnrollEscrow");
|
|
31106
31125
|
const withAutoClear = /* @__PURE__ */ __name((shareVersion, autoClearedFrom) => {
|
|
31107
31126
|
if (!autoClearedFrom) return { enrolled: true, changed: true, shareVersion };
|
|
31108
31127
|
try {
|
|
@@ -31163,7 +31182,22 @@ function createSSSStrategy(config) {
|
|
|
31163
31182
|
clearPinForEnrollment ||= current.hasPin && pin === void 0;
|
|
31164
31183
|
}
|
|
31165
31184
|
currentlyEnrolled = currentlyEnrolled && current.status === "active" && current.shareVersion === status.shareVersion && current.envelope?.keyId === verifiedKey.keyId;
|
|
31185
|
+
let identityMismatch = false;
|
|
31186
|
+
if (currentlyEnrolled && current.envelope && status.escrowBlobIdentity !== void 0) {
|
|
31187
|
+
const authorityIdentity = await getEscrowBlobIdentity(current.envelope);
|
|
31188
|
+
if (authorityIdentity !== status.escrowBlobIdentity) {
|
|
31189
|
+
const reread = await self.fetchServerKeyStatus(
|
|
31190
|
+
params.token,
|
|
31191
|
+
params.providerType
|
|
31192
|
+
);
|
|
31193
|
+
storage2.assertCurrent();
|
|
31194
|
+
identityMismatch = reread.escrowBlobIdentity !== authorityIdentity && reread.escrowUpdating !== true;
|
|
31195
|
+
}
|
|
31196
|
+
}
|
|
31197
|
+
if (identityMismatch) currentlyEnrolled = false;
|
|
31166
31198
|
if (currentlyEnrolled) verifiedEscrowEnvelope = current.envelope ?? void 0;
|
|
31199
|
+
if (identityMismatch && current.hasPin && pin === void 0 && !clearPinForEnrollment)
|
|
31200
|
+
return { enrolled: false, reason: "pin-reset-required" };
|
|
31167
31201
|
hasPin = current.hasPin;
|
|
31168
31202
|
const uncarryablePin = !clearPinForEnrollment && current.status === "active" && current.hasPin && pin === void 0 && !currentlyEnrolled && status.escrowPin?.state === "none";
|
|
31169
31203
|
if (uncarryablePin && (config.autoClearUncarryablePin ?? DEFAULT_AUTO_CLEAR_UNCARRYABLE_PIN) && current.shareVersion !== null && status.shareVersion !== null && current.shareVersion < status.shareVersion && !status.recoveryMethods.some(
|
|
@@ -31291,6 +31325,411 @@ function createSSSStrategy(config) {
|
|
|
31291
31325
|
}
|
|
31292
31326
|
};
|
|
31293
31327
|
}, "captureActiveUserGuard");
|
|
31328
|
+
const recordedWrongPinAttempts = /* @__PURE__ */ __name((escrowPin) => {
|
|
31329
|
+
const status = escrowPin;
|
|
31330
|
+
if (status?.state === "none") return 0;
|
|
31331
|
+
const count = status?.wrongAttempts;
|
|
31332
|
+
return typeof count === "number" && Number.isSafeInteger(count) && count >= 0 ? count : void 0;
|
|
31333
|
+
}, "recordedWrongPinAttempts");
|
|
31334
|
+
const attemptCount = /* @__PURE__ */ __name((value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0, "attemptCount");
|
|
31335
|
+
const pinSignInClean = /* @__PURE__ */ __name((observed, flowAttempts) => {
|
|
31336
|
+
const flowSalt = flowAttempts?.pinSalt;
|
|
31337
|
+
const sameGeneration = typeof flowSalt !== "string" || observed.every((status) => {
|
|
31338
|
+
const salt = status?.salt;
|
|
31339
|
+
return typeof salt !== "string" || salt === flowSalt;
|
|
31340
|
+
});
|
|
31341
|
+
const attempts = sameGeneration ? flowAttempts : void 0;
|
|
31342
|
+
const own = attempts ? attemptCount(attempts.ownWrongAttempts) : 0;
|
|
31343
|
+
if (own === void 0) return { clean: false, ownWrongAttempts: 0 };
|
|
31344
|
+
const prior = attempts ? attemptCount(attempts.priorWrongAttempts) : recordedWrongPinAttempts(observed[0]);
|
|
31345
|
+
const clean = prior === 0 && observed.length > 0 && observed.every((status) => recordedWrongPinAttempts(status) === own);
|
|
31346
|
+
return { clean, ownWrongAttempts: own };
|
|
31347
|
+
}, "pinSignInClean");
|
|
31348
|
+
const refreshablePinCharges = /* @__PURE__ */ __name((before, after, ownWrongAttempts) => {
|
|
31349
|
+
const pre = before;
|
|
31350
|
+
const post = after;
|
|
31351
|
+
if (pre?.state !== "enabled" || post?.state !== "enabled") return void 0;
|
|
31352
|
+
if (typeof pre.attemptsRemaining !== "number" || typeof post.attemptsRemaining !== "number")
|
|
31353
|
+
return void 0;
|
|
31354
|
+
if (post.attemptsRemaining !== pre.attemptsRemaining - 1) return void 0;
|
|
31355
|
+
return { attemptsRemaining: post.attemptsRemaining, wrongAttempts: ownWrongAttempts };
|
|
31356
|
+
}, "refreshablePinCharges");
|
|
31357
|
+
const freshPinMaterial = /* @__PURE__ */ __name(async (pin) => {
|
|
31358
|
+
if (!validatePin(pin).ok) return void 0;
|
|
31359
|
+
try {
|
|
31360
|
+
const pinSalt = generatePinSalt();
|
|
31361
|
+
return { pinSalt, pinVerifier: await derivePinProof(pin, pinSalt) };
|
|
31362
|
+
} catch {
|
|
31363
|
+
return void 0;
|
|
31364
|
+
}
|
|
31365
|
+
}, "freshPinMaterial");
|
|
31366
|
+
const adoptReleasedShare = /* @__PURE__ */ __name(async (storage2, storageId, released, shareVersion, currentVersion) => {
|
|
31367
|
+
await storage2.storeDeviceShare(released.recoveryShare, storageId);
|
|
31368
|
+
await storage2.storeShareVersion(shareVersion, storageId);
|
|
31369
|
+
lastEmailShare = void 0;
|
|
31370
|
+
lastShareVersion = shareVersion;
|
|
31371
|
+
lastServerSnapshot = {
|
|
31372
|
+
currentVersion,
|
|
31373
|
+
resolvedVersion: shareVersion,
|
|
31374
|
+
authShare: released.authShare,
|
|
31375
|
+
primaryDid: released.primaryDid
|
|
31376
|
+
};
|
|
31377
|
+
}, "adoptReleasedShare");
|
|
31378
|
+
const completePinSignInKeep = /* @__PURE__ */ __name(async (params, released, pin, pinBefore, pinAttempts) => {
|
|
31379
|
+
const storage2 = guardedStorage();
|
|
31380
|
+
const generation = storageGeneration;
|
|
31381
|
+
const storageId = activeStorageId;
|
|
31382
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
31383
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
31384
|
+
throw new Error("This recovery request was cancelled.");
|
|
31385
|
+
}
|
|
31386
|
+
}, "assertActive");
|
|
31387
|
+
const {
|
|
31388
|
+
mode,
|
|
31389
|
+
newPinRequired: newPinRequiredAtRelease,
|
|
31390
|
+
refreshCharges
|
|
31391
|
+
} = await withShareUpdateLock(
|
|
31392
|
+
storage2,
|
|
31393
|
+
storageId,
|
|
31394
|
+
() => withRotationLock(async () => {
|
|
31395
|
+
assertActive();
|
|
31396
|
+
const current = await fetchAuthShareRaw(
|
|
31397
|
+
serverUrl,
|
|
31398
|
+
params.token,
|
|
31399
|
+
params.providerType,
|
|
31400
|
+
void 0,
|
|
31401
|
+
tenantId
|
|
31402
|
+
);
|
|
31403
|
+
assertActive();
|
|
31404
|
+
if (!current || current.primaryDid !== released.primaryDid || typeof current.shareVersion !== "number") {
|
|
31405
|
+
throw new PinSignInStaleError();
|
|
31406
|
+
}
|
|
31407
|
+
let mode2;
|
|
31408
|
+
if (current.shareVersion === released.shareVersion) {
|
|
31409
|
+
if (authShareToString(current.authShare) !== released.authShare) {
|
|
31410
|
+
throw new PinSignInStaleError();
|
|
31411
|
+
}
|
|
31412
|
+
mode2 = "kept";
|
|
31413
|
+
} else {
|
|
31414
|
+
const historical = current.shareVersion > released.shareVersion ? await fetchAuthShareRaw(
|
|
31415
|
+
serverUrl,
|
|
31416
|
+
params.token,
|
|
31417
|
+
params.providerType,
|
|
31418
|
+
released.shareVersion,
|
|
31419
|
+
tenantId
|
|
31420
|
+
) : null;
|
|
31421
|
+
if (authShareToString(historical?.authShare) !== released.authShare) {
|
|
31422
|
+
throw new PinSignInStaleError();
|
|
31423
|
+
}
|
|
31424
|
+
mode2 = "deferred-rotation";
|
|
31425
|
+
}
|
|
31426
|
+
assertActive();
|
|
31427
|
+
await adoptReleasedShare(
|
|
31428
|
+
storage2,
|
|
31429
|
+
storageId,
|
|
31430
|
+
released,
|
|
31431
|
+
released.shareVersion,
|
|
31432
|
+
current.shareVersion
|
|
31433
|
+
);
|
|
31434
|
+
pendingIdentityRecovery = void 0;
|
|
31435
|
+
const { clean, ownWrongAttempts } = pinSignInClean(
|
|
31436
|
+
[pinBefore, current.escrowPin],
|
|
31437
|
+
pinAttempts
|
|
31438
|
+
);
|
|
31439
|
+
return {
|
|
31440
|
+
mode: mode2,
|
|
31441
|
+
newPinRequired: !clean,
|
|
31442
|
+
refreshCharges: clean ? refreshablePinCharges(pinBefore, current.escrowPin, ownWrongAttempts) : void 0
|
|
31443
|
+
};
|
|
31444
|
+
})
|
|
31445
|
+
);
|
|
31446
|
+
let pinRefreshed = false;
|
|
31447
|
+
let pinRefreshFailed = false;
|
|
31448
|
+
let newPinRequired = newPinRequiredAtRelease;
|
|
31449
|
+
if (mode === "kept" && !newPinRequired && refreshCharges && params.signDidAuthVp) {
|
|
31450
|
+
const pinMaterial = await freshPinMaterial(pin);
|
|
31451
|
+
const refresh = pinMaterial === void 0 ? void 0 : await attemptEnrollEscrow(
|
|
31452
|
+
params.token,
|
|
31453
|
+
params.providerType,
|
|
31454
|
+
released.privateKey,
|
|
31455
|
+
released.primaryDid,
|
|
31456
|
+
{ recoveryShare: released.recoveryShare },
|
|
31457
|
+
released.shareVersion,
|
|
31458
|
+
params.signDidAuthVp,
|
|
31459
|
+
void 0,
|
|
31460
|
+
pinMaterial,
|
|
31461
|
+
false,
|
|
31462
|
+
storage2.assertCurrent,
|
|
31463
|
+
params.options?.recoveryEmail,
|
|
31464
|
+
params.options?.recoveryLanguage,
|
|
31465
|
+
refreshCharges
|
|
31466
|
+
);
|
|
31467
|
+
pinRefreshed = refresh?.enrolled === true;
|
|
31468
|
+
pinRefreshFailed = pinMaterial !== void 0 && !pinRefreshed;
|
|
31469
|
+
if (pinRefreshFailed) {
|
|
31470
|
+
const latest = await fetchAuthShareRaw(
|
|
31471
|
+
serverUrl,
|
|
31472
|
+
params.token,
|
|
31473
|
+
params.providerType,
|
|
31474
|
+
void 0,
|
|
31475
|
+
tenantId
|
|
31476
|
+
).catch(() => void 0);
|
|
31477
|
+
newPinRequired = latest ? !pinSignInClean([pinBefore, latest.escrowPin], pinAttempts).clean : isConflictRefusal(refresh && !refresh.enrolled ? refresh.error : void 0);
|
|
31478
|
+
}
|
|
31479
|
+
}
|
|
31480
|
+
assertActive();
|
|
31481
|
+
return {
|
|
31482
|
+
privateKey: released.privateKey,
|
|
31483
|
+
did: released.primaryDid,
|
|
31484
|
+
escrowEnrolled: true,
|
|
31485
|
+
escrowRecovery: true,
|
|
31486
|
+
pinSignIn: {
|
|
31487
|
+
mode,
|
|
31488
|
+
pinRefreshed,
|
|
31489
|
+
newPinRequired,
|
|
31490
|
+
...pinRefreshFailed ? { pinRefreshFailed: true } : {}
|
|
31491
|
+
}
|
|
31492
|
+
};
|
|
31493
|
+
}, "completePinSignInKeep");
|
|
31494
|
+
const completePinSignInRelink = /* @__PURE__ */ __name(async (params, pending, signDidAuthVp) => {
|
|
31495
|
+
const storage2 = guardedStorage();
|
|
31496
|
+
const generation = storageGeneration;
|
|
31497
|
+
const storageId = activeStorageId;
|
|
31498
|
+
const shareVersion = pending.pinKeep.shareVersion;
|
|
31499
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
31500
|
+
if (activeStorageId !== storageId || pendingIdentityRecovery !== pending || storageGeneration !== generation) {
|
|
31501
|
+
throw new Error("This recovery request was cancelled.");
|
|
31502
|
+
}
|
|
31503
|
+
}, "assertActive");
|
|
31504
|
+
await withShareUpdateLock(
|
|
31505
|
+
storage2,
|
|
31506
|
+
storageId,
|
|
31507
|
+
() => withRotationLock(async () => {
|
|
31508
|
+
assertActive();
|
|
31509
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
31510
|
+
serverUrl,
|
|
31511
|
+
pending.privateKey,
|
|
31512
|
+
pending.primaryDid,
|
|
31513
|
+
signDidAuthVp,
|
|
31514
|
+
tenantId
|
|
31515
|
+
);
|
|
31516
|
+
assertActive();
|
|
31517
|
+
try {
|
|
31518
|
+
const response = await postJson(
|
|
31519
|
+
`${serverUrl}/keys/recovery-session/pin-sign-in`,
|
|
31520
|
+
{
|
|
31521
|
+
recoverySessionToken: pending.rebindSessionToken,
|
|
31522
|
+
providerType: params.providerType,
|
|
31523
|
+
primaryDid: pending.primaryDid
|
|
31524
|
+
},
|
|
31525
|
+
{
|
|
31526
|
+
...buildHeaders("", didAuthVp, tenantId),
|
|
31527
|
+
"X-Auth-Token": params.token
|
|
31528
|
+
}
|
|
31529
|
+
);
|
|
31530
|
+
if (response.shareVersion !== shareVersion) throw new PinSignInStaleError();
|
|
31531
|
+
} catch (error) {
|
|
31532
|
+
const current = await fetchAuthShareRaw(
|
|
31533
|
+
serverUrl,
|
|
31534
|
+
params.token,
|
|
31535
|
+
params.providerType,
|
|
31536
|
+
void 0,
|
|
31537
|
+
tenantId
|
|
31538
|
+
).catch(() => null);
|
|
31539
|
+
if (!current || current.primaryDid !== pending.primaryDid || current.shareVersion !== shareVersion || authShareToString(current.authShare) !== pending.authShare) {
|
|
31540
|
+
throw error;
|
|
31541
|
+
}
|
|
31542
|
+
}
|
|
31543
|
+
assertActive();
|
|
31544
|
+
await adoptReleasedShare(storage2, storageId, pending, shareVersion, shareVersion);
|
|
31545
|
+
pendingIdentityRecovery = void 0;
|
|
31546
|
+
})
|
|
31547
|
+
);
|
|
31548
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
31549
|
+
throw new Error("This recovery request was cancelled.");
|
|
31550
|
+
}
|
|
31551
|
+
const status = await fetchAuthShareRaw(
|
|
31552
|
+
serverUrl,
|
|
31553
|
+
params.token,
|
|
31554
|
+
params.providerType,
|
|
31555
|
+
void 0,
|
|
31556
|
+
tenantId
|
|
31557
|
+
).catch(() => null);
|
|
31558
|
+
return {
|
|
31559
|
+
privateKey: pending.privateKey,
|
|
31560
|
+
did: pending.primaryDid,
|
|
31561
|
+
escrowEnrolled: true,
|
|
31562
|
+
escrowRecovery: true,
|
|
31563
|
+
pinSignIn: {
|
|
31564
|
+
mode: "relinked",
|
|
31565
|
+
pinRefreshed: false,
|
|
31566
|
+
newPinRequired: !pinSignInClean([status?.escrowPin], pending.pinKeep?.pinAttempts).clean
|
|
31567
|
+
}
|
|
31568
|
+
};
|
|
31569
|
+
}, "completePinSignInRelink");
|
|
31570
|
+
const completeIdentityRecoveryWith = /* @__PURE__ */ __name(async (params) => {
|
|
31571
|
+
const storage2 = guardedStorage();
|
|
31572
|
+
const generation = storageGeneration;
|
|
31573
|
+
const pending = pendingIdentityRecovery;
|
|
31574
|
+
const signDidAuthVp = params.signDidAuthVp;
|
|
31575
|
+
if (!pending) throw new Error("No identity recovery is waiting for a new sign-in");
|
|
31576
|
+
if (!signDidAuthVp) {
|
|
31577
|
+
throw new Error("DID proof signing is required to bind a new sign-in");
|
|
31578
|
+
}
|
|
31579
|
+
if (pending.pinKeep) return completePinSignInRelink(params, pending, signDidAuthVp);
|
|
31580
|
+
const storageId = activeStorageId;
|
|
31581
|
+
const { shares, shareVersion } = await withShareUpdateLock(
|
|
31582
|
+
storage2,
|
|
31583
|
+
storageId,
|
|
31584
|
+
() => withRotationLock(async () => {
|
|
31585
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
31586
|
+
if (activeStorageId !== storageId || pendingIdentityRecovery !== pending || storageGeneration !== generation) {
|
|
31587
|
+
throw new Error("This recovery request was cancelled.");
|
|
31588
|
+
}
|
|
31589
|
+
}, "assertActive");
|
|
31590
|
+
assertActive();
|
|
31591
|
+
const candidates = await readPendingShareCandidates(storage2, storageId);
|
|
31592
|
+
if (pending.rebind && pending.rebind.storageId !== storageId) {
|
|
31593
|
+
throw new Error("Active account changed during identity recovery");
|
|
31594
|
+
}
|
|
31595
|
+
if (candidates.some(
|
|
31596
|
+
(candidate) => candidate.share !== pending.rebind?.shares.deviceShare
|
|
31597
|
+
)) {
|
|
31598
|
+
throw new Error("Reconcile the pending share update before binding a sign-in");
|
|
31599
|
+
}
|
|
31600
|
+
let shareVersion2;
|
|
31601
|
+
const retry = pending.rebind?.attempted ?? false;
|
|
31602
|
+
if (retry && pending.rebind) {
|
|
31603
|
+
const current = await fetchAuthShareRaw(
|
|
31604
|
+
serverUrl,
|
|
31605
|
+
params.token,
|
|
31606
|
+
params.providerType,
|
|
31607
|
+
void 0,
|
|
31608
|
+
tenantId
|
|
31609
|
+
);
|
|
31610
|
+
const authShare = authShareToString(current?.authShare);
|
|
31611
|
+
if (authShare && current?.shareVersion != null) {
|
|
31612
|
+
const health = await verifyStoredShares(
|
|
31613
|
+
{
|
|
31614
|
+
getDevice: /* @__PURE__ */ __name(async () => pending.rebind.shares.deviceShare, "getDevice"),
|
|
31615
|
+
getAuth: /* @__PURE__ */ __name(async () => authShare, "getAuth")
|
|
31616
|
+
},
|
|
31617
|
+
pending.primaryDid,
|
|
31618
|
+
async (key) => key === pending.privateKey ? pending.primaryDid : ""
|
|
31619
|
+
);
|
|
31620
|
+
if (health.healthy) shareVersion2 = current.shareVersion;
|
|
31621
|
+
}
|
|
31622
|
+
}
|
|
31623
|
+
assertActive();
|
|
31624
|
+
if (shareVersion2 === void 0) {
|
|
31625
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
31626
|
+
serverUrl,
|
|
31627
|
+
pending.privateKey,
|
|
31628
|
+
pending.primaryDid,
|
|
31629
|
+
signDidAuthVp,
|
|
31630
|
+
tenantId
|
|
31631
|
+
);
|
|
31632
|
+
assertActive();
|
|
31633
|
+
pending.rebind ??= {
|
|
31634
|
+
shares: (await splitAndVerify(pending.privateKey)).shares,
|
|
31635
|
+
storageId,
|
|
31636
|
+
attempted: false
|
|
31637
|
+
};
|
|
31638
|
+
const rebind = pending.rebind;
|
|
31639
|
+
if (!candidates.some((candidate) => candidate.share === rebind.shares.deviceShare)) {
|
|
31640
|
+
await addPendingShareCandidate(
|
|
31641
|
+
storage2,
|
|
31642
|
+
{ share: rebind.shares.deviceShare, createdAt: Date.now() },
|
|
31643
|
+
storageId
|
|
31644
|
+
);
|
|
31645
|
+
}
|
|
31646
|
+
assertActive();
|
|
31647
|
+
rebind.attempted = true;
|
|
31648
|
+
try {
|
|
31649
|
+
const response = await postJson(
|
|
31650
|
+
`${serverUrl}/keys/recovery-session/rebind`,
|
|
31651
|
+
{
|
|
31652
|
+
recoverySessionToken: pending.rebindSessionToken,
|
|
31653
|
+
providerType: params.providerType,
|
|
31654
|
+
primaryDid: pending.primaryDid,
|
|
31655
|
+
authShare: {
|
|
31656
|
+
encryptedData: rebind.shares.authShare,
|
|
31657
|
+
encryptedDek: "",
|
|
31658
|
+
iv: ""
|
|
31659
|
+
}
|
|
31660
|
+
},
|
|
31661
|
+
{
|
|
31662
|
+
...buildHeaders("", didAuthVp, tenantId),
|
|
31663
|
+
"X-Auth-Token": params.token
|
|
31664
|
+
}
|
|
31665
|
+
);
|
|
31666
|
+
shareVersion2 = response.shareVersion;
|
|
31667
|
+
} catch (error) {
|
|
31668
|
+
if (error instanceof ShareWriteRejectedError && !retry) {
|
|
31669
|
+
await removePendingShareCandidate(
|
|
31670
|
+
storage2,
|
|
31671
|
+
rebind.shares.deviceShare,
|
|
31672
|
+
storageId
|
|
31673
|
+
);
|
|
31674
|
+
pending.rebind = void 0;
|
|
31675
|
+
}
|
|
31676
|
+
throw error;
|
|
31677
|
+
}
|
|
31678
|
+
}
|
|
31679
|
+
if (shareVersion2 === void 0 || !pending.rebind) {
|
|
31680
|
+
throw new Error("Server did not confirm the new share");
|
|
31681
|
+
}
|
|
31682
|
+
assertActive();
|
|
31683
|
+
const shares2 = pending.rebind.shares;
|
|
31684
|
+
await storage2.storeDeviceShare(shares2.deviceShare, storageId);
|
|
31685
|
+
await storage2.storeShareVersion(shareVersion2, storageId);
|
|
31686
|
+
await clearPendingShareCandidates(storage2, storageId);
|
|
31687
|
+
assertActive();
|
|
31688
|
+
lastEmailShare = shares2.emailShare;
|
|
31689
|
+
lastShareVersion = shareVersion2;
|
|
31690
|
+
lastServerSnapshot = {
|
|
31691
|
+
currentVersion: shareVersion2,
|
|
31692
|
+
resolvedVersion: shareVersion2,
|
|
31693
|
+
authShare: shares2.authShare,
|
|
31694
|
+
primaryDid: pending.primaryDid
|
|
31695
|
+
};
|
|
31696
|
+
pendingIdentityRecovery = void 0;
|
|
31697
|
+
return { shares: shares2, shareVersion: shareVersion2 };
|
|
31698
|
+
})
|
|
31699
|
+
);
|
|
31700
|
+
const enrolled = pending.fromEscrow && await tryEnrollEscrow(
|
|
31701
|
+
params.token,
|
|
31702
|
+
params.providerType,
|
|
31703
|
+
pending.privateKey,
|
|
31704
|
+
pending.primaryDid,
|
|
31705
|
+
shares,
|
|
31706
|
+
shareVersion,
|
|
31707
|
+
signDidAuthVp,
|
|
31708
|
+
void 0,
|
|
31709
|
+
void 0,
|
|
31710
|
+
true,
|
|
31711
|
+
storage2.assertCurrent,
|
|
31712
|
+
params.options?.recoveryEmail,
|
|
31713
|
+
params.options?.recoveryLanguage
|
|
31714
|
+
);
|
|
31715
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
31716
|
+
throw new Error("This recovery request was cancelled.");
|
|
31717
|
+
}
|
|
31718
|
+
if (!enrolled) {
|
|
31719
|
+
unenrolledRotation = {
|
|
31720
|
+
shares,
|
|
31721
|
+
shareVersion,
|
|
31722
|
+
primaryDid: pending.primaryDid,
|
|
31723
|
+
clearPin: true
|
|
31724
|
+
};
|
|
31725
|
+
}
|
|
31726
|
+
return {
|
|
31727
|
+
privateKey: pending.privateKey,
|
|
31728
|
+
did: pending.primaryDid,
|
|
31729
|
+
escrowEnrolled: enrolled,
|
|
31730
|
+
escrowRecovery: pending.fromEscrow
|
|
31731
|
+
};
|
|
31732
|
+
}, "completeIdentityRecoveryWith");
|
|
31294
31733
|
return {
|
|
31295
31734
|
name: "sss",
|
|
31296
31735
|
capabilities: {
|
|
@@ -31592,6 +32031,8 @@ function createSSSStrategy(config) {
|
|
|
31592
32031
|
escrowOptedOut: data.escrowOptedOut === true,
|
|
31593
32032
|
escrowPin: data.escrowPin,
|
|
31594
32033
|
escrowStale: data.escrowStale,
|
|
32034
|
+
...typeof data.escrowBlobIdentity === "string" ? { escrowBlobIdentity: data.escrowBlobIdentity } : {},
|
|
32035
|
+
...data.escrowUpdating === true ? { escrowUpdating: true } : {},
|
|
31595
32036
|
sssActivationState: data.sssActivationState ?? "active",
|
|
31596
32037
|
...typeof data.priorEscrowEnrollment === "boolean" ? { priorEscrowEnrollment: data.priorEscrowEnrollment } : {}
|
|
31597
32038
|
};
|
|
@@ -31966,9 +32407,20 @@ function createSSSStrategy(config) {
|
|
|
31966
32407
|
if (input.method === "escrow" || input.method === "escrow-pin") {
|
|
31967
32408
|
if (!didFromPrivateKey)
|
|
31968
32409
|
throw new Error("DID verification is required for escrow recovery");
|
|
31969
|
-
|
|
32410
|
+
if (input.method === "escrow-pin" && !token && !input.recoverySessionToken)
|
|
32411
|
+
throw new Error("PIN recovery requires signing in first.");
|
|
32412
|
+
const pinBefore = input.method === "escrow-pin" && token ? await fetchAuthShareRaw(
|
|
32413
|
+
serverUrl,
|
|
31970
32414
|
token,
|
|
31971
32415
|
providerType,
|
|
32416
|
+
void 0,
|
|
32417
|
+
tenantId
|
|
32418
|
+
).then(
|
|
32419
|
+
(current) => current?.escrowPin,
|
|
32420
|
+
() => void 0
|
|
32421
|
+
) : void 0;
|
|
32422
|
+
const start = input.method === "escrow-pin" ? await this.startEscrowRecovery({
|
|
32423
|
+
...token ? { token, providerType } : { recoverySessionToken: input.recoverySessionToken },
|
|
31972
32424
|
expectedDid: input.expectedDid,
|
|
31973
32425
|
options: { releasePolicy: "pin" }
|
|
31974
32426
|
}) : input;
|
|
@@ -32020,16 +32472,38 @@ function createSSSStrategy(config) {
|
|
|
32020
32472
|
"Recovery produced an incorrect key. Try another recovery method."
|
|
32021
32473
|
);
|
|
32022
32474
|
}
|
|
32475
|
+
if (input.method === "escrow-pin" && token) {
|
|
32476
|
+
return completePinSignInKeep(
|
|
32477
|
+
{ token, providerType, signDidAuthVp, options: params.options },
|
|
32478
|
+
{
|
|
32479
|
+
privateKey: privateKey2,
|
|
32480
|
+
primaryDid: material.primaryDid,
|
|
32481
|
+
recoveryShare: plaintext.recoveryShare,
|
|
32482
|
+
authShare,
|
|
32483
|
+
shareVersion: material.shareVersion
|
|
32484
|
+
},
|
|
32485
|
+
input.pin,
|
|
32486
|
+
pinBefore,
|
|
32487
|
+
input.pinAttempts
|
|
32488
|
+
);
|
|
32489
|
+
}
|
|
32023
32490
|
pendingIdentityRecovery = {
|
|
32024
32491
|
privateKey: privateKey2,
|
|
32025
32492
|
primaryDid: material.primaryDid,
|
|
32026
32493
|
recoveryShare: plaintext.recoveryShare,
|
|
32027
32494
|
authShare,
|
|
32028
32495
|
rebindSessionToken: material.rebindSessionToken,
|
|
32029
|
-
fromEscrow: true
|
|
32496
|
+
fromEscrow: true,
|
|
32497
|
+
// The PIN itself is not kept across the new-login step.
|
|
32498
|
+
...input.method === "escrow-pin" ? {
|
|
32499
|
+
pinKeep: {
|
|
32500
|
+
shareVersion: material.shareVersion,
|
|
32501
|
+
...input.pinAttempts ? { pinAttempts: { ...input.pinAttempts } } : {}
|
|
32502
|
+
}
|
|
32503
|
+
} : {}
|
|
32030
32504
|
};
|
|
32031
32505
|
if (!token) return { privateKey: privateKey2, did: material.primaryDid };
|
|
32032
|
-
return
|
|
32506
|
+
return completeIdentityRecoveryWith({
|
|
32033
32507
|
token,
|
|
32034
32508
|
providerType,
|
|
32035
32509
|
signDidAuthVp,
|
|
@@ -32604,125 +33078,128 @@ function createSSSStrategy(config) {
|
|
|
32604
33078
|
pendingIdentityRecovery = void 0;
|
|
32605
33079
|
},
|
|
32606
33080
|
async completeIdentityRecovery(params) {
|
|
32607
|
-
|
|
32608
|
-
|
|
32609
|
-
|
|
32610
|
-
|
|
32611
|
-
|
|
32612
|
-
|
|
32613
|
-
|
|
33081
|
+
return completeIdentityRecoveryWith(params);
|
|
33082
|
+
},
|
|
33083
|
+
/**
|
|
33084
|
+
* "Secure my account": one atomic server update re-splits the key and drops all
|
|
33085
|
+
* older auth share versions, signing out other devices and turning off the old
|
|
33086
|
+
* phrase/backup/passkey/email key. Staged through the pending-candidate slot, so
|
|
33087
|
+
* a lost acknowledgement is promoted by the usual reconciliation. Escrow is then
|
|
33088
|
+
* re-enrolled with `pin` (fresh salt) or, for `null`, without a PIN. The PIN is
|
|
33089
|
+
* used in this call only and never kept in retry state.
|
|
33090
|
+
*/
|
|
33091
|
+
async revokeOtherDevices(params) {
|
|
33092
|
+
const { token, providerType, privateKey, did, signDidAuthVp, pin } = params;
|
|
33093
|
+
if (!signDidAuthVp) throw new Error("DID proof signing is required");
|
|
33094
|
+
if (pin !== null) {
|
|
33095
|
+
const validation = validatePin(pin);
|
|
33096
|
+
if (!validation.ok)
|
|
33097
|
+
throw new Error(
|
|
33098
|
+
validation.reason === "length" ? "PIN must contain 6\u201312 digits." : "Choose a PIN without trivial or sequential patterns."
|
|
33099
|
+
);
|
|
32614
33100
|
}
|
|
33101
|
+
const storage2 = guardedStorage();
|
|
32615
33102
|
const storageId = activeStorageId;
|
|
33103
|
+
const assertUser = captureActiveUserGuard();
|
|
33104
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
33105
|
+
assertUser();
|
|
33106
|
+
storage2.assertCurrent();
|
|
33107
|
+
}, "assertActive");
|
|
33108
|
+
const before = await fetchAuthShareRaw(
|
|
33109
|
+
serverUrl,
|
|
33110
|
+
token,
|
|
33111
|
+
providerType,
|
|
33112
|
+
void 0,
|
|
33113
|
+
tenantId
|
|
33114
|
+
);
|
|
33115
|
+
if (!before || before.primaryDid !== did) {
|
|
33116
|
+
throw new Error("This account could not be found. Sign in again.");
|
|
33117
|
+
}
|
|
33118
|
+
const hadEscrow = !before.escrowOptedOut && (before.priorEscrowEnrollment === true || Array.isArray(before.recoveryMethods) && before.recoveryMethods.some(
|
|
33119
|
+
(method) => method?.type === "escrow"
|
|
33120
|
+
));
|
|
33121
|
+
const didFromKey = /* @__PURE__ */ __name(async (key) => key === privateKey ? did : `${did}:mismatch`, "didFromKey");
|
|
32616
33122
|
const { shares, shareVersion } = await withShareUpdateLock(
|
|
32617
33123
|
storage2,
|
|
32618
33124
|
storageId,
|
|
32619
33125
|
() => withRotationLock(async () => {
|
|
32620
|
-
const
|
|
32621
|
-
|
|
32622
|
-
|
|
32623
|
-
|
|
32624
|
-
|
|
32625
|
-
|
|
32626
|
-
|
|
32627
|
-
|
|
32628
|
-
|
|
32629
|
-
|
|
32630
|
-
if (candidates.some(
|
|
32631
|
-
(candidate) => candidate.share !== pending.rebind?.shares.deviceShare
|
|
32632
|
-
)) {
|
|
32633
|
-
throw new Error(
|
|
32634
|
-
"Reconcile the pending share update before binding a sign-in"
|
|
32635
|
-
);
|
|
32636
|
-
}
|
|
32637
|
-
let shareVersion2;
|
|
32638
|
-
const retry = pending.rebind?.attempted ?? false;
|
|
32639
|
-
if (retry && pending.rebind) {
|
|
32640
|
-
const current = await fetchAuthShareRaw(
|
|
32641
|
-
serverUrl,
|
|
32642
|
-
params.token,
|
|
32643
|
-
params.providerType,
|
|
32644
|
-
void 0,
|
|
32645
|
-
tenantId
|
|
32646
|
-
);
|
|
32647
|
-
const authShare = authShareToString(current?.authShare);
|
|
32648
|
-
if (authShare && current?.shareVersion != null) {
|
|
32649
|
-
const health = await verifyStoredShares(
|
|
32650
|
-
{
|
|
32651
|
-
getDevice: /* @__PURE__ */ __name(async () => pending.rebind.shares.deviceShare, "getDevice"),
|
|
32652
|
-
getAuth: /* @__PURE__ */ __name(async () => authShare, "getAuth")
|
|
32653
|
-
},
|
|
32654
|
-
pending.primaryDid,
|
|
32655
|
-
async (key) => key === pending.privateKey ? pending.primaryDid : ""
|
|
33126
|
+
const { snapshot } = await resolvePendingShareCandidates(
|
|
33127
|
+
storage2,
|
|
33128
|
+
storageId,
|
|
33129
|
+
async () => {
|
|
33130
|
+
const data = await fetchAuthShareRaw(
|
|
33131
|
+
serverUrl,
|
|
33132
|
+
token,
|
|
33133
|
+
providerType,
|
|
33134
|
+
void 0,
|
|
33135
|
+
tenantId
|
|
32656
33136
|
);
|
|
32657
|
-
|
|
32658
|
-
|
|
33137
|
+
return {
|
|
33138
|
+
currentVersion: data?.shareVersion ?? null,
|
|
33139
|
+
authShare: authShareToString(data?.authShare)
|
|
33140
|
+
};
|
|
33141
|
+
},
|
|
33142
|
+
did,
|
|
33143
|
+
didFromKey,
|
|
33144
|
+
assertActive,
|
|
33145
|
+
recordPromotion(did),
|
|
33146
|
+
async (version) => authShareToString(
|
|
33147
|
+
(await fetchAuthShareRaw(
|
|
33148
|
+
serverUrl,
|
|
33149
|
+
token,
|
|
33150
|
+
providerType,
|
|
33151
|
+
version,
|
|
33152
|
+
tenantId
|
|
33153
|
+
))?.authShare
|
|
33154
|
+
)
|
|
33155
|
+
);
|
|
33156
|
+
if (!snapshot.currentVersion) {
|
|
33157
|
+
throw new Error("This account could not be found. Sign in again.");
|
|
32659
33158
|
}
|
|
33159
|
+
const expectedShareVersion = snapshot.currentVersion;
|
|
33160
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
33161
|
+
serverUrl,
|
|
33162
|
+
privateKey,
|
|
33163
|
+
did,
|
|
33164
|
+
signDidAuthVp,
|
|
33165
|
+
tenantId
|
|
33166
|
+
);
|
|
32660
33167
|
assertActive();
|
|
32661
|
-
|
|
32662
|
-
|
|
32663
|
-
|
|
32664
|
-
|
|
32665
|
-
|
|
32666
|
-
|
|
32667
|
-
tenantId
|
|
32668
|
-
);
|
|
32669
|
-
assertActive();
|
|
32670
|
-
pending.rebind ??= {
|
|
32671
|
-
shares: (await splitAndVerify(pending.privateKey)).shares,
|
|
32672
|
-
storageId,
|
|
32673
|
-
attempted: false
|
|
32674
|
-
};
|
|
32675
|
-
const rebind = pending.rebind;
|
|
32676
|
-
if (!candidates.some(
|
|
32677
|
-
(candidate) => candidate.share === rebind.shares.deviceShare
|
|
32678
|
-
)) {
|
|
33168
|
+
let shareVersion2;
|
|
33169
|
+
let stagedShare = "";
|
|
33170
|
+
const shares2 = await atomicShareUpdate(privateKey, {
|
|
33171
|
+
storeDevice: /* @__PURE__ */ __name(async (share) => {
|
|
33172
|
+
assertActive();
|
|
33173
|
+
stagedShare = share;
|
|
32679
33174
|
await addPendingShareCandidate(
|
|
32680
33175
|
storage2,
|
|
32681
|
-
{ share
|
|
33176
|
+
{ share, createdAt: Date.now() },
|
|
32682
33177
|
storageId
|
|
32683
33178
|
);
|
|
32684
|
-
}
|
|
32685
|
-
|
|
32686
|
-
|
|
32687
|
-
|
|
33179
|
+
}, "storeDevice"),
|
|
33180
|
+
clearDevice: /* @__PURE__ */ __name(() => removePendingShareCandidate(storage2, stagedShare, storageId), "clearDevice"),
|
|
33181
|
+
storeAuth: /* @__PURE__ */ __name(async (share) => {
|
|
33182
|
+
assertActive();
|
|
32688
33183
|
const response = await postJson(
|
|
32689
|
-
`${serverUrl}/keys/
|
|
33184
|
+
`${serverUrl}/keys/revoke-other-devices`,
|
|
32690
33185
|
{
|
|
32691
|
-
|
|
32692
|
-
providerType
|
|
32693
|
-
primaryDid:
|
|
32694
|
-
authShare: {
|
|
32695
|
-
|
|
32696
|
-
encryptedDek: "",
|
|
32697
|
-
iv: ""
|
|
32698
|
-
}
|
|
33186
|
+
authToken: token,
|
|
33187
|
+
providerType,
|
|
33188
|
+
primaryDid: did,
|
|
33189
|
+
authShare: { encryptedData: share, encryptedDek: "", iv: "" },
|
|
33190
|
+
expectedShareVersion
|
|
32699
33191
|
},
|
|
32700
|
-
|
|
32701
|
-
...buildHeaders("", didAuthVp, tenantId),
|
|
32702
|
-
"X-Auth-Token": params.token
|
|
32703
|
-
}
|
|
33192
|
+
buildHeaders(token, didAuthVp, tenantId)
|
|
32704
33193
|
);
|
|
32705
33194
|
shareVersion2 = response.shareVersion;
|
|
32706
|
-
}
|
|
32707
|
-
|
|
32708
|
-
|
|
32709
|
-
|
|
32710
|
-
rebind.shares.deviceShare,
|
|
32711
|
-
storageId
|
|
32712
|
-
);
|
|
32713
|
-
pending.rebind = void 0;
|
|
32714
|
-
}
|
|
32715
|
-
throw error;
|
|
32716
|
-
}
|
|
32717
|
-
}
|
|
32718
|
-
if (shareVersion2 === void 0 || !pending.rebind) {
|
|
32719
|
-
throw new Error("Server did not confirm the new share");
|
|
33195
|
+
}, "storeAuth")
|
|
33196
|
+
});
|
|
33197
|
+
if (shareVersion2 === void 0) {
|
|
33198
|
+
throw new Error("Server did not return a share version");
|
|
32720
33199
|
}
|
|
32721
|
-
assertActive();
|
|
32722
|
-
const shares2 = pending.rebind.shares;
|
|
32723
33200
|
await storage2.storeDeviceShare(shares2.deviceShare, storageId);
|
|
32724
33201
|
await storage2.storeShareVersion(shareVersion2, storageId);
|
|
32725
|
-
await
|
|
33202
|
+
await removePendingShareCandidate(storage2, shares2.deviceShare, storageId);
|
|
32726
33203
|
assertActive();
|
|
32727
33204
|
lastEmailShare = shares2.emailShare;
|
|
32728
33205
|
lastShareVersion = shareVersion2;
|
|
@@ -32730,44 +33207,36 @@ function createSSSStrategy(config) {
|
|
|
32730
33207
|
currentVersion: shareVersion2,
|
|
32731
33208
|
resolvedVersion: shareVersion2,
|
|
32732
33209
|
authShare: shares2.authShare,
|
|
32733
|
-
primaryDid:
|
|
33210
|
+
primaryDid: did
|
|
32734
33211
|
};
|
|
32735
|
-
pendingIdentityRecovery = void 0;
|
|
32736
33212
|
return { shares: shares2, shareVersion: shareVersion2 };
|
|
32737
33213
|
})
|
|
32738
33214
|
);
|
|
32739
|
-
|
|
32740
|
-
|
|
32741
|
-
|
|
32742
|
-
|
|
32743
|
-
|
|
33215
|
+
if (!hadEscrow || !config.escrow?.enabled) {
|
|
33216
|
+
return { shareVersion, escrowEnrolled: false, pinKept: false };
|
|
33217
|
+
}
|
|
33218
|
+
const pinMaterial = pin === null ? void 0 : await freshPinMaterial(pin);
|
|
33219
|
+
const enrollArgs = [
|
|
33220
|
+
token,
|
|
33221
|
+
providerType,
|
|
33222
|
+
privateKey,
|
|
33223
|
+
did,
|
|
32744
33224
|
shares,
|
|
32745
33225
|
shareVersion,
|
|
32746
33226
|
signDidAuthVp,
|
|
32747
33227
|
void 0,
|
|
32748
|
-
|
|
32749
|
-
|
|
33228
|
+
pinMaterial,
|
|
33229
|
+
!pinMaterial,
|
|
32750
33230
|
storage2.assertCurrent,
|
|
32751
33231
|
params.options?.recoveryEmail,
|
|
32752
33232
|
params.options?.recoveryLanguage
|
|
32753
|
-
|
|
32754
|
-
|
|
32755
|
-
|
|
32756
|
-
}
|
|
33233
|
+
];
|
|
33234
|
+
const attempt = await attemptEnrollEscrow(...enrollArgs);
|
|
33235
|
+
const enrolled = attempt.enrolled || attempt.error instanceof EscrowRequestError && attempt.error.status === 403 && await tryEnrollEscrow(...enrollArgs);
|
|
32757
33236
|
if (!enrolled) {
|
|
32758
|
-
unenrolledRotation = {
|
|
32759
|
-
shares,
|
|
32760
|
-
shareVersion,
|
|
32761
|
-
primaryDid: pending.primaryDid,
|
|
32762
|
-
clearPin: true
|
|
32763
|
-
};
|
|
33237
|
+
unenrolledRotation = { shares, shareVersion, primaryDid: did, clearPin: true };
|
|
32764
33238
|
}
|
|
32765
|
-
return {
|
|
32766
|
-
privateKey: pending.privateKey,
|
|
32767
|
-
did: pending.primaryDid,
|
|
32768
|
-
escrowEnrolled: enrolled,
|
|
32769
|
-
escrowRecovery: pending.fromEscrow
|
|
32770
|
-
};
|
|
33239
|
+
return { shareVersion, escrowEnrolled: enrolled, pinKept: enrolled && !!pinMaterial };
|
|
32771
33240
|
},
|
|
32772
33241
|
// --- Contact method management ---
|
|
32773
33242
|
async upgradeContactMethod(token, providerType, previousPhone, email, code) {
|