@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
|
@@ -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;
|
|
@@ -25077,6 +25083,7 @@ __export(index_exports, {
|
|
|
25077
25083
|
AtomicUpdateError: () => AtomicUpdateError,
|
|
25078
25084
|
AuthSessionError: () => import_types.AuthSessionError,
|
|
25079
25085
|
DEFAULT_KDF_PARAMS: () => DEFAULT_KDF_PARAMS,
|
|
25086
|
+
DuplicateShareCoordinateError: () => DuplicateShareCoordinateError,
|
|
25080
25087
|
EMAIL_RELAY_ALGORITHM: () => EMAIL_RELAY_ALGORITHM,
|
|
25081
25088
|
EMAIL_RELAY_ENVELOPE_VERSION: () => EMAIL_RELAY_ENVELOPE_VERSION,
|
|
25082
25089
|
ESCROW_ALGORITHM: () => ESCROW_ALGORITHM,
|
|
@@ -25097,6 +25104,7 @@ __export(index_exports, {
|
|
|
25097
25104
|
NitroAttestationError: () => NitroAttestationError,
|
|
25098
25105
|
PIN_MAX_LENGTH: () => PIN_MAX_LENGTH,
|
|
25099
25106
|
PIN_MIN_LENGTH: () => PIN_MIN_LENGTH,
|
|
25107
|
+
PinSignInStaleError: () => PinSignInStaleError,
|
|
25100
25108
|
SSSApiClient: () => SSSApiClient,
|
|
25101
25109
|
SSSKeyManager: () => SSSKeyManager,
|
|
25102
25110
|
SSS_THRESHOLD: () => SSS_THRESHOLD,
|
|
@@ -30153,6 +30161,15 @@ var EscrowPinLockedError = class extends Error {
|
|
|
30153
30161
|
this.name = "EscrowPinLockedError";
|
|
30154
30162
|
}
|
|
30155
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
|
+
};
|
|
30156
30173
|
|
|
30157
30174
|
// src/escrow-pin.ts
|
|
30158
30175
|
var PIN_MIN_LENGTH = 6;
|
|
@@ -30411,6 +30428,15 @@ var EscrowRequestError = class extends Error {
|
|
|
30411
30428
|
__name(this, "EscrowRequestError");
|
|
30412
30429
|
}
|
|
30413
30430
|
};
|
|
30431
|
+
var DuplicateShareCoordinateError = class extends Error {
|
|
30432
|
+
static {
|
|
30433
|
+
__name(this, "DuplicateShareCoordinateError");
|
|
30434
|
+
}
|
|
30435
|
+
constructor() {
|
|
30436
|
+
super("Stored shares have the same coordinate and cannot be combined");
|
|
30437
|
+
this.name = "DuplicateShareCoordinateError";
|
|
30438
|
+
}
|
|
30439
|
+
};
|
|
30414
30440
|
var fetchAuthShareRaw = /* @__PURE__ */ __name(async (serverUrl, token, providerType, shareVersion, tenantId) => {
|
|
30415
30441
|
const response = await fetch(`${serverUrl}/keys/auth-share`, {
|
|
30416
30442
|
method: "POST",
|
|
@@ -31006,7 +31032,7 @@ function createSSSStrategy(config) {
|
|
|
31006
31032
|
assertCurrent();
|
|
31007
31033
|
return result;
|
|
31008
31034
|
}, "fetchAuthorityState");
|
|
31009
|
-
const enrollEscrow = /* @__PURE__ */ __name(async (token, providerType, privateKey, primaryDid, shares, shareVersion, signDidAuthVp, verifiedKey, pinMaterial, clearPin = false, assertCurrent = guardedStorage().assertCurrent, recoveryEmail = "", recoveryLanguage = "") => {
|
|
31035
|
+
const enrollEscrow = /* @__PURE__ */ __name(async (token, providerType, privateKey, primaryDid, shares, shareVersion, signDidAuthVp, verifiedKey, pinMaterial, clearPin = false, assertCurrent = guardedStorage().assertCurrent, recoveryEmail = "", recoveryLanguage = "", expectedPinCharges) => {
|
|
31010
31036
|
if (!config.escrow?.enabled) throw new Error("Escrow enrollment is disabled");
|
|
31011
31037
|
if (!signDidAuthVp) throw new Error("DID proof signing is required for escrow enrollment");
|
|
31012
31038
|
const identity = verifiedKey ?? await fetchVerifiedEnclaveKey();
|
|
@@ -31065,7 +31091,8 @@ function createSSSStrategy(config) {
|
|
|
31065
31091
|
enclaveKeyId: keyId,
|
|
31066
31092
|
...pinMaterial ? { pinSalt: pinMaterial.pinSalt } : {},
|
|
31067
31093
|
...(signedIntent ? signedIntent.intent.pinAction === "clear" : clearPin) ? { clearPin: true } : {},
|
|
31068
|
-
...signedIntent ? { signedIntent, sourceEnvelope: authority?.envelope ?? null } : {}
|
|
31094
|
+
...signedIntent ? { signedIntent, sourceEnvelope: authority?.envelope ?? null } : {},
|
|
31095
|
+
...expectedPinCharges ? { expectedPinCharges } : {}
|
|
31069
31096
|
})
|
|
31070
31097
|
});
|
|
31071
31098
|
if (signedIntent) {
|
|
@@ -31078,11 +31105,11 @@ function createSSSStrategy(config) {
|
|
|
31078
31105
|
verifiedEscrowEnvelope = committed.envelope ?? void 0;
|
|
31079
31106
|
}
|
|
31080
31107
|
}, "enrollEscrow");
|
|
31081
|
-
const
|
|
31082
|
-
if (!config.escrow?.enabled) return false;
|
|
31108
|
+
const attemptEnrollEscrow = /* @__PURE__ */ __name(async (...args) => {
|
|
31109
|
+
if (!config.escrow?.enabled) return { enrolled: false };
|
|
31083
31110
|
try {
|
|
31084
31111
|
await enrollEscrow(...args);
|
|
31085
|
-
return true;
|
|
31112
|
+
return { enrolled: true };
|
|
31086
31113
|
} catch (err2) {
|
|
31087
31114
|
try {
|
|
31088
31115
|
if (config.onEscrowError) config.onEscrowError(err2);
|
|
@@ -31090,9 +31117,10 @@ function createSSSStrategy(config) {
|
|
|
31090
31117
|
} catch {
|
|
31091
31118
|
console.warn("SSS: escrow error reporting failed");
|
|
31092
31119
|
}
|
|
31093
|
-
return false;
|
|
31120
|
+
return { enrolled: false, error: err2 };
|
|
31094
31121
|
}
|
|
31095
|
-
}, "
|
|
31122
|
+
}, "attemptEnrollEscrow");
|
|
31123
|
+
const tryEnrollEscrow = /* @__PURE__ */ __name(async (...args) => (await attemptEnrollEscrow(...args)).enrolled, "tryEnrollEscrow");
|
|
31096
31124
|
const withAutoClear = /* @__PURE__ */ __name((shareVersion, autoClearedFrom) => {
|
|
31097
31125
|
if (!autoClearedFrom) return { enrolled: true, changed: true, shareVersion };
|
|
31098
31126
|
try {
|
|
@@ -31153,7 +31181,22 @@ function createSSSStrategy(config) {
|
|
|
31153
31181
|
clearPinForEnrollment ||= current.hasPin && pin === void 0;
|
|
31154
31182
|
}
|
|
31155
31183
|
currentlyEnrolled = currentlyEnrolled && current.status === "active" && current.shareVersion === status.shareVersion && current.envelope?.keyId === verifiedKey.keyId;
|
|
31184
|
+
let identityMismatch = false;
|
|
31185
|
+
if (currentlyEnrolled && current.envelope && status.escrowBlobIdentity !== void 0) {
|
|
31186
|
+
const authorityIdentity = await getEscrowBlobIdentity(current.envelope);
|
|
31187
|
+
if (authorityIdentity !== status.escrowBlobIdentity) {
|
|
31188
|
+
const reread = await self.fetchServerKeyStatus(
|
|
31189
|
+
params.token,
|
|
31190
|
+
params.providerType
|
|
31191
|
+
);
|
|
31192
|
+
storage2.assertCurrent();
|
|
31193
|
+
identityMismatch = reread.escrowBlobIdentity !== authorityIdentity && reread.escrowUpdating !== true;
|
|
31194
|
+
}
|
|
31195
|
+
}
|
|
31196
|
+
if (identityMismatch) currentlyEnrolled = false;
|
|
31156
31197
|
if (currentlyEnrolled) verifiedEscrowEnvelope = current.envelope ?? void 0;
|
|
31198
|
+
if (identityMismatch && current.hasPin && pin === void 0 && !clearPinForEnrollment)
|
|
31199
|
+
return { enrolled: false, reason: "pin-reset-required" };
|
|
31157
31200
|
hasPin = current.hasPin;
|
|
31158
31201
|
const uncarryablePin = !clearPinForEnrollment && current.status === "active" && current.hasPin && pin === void 0 && !currentlyEnrolled && status.escrowPin?.state === "none";
|
|
31159
31202
|
if (uncarryablePin && (config.autoClearUncarryablePin ?? DEFAULT_AUTO_CLEAR_UNCARRYABLE_PIN) && current.shareVersion !== null && status.shareVersion !== null && current.shareVersion < status.shareVersion && !status.recoveryMethods.some(
|
|
@@ -31281,6 +31324,378 @@ function createSSSStrategy(config) {
|
|
|
31281
31324
|
}
|
|
31282
31325
|
};
|
|
31283
31326
|
}, "captureActiveUserGuard");
|
|
31327
|
+
const pinHasRecordedWrongAttempts = /* @__PURE__ */ __name((escrowPin) => {
|
|
31328
|
+
const status = escrowPin;
|
|
31329
|
+
if (status?.state === "none") return false;
|
|
31330
|
+
return typeof status?.wrongAttempts !== "number" || status.wrongAttempts > 0;
|
|
31331
|
+
}, "pinHasRecordedWrongAttempts");
|
|
31332
|
+
const refreshablePinCharges = /* @__PURE__ */ __name((before, after) => {
|
|
31333
|
+
const pre = before;
|
|
31334
|
+
const post = after;
|
|
31335
|
+
if (pinHasRecordedWrongAttempts(before) || pinHasRecordedWrongAttempts(after))
|
|
31336
|
+
return void 0;
|
|
31337
|
+
if (pre?.state !== "enabled" || post?.state !== "enabled") return void 0;
|
|
31338
|
+
if (typeof pre.attemptsRemaining !== "number" || typeof post.attemptsRemaining !== "number")
|
|
31339
|
+
return void 0;
|
|
31340
|
+
if (post.attemptsRemaining !== pre.attemptsRemaining - 1) return void 0;
|
|
31341
|
+
return { attemptsRemaining: post.attemptsRemaining, wrongAttempts: 0 };
|
|
31342
|
+
}, "refreshablePinCharges");
|
|
31343
|
+
const freshPinMaterial = /* @__PURE__ */ __name(async (pin) => {
|
|
31344
|
+
if (!validatePin(pin).ok) return void 0;
|
|
31345
|
+
try {
|
|
31346
|
+
const pinSalt = generatePinSalt();
|
|
31347
|
+
return { pinSalt, pinVerifier: await derivePinProof(pin, pinSalt) };
|
|
31348
|
+
} catch {
|
|
31349
|
+
return void 0;
|
|
31350
|
+
}
|
|
31351
|
+
}, "freshPinMaterial");
|
|
31352
|
+
const adoptReleasedShare = /* @__PURE__ */ __name(async (storage2, storageId, released, shareVersion, currentVersion) => {
|
|
31353
|
+
await storage2.storeDeviceShare(released.recoveryShare, storageId);
|
|
31354
|
+
await storage2.storeShareVersion(shareVersion, storageId);
|
|
31355
|
+
lastEmailShare = void 0;
|
|
31356
|
+
lastShareVersion = shareVersion;
|
|
31357
|
+
lastServerSnapshot = {
|
|
31358
|
+
currentVersion,
|
|
31359
|
+
resolvedVersion: shareVersion,
|
|
31360
|
+
authShare: released.authShare,
|
|
31361
|
+
primaryDid: released.primaryDid
|
|
31362
|
+
};
|
|
31363
|
+
}, "adoptReleasedShare");
|
|
31364
|
+
const completePinSignInKeep = /* @__PURE__ */ __name(async (params, released, pin, pinBefore) => {
|
|
31365
|
+
const storage2 = guardedStorage();
|
|
31366
|
+
const generation = storageGeneration;
|
|
31367
|
+
const storageId = activeStorageId;
|
|
31368
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
31369
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
31370
|
+
throw new Error("This recovery request was cancelled.");
|
|
31371
|
+
}
|
|
31372
|
+
}, "assertActive");
|
|
31373
|
+
const { mode, newPinRequired, refreshCharges } = await withShareUpdateLock(
|
|
31374
|
+
storage2,
|
|
31375
|
+
storageId,
|
|
31376
|
+
() => withRotationLock(async () => {
|
|
31377
|
+
assertActive();
|
|
31378
|
+
const current = await fetchAuthShareRaw(
|
|
31379
|
+
serverUrl,
|
|
31380
|
+
params.token,
|
|
31381
|
+
params.providerType,
|
|
31382
|
+
void 0,
|
|
31383
|
+
tenantId
|
|
31384
|
+
);
|
|
31385
|
+
assertActive();
|
|
31386
|
+
if (!current || current.primaryDid !== released.primaryDid || typeof current.shareVersion !== "number") {
|
|
31387
|
+
throw new PinSignInStaleError();
|
|
31388
|
+
}
|
|
31389
|
+
let mode2;
|
|
31390
|
+
if (current.shareVersion === released.shareVersion) {
|
|
31391
|
+
if (authShareToString(current.authShare) !== released.authShare) {
|
|
31392
|
+
throw new PinSignInStaleError();
|
|
31393
|
+
}
|
|
31394
|
+
mode2 = "kept";
|
|
31395
|
+
} else {
|
|
31396
|
+
const historical = current.shareVersion > released.shareVersion ? await fetchAuthShareRaw(
|
|
31397
|
+
serverUrl,
|
|
31398
|
+
params.token,
|
|
31399
|
+
params.providerType,
|
|
31400
|
+
released.shareVersion,
|
|
31401
|
+
tenantId
|
|
31402
|
+
) : null;
|
|
31403
|
+
if (authShareToString(historical?.authShare) !== released.authShare) {
|
|
31404
|
+
throw new PinSignInStaleError();
|
|
31405
|
+
}
|
|
31406
|
+
mode2 = "deferred-rotation";
|
|
31407
|
+
}
|
|
31408
|
+
assertActive();
|
|
31409
|
+
await adoptReleasedShare(
|
|
31410
|
+
storage2,
|
|
31411
|
+
storageId,
|
|
31412
|
+
released,
|
|
31413
|
+
released.shareVersion,
|
|
31414
|
+
current.shareVersion
|
|
31415
|
+
);
|
|
31416
|
+
pendingIdentityRecovery = void 0;
|
|
31417
|
+
return {
|
|
31418
|
+
mode: mode2,
|
|
31419
|
+
newPinRequired: pinHasRecordedWrongAttempts(pinBefore) || pinHasRecordedWrongAttempts(current.escrowPin),
|
|
31420
|
+
refreshCharges: refreshablePinCharges(pinBefore, current.escrowPin)
|
|
31421
|
+
};
|
|
31422
|
+
})
|
|
31423
|
+
);
|
|
31424
|
+
let pinRefreshed = false;
|
|
31425
|
+
let pinRefreshFailed = false;
|
|
31426
|
+
if (mode === "kept" && !newPinRequired && refreshCharges && params.signDidAuthVp) {
|
|
31427
|
+
const pinMaterial = await freshPinMaterial(pin);
|
|
31428
|
+
pinRefreshed = pinMaterial !== void 0 && await tryEnrollEscrow(
|
|
31429
|
+
params.token,
|
|
31430
|
+
params.providerType,
|
|
31431
|
+
released.privateKey,
|
|
31432
|
+
released.primaryDid,
|
|
31433
|
+
{ recoveryShare: released.recoveryShare },
|
|
31434
|
+
released.shareVersion,
|
|
31435
|
+
params.signDidAuthVp,
|
|
31436
|
+
void 0,
|
|
31437
|
+
pinMaterial,
|
|
31438
|
+
false,
|
|
31439
|
+
storage2.assertCurrent,
|
|
31440
|
+
params.options?.recoveryEmail,
|
|
31441
|
+
params.options?.recoveryLanguage,
|
|
31442
|
+
refreshCharges
|
|
31443
|
+
);
|
|
31444
|
+
pinRefreshFailed = pinMaterial !== void 0 && !pinRefreshed;
|
|
31445
|
+
}
|
|
31446
|
+
assertActive();
|
|
31447
|
+
return {
|
|
31448
|
+
privateKey: released.privateKey,
|
|
31449
|
+
did: released.primaryDid,
|
|
31450
|
+
escrowEnrolled: true,
|
|
31451
|
+
escrowRecovery: true,
|
|
31452
|
+
pinSignIn: {
|
|
31453
|
+
mode,
|
|
31454
|
+
pinRefreshed,
|
|
31455
|
+
newPinRequired,
|
|
31456
|
+
...pinRefreshFailed ? { pinRefreshFailed: true } : {}
|
|
31457
|
+
}
|
|
31458
|
+
};
|
|
31459
|
+
}, "completePinSignInKeep");
|
|
31460
|
+
const completePinSignInRelink = /* @__PURE__ */ __name(async (params, pending, signDidAuthVp) => {
|
|
31461
|
+
const storage2 = guardedStorage();
|
|
31462
|
+
const generation = storageGeneration;
|
|
31463
|
+
const storageId = activeStorageId;
|
|
31464
|
+
const shareVersion = pending.pinKeep.shareVersion;
|
|
31465
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
31466
|
+
if (activeStorageId !== storageId || pendingIdentityRecovery !== pending || storageGeneration !== generation) {
|
|
31467
|
+
throw new Error("This recovery request was cancelled.");
|
|
31468
|
+
}
|
|
31469
|
+
}, "assertActive");
|
|
31470
|
+
await withShareUpdateLock(
|
|
31471
|
+
storage2,
|
|
31472
|
+
storageId,
|
|
31473
|
+
() => withRotationLock(async () => {
|
|
31474
|
+
assertActive();
|
|
31475
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
31476
|
+
serverUrl,
|
|
31477
|
+
pending.privateKey,
|
|
31478
|
+
pending.primaryDid,
|
|
31479
|
+
signDidAuthVp,
|
|
31480
|
+
tenantId
|
|
31481
|
+
);
|
|
31482
|
+
assertActive();
|
|
31483
|
+
try {
|
|
31484
|
+
const response = await postJson(
|
|
31485
|
+
`${serverUrl}/keys/recovery-session/pin-sign-in`,
|
|
31486
|
+
{
|
|
31487
|
+
recoverySessionToken: pending.rebindSessionToken,
|
|
31488
|
+
providerType: params.providerType,
|
|
31489
|
+
primaryDid: pending.primaryDid
|
|
31490
|
+
},
|
|
31491
|
+
{
|
|
31492
|
+
...buildHeaders("", didAuthVp, tenantId),
|
|
31493
|
+
"X-Auth-Token": params.token
|
|
31494
|
+
}
|
|
31495
|
+
);
|
|
31496
|
+
if (response.shareVersion !== shareVersion) throw new PinSignInStaleError();
|
|
31497
|
+
} catch (error) {
|
|
31498
|
+
const current = await fetchAuthShareRaw(
|
|
31499
|
+
serverUrl,
|
|
31500
|
+
params.token,
|
|
31501
|
+
params.providerType,
|
|
31502
|
+
void 0,
|
|
31503
|
+
tenantId
|
|
31504
|
+
).catch(() => null);
|
|
31505
|
+
if (!current || current.primaryDid !== pending.primaryDid || current.shareVersion !== shareVersion || authShareToString(current.authShare) !== pending.authShare) {
|
|
31506
|
+
throw error;
|
|
31507
|
+
}
|
|
31508
|
+
}
|
|
31509
|
+
assertActive();
|
|
31510
|
+
await adoptReleasedShare(storage2, storageId, pending, shareVersion, shareVersion);
|
|
31511
|
+
pendingIdentityRecovery = void 0;
|
|
31512
|
+
})
|
|
31513
|
+
);
|
|
31514
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
31515
|
+
throw new Error("This recovery request was cancelled.");
|
|
31516
|
+
}
|
|
31517
|
+
const status = await fetchAuthShareRaw(
|
|
31518
|
+
serverUrl,
|
|
31519
|
+
params.token,
|
|
31520
|
+
params.providerType,
|
|
31521
|
+
void 0,
|
|
31522
|
+
tenantId
|
|
31523
|
+
).catch(() => null);
|
|
31524
|
+
return {
|
|
31525
|
+
privateKey: pending.privateKey,
|
|
31526
|
+
did: pending.primaryDid,
|
|
31527
|
+
escrowEnrolled: true,
|
|
31528
|
+
escrowRecovery: true,
|
|
31529
|
+
pinSignIn: {
|
|
31530
|
+
mode: "relinked",
|
|
31531
|
+
pinRefreshed: false,
|
|
31532
|
+
newPinRequired: pinHasRecordedWrongAttempts(status?.escrowPin)
|
|
31533
|
+
}
|
|
31534
|
+
};
|
|
31535
|
+
}, "completePinSignInRelink");
|
|
31536
|
+
const completeIdentityRecoveryWith = /* @__PURE__ */ __name(async (params) => {
|
|
31537
|
+
const storage2 = guardedStorage();
|
|
31538
|
+
const generation = storageGeneration;
|
|
31539
|
+
const pending = pendingIdentityRecovery;
|
|
31540
|
+
const signDidAuthVp = params.signDidAuthVp;
|
|
31541
|
+
if (!pending) throw new Error("No identity recovery is waiting for a new sign-in");
|
|
31542
|
+
if (!signDidAuthVp) {
|
|
31543
|
+
throw new Error("DID proof signing is required to bind a new sign-in");
|
|
31544
|
+
}
|
|
31545
|
+
if (pending.pinKeep) return completePinSignInRelink(params, pending, signDidAuthVp);
|
|
31546
|
+
const storageId = activeStorageId;
|
|
31547
|
+
const { shares, shareVersion } = await withShareUpdateLock(
|
|
31548
|
+
storage2,
|
|
31549
|
+
storageId,
|
|
31550
|
+
() => withRotationLock(async () => {
|
|
31551
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
31552
|
+
if (activeStorageId !== storageId || pendingIdentityRecovery !== pending || storageGeneration !== generation) {
|
|
31553
|
+
throw new Error("This recovery request was cancelled.");
|
|
31554
|
+
}
|
|
31555
|
+
}, "assertActive");
|
|
31556
|
+
assertActive();
|
|
31557
|
+
const candidates = await readPendingShareCandidates(storage2, storageId);
|
|
31558
|
+
if (pending.rebind && pending.rebind.storageId !== storageId) {
|
|
31559
|
+
throw new Error("Active account changed during identity recovery");
|
|
31560
|
+
}
|
|
31561
|
+
if (candidates.some(
|
|
31562
|
+
(candidate) => candidate.share !== pending.rebind?.shares.deviceShare
|
|
31563
|
+
)) {
|
|
31564
|
+
throw new Error("Reconcile the pending share update before binding a sign-in");
|
|
31565
|
+
}
|
|
31566
|
+
let shareVersion2;
|
|
31567
|
+
const retry = pending.rebind?.attempted ?? false;
|
|
31568
|
+
if (retry && pending.rebind) {
|
|
31569
|
+
const current = await fetchAuthShareRaw(
|
|
31570
|
+
serverUrl,
|
|
31571
|
+
params.token,
|
|
31572
|
+
params.providerType,
|
|
31573
|
+
void 0,
|
|
31574
|
+
tenantId
|
|
31575
|
+
);
|
|
31576
|
+
const authShare = authShareToString(current?.authShare);
|
|
31577
|
+
if (authShare && current?.shareVersion != null) {
|
|
31578
|
+
const health = await verifyStoredShares(
|
|
31579
|
+
{
|
|
31580
|
+
getDevice: /* @__PURE__ */ __name(async () => pending.rebind.shares.deviceShare, "getDevice"),
|
|
31581
|
+
getAuth: /* @__PURE__ */ __name(async () => authShare, "getAuth")
|
|
31582
|
+
},
|
|
31583
|
+
pending.primaryDid,
|
|
31584
|
+
async (key) => key === pending.privateKey ? pending.primaryDid : ""
|
|
31585
|
+
);
|
|
31586
|
+
if (health.healthy) shareVersion2 = current.shareVersion;
|
|
31587
|
+
}
|
|
31588
|
+
}
|
|
31589
|
+
assertActive();
|
|
31590
|
+
if (shareVersion2 === void 0) {
|
|
31591
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
31592
|
+
serverUrl,
|
|
31593
|
+
pending.privateKey,
|
|
31594
|
+
pending.primaryDid,
|
|
31595
|
+
signDidAuthVp,
|
|
31596
|
+
tenantId
|
|
31597
|
+
);
|
|
31598
|
+
assertActive();
|
|
31599
|
+
pending.rebind ??= {
|
|
31600
|
+
shares: (await splitAndVerify(pending.privateKey)).shares,
|
|
31601
|
+
storageId,
|
|
31602
|
+
attempted: false
|
|
31603
|
+
};
|
|
31604
|
+
const rebind = pending.rebind;
|
|
31605
|
+
if (!candidates.some((candidate) => candidate.share === rebind.shares.deviceShare)) {
|
|
31606
|
+
await addPendingShareCandidate(
|
|
31607
|
+
storage2,
|
|
31608
|
+
{ share: rebind.shares.deviceShare, createdAt: Date.now() },
|
|
31609
|
+
storageId
|
|
31610
|
+
);
|
|
31611
|
+
}
|
|
31612
|
+
assertActive();
|
|
31613
|
+
rebind.attempted = true;
|
|
31614
|
+
try {
|
|
31615
|
+
const response = await postJson(
|
|
31616
|
+
`${serverUrl}/keys/recovery-session/rebind`,
|
|
31617
|
+
{
|
|
31618
|
+
recoverySessionToken: pending.rebindSessionToken,
|
|
31619
|
+
providerType: params.providerType,
|
|
31620
|
+
primaryDid: pending.primaryDid,
|
|
31621
|
+
authShare: {
|
|
31622
|
+
encryptedData: rebind.shares.authShare,
|
|
31623
|
+
encryptedDek: "",
|
|
31624
|
+
iv: ""
|
|
31625
|
+
}
|
|
31626
|
+
},
|
|
31627
|
+
{
|
|
31628
|
+
...buildHeaders("", didAuthVp, tenantId),
|
|
31629
|
+
"X-Auth-Token": params.token
|
|
31630
|
+
}
|
|
31631
|
+
);
|
|
31632
|
+
shareVersion2 = response.shareVersion;
|
|
31633
|
+
} catch (error) {
|
|
31634
|
+
if (error instanceof ShareWriteRejectedError && !retry) {
|
|
31635
|
+
await removePendingShareCandidate(
|
|
31636
|
+
storage2,
|
|
31637
|
+
rebind.shares.deviceShare,
|
|
31638
|
+
storageId
|
|
31639
|
+
);
|
|
31640
|
+
pending.rebind = void 0;
|
|
31641
|
+
}
|
|
31642
|
+
throw error;
|
|
31643
|
+
}
|
|
31644
|
+
}
|
|
31645
|
+
if (shareVersion2 === void 0 || !pending.rebind) {
|
|
31646
|
+
throw new Error("Server did not confirm the new share");
|
|
31647
|
+
}
|
|
31648
|
+
assertActive();
|
|
31649
|
+
const shares2 = pending.rebind.shares;
|
|
31650
|
+
await storage2.storeDeviceShare(shares2.deviceShare, storageId);
|
|
31651
|
+
await storage2.storeShareVersion(shareVersion2, storageId);
|
|
31652
|
+
await clearPendingShareCandidates(storage2, storageId);
|
|
31653
|
+
assertActive();
|
|
31654
|
+
lastEmailShare = shares2.emailShare;
|
|
31655
|
+
lastShareVersion = shareVersion2;
|
|
31656
|
+
lastServerSnapshot = {
|
|
31657
|
+
currentVersion: shareVersion2,
|
|
31658
|
+
resolvedVersion: shareVersion2,
|
|
31659
|
+
authShare: shares2.authShare,
|
|
31660
|
+
primaryDid: pending.primaryDid
|
|
31661
|
+
};
|
|
31662
|
+
pendingIdentityRecovery = void 0;
|
|
31663
|
+
return { shares: shares2, shareVersion: shareVersion2 };
|
|
31664
|
+
})
|
|
31665
|
+
);
|
|
31666
|
+
const enrolled = pending.fromEscrow && await tryEnrollEscrow(
|
|
31667
|
+
params.token,
|
|
31668
|
+
params.providerType,
|
|
31669
|
+
pending.privateKey,
|
|
31670
|
+
pending.primaryDid,
|
|
31671
|
+
shares,
|
|
31672
|
+
shareVersion,
|
|
31673
|
+
signDidAuthVp,
|
|
31674
|
+
void 0,
|
|
31675
|
+
void 0,
|
|
31676
|
+
true,
|
|
31677
|
+
storage2.assertCurrent,
|
|
31678
|
+
params.options?.recoveryEmail,
|
|
31679
|
+
params.options?.recoveryLanguage
|
|
31680
|
+
);
|
|
31681
|
+
if (activeStorageId !== storageId || storageGeneration !== generation) {
|
|
31682
|
+
throw new Error("This recovery request was cancelled.");
|
|
31683
|
+
}
|
|
31684
|
+
if (!enrolled) {
|
|
31685
|
+
unenrolledRotation = {
|
|
31686
|
+
shares,
|
|
31687
|
+
shareVersion,
|
|
31688
|
+
primaryDid: pending.primaryDid,
|
|
31689
|
+
clearPin: true
|
|
31690
|
+
};
|
|
31691
|
+
}
|
|
31692
|
+
return {
|
|
31693
|
+
privateKey: pending.privateKey,
|
|
31694
|
+
did: pending.primaryDid,
|
|
31695
|
+
escrowEnrolled: enrolled,
|
|
31696
|
+
escrowRecovery: pending.fromEscrow
|
|
31697
|
+
};
|
|
31698
|
+
}, "completeIdentityRecoveryWith");
|
|
31284
31699
|
return {
|
|
31285
31700
|
name: "sss",
|
|
31286
31701
|
capabilities: {
|
|
@@ -31350,6 +31765,10 @@ function createSSSStrategy(config) {
|
|
|
31350
31765
|
};
|
|
31351
31766
|
},
|
|
31352
31767
|
async reconstructKey(localKey, remoteKey) {
|
|
31768
|
+
const coordinate = localKey.slice(-2).toLowerCase();
|
|
31769
|
+
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()) {
|
|
31770
|
+
throw new DuplicateShareCoordinateError();
|
|
31771
|
+
}
|
|
31353
31772
|
return reconstructFromShares([localKey, remoteKey]);
|
|
31354
31773
|
},
|
|
31355
31774
|
async verifyKeys(localKey, remoteKey, expectedDid, didFromPrivateKey) {
|
|
@@ -31578,6 +31997,8 @@ function createSSSStrategy(config) {
|
|
|
31578
31997
|
escrowOptedOut: data.escrowOptedOut === true,
|
|
31579
31998
|
escrowPin: data.escrowPin,
|
|
31580
31999
|
escrowStale: data.escrowStale,
|
|
32000
|
+
...typeof data.escrowBlobIdentity === "string" ? { escrowBlobIdentity: data.escrowBlobIdentity } : {},
|
|
32001
|
+
...data.escrowUpdating === true ? { escrowUpdating: true } : {},
|
|
31581
32002
|
sssActivationState: data.sssActivationState ?? "active",
|
|
31582
32003
|
...typeof data.priorEscrowEnrollment === "boolean" ? { priorEscrowEnrollment: data.priorEscrowEnrollment } : {}
|
|
31583
32004
|
};
|
|
@@ -31952,9 +32373,20 @@ function createSSSStrategy(config) {
|
|
|
31952
32373
|
if (input.method === "escrow" || input.method === "escrow-pin") {
|
|
31953
32374
|
if (!didFromPrivateKey)
|
|
31954
32375
|
throw new Error("DID verification is required for escrow recovery");
|
|
31955
|
-
|
|
32376
|
+
if (input.method === "escrow-pin" && !token && !input.recoverySessionToken)
|
|
32377
|
+
throw new Error("PIN recovery requires signing in first.");
|
|
32378
|
+
const pinBefore = input.method === "escrow-pin" && token ? await fetchAuthShareRaw(
|
|
32379
|
+
serverUrl,
|
|
31956
32380
|
token,
|
|
31957
32381
|
providerType,
|
|
32382
|
+
void 0,
|
|
32383
|
+
tenantId
|
|
32384
|
+
).then(
|
|
32385
|
+
(current) => current?.escrowPin,
|
|
32386
|
+
() => void 0
|
|
32387
|
+
) : void 0;
|
|
32388
|
+
const start = input.method === "escrow-pin" ? await this.startEscrowRecovery({
|
|
32389
|
+
...token ? { token, providerType } : { recoverySessionToken: input.recoverySessionToken },
|
|
31958
32390
|
expectedDid: input.expectedDid,
|
|
31959
32391
|
options: { releasePolicy: "pin" }
|
|
31960
32392
|
}) : input;
|
|
@@ -32006,16 +32438,32 @@ function createSSSStrategy(config) {
|
|
|
32006
32438
|
"Recovery produced an incorrect key. Try another recovery method."
|
|
32007
32439
|
);
|
|
32008
32440
|
}
|
|
32441
|
+
if (input.method === "escrow-pin" && token) {
|
|
32442
|
+
return completePinSignInKeep(
|
|
32443
|
+
{ token, providerType, signDidAuthVp, options: params.options },
|
|
32444
|
+
{
|
|
32445
|
+
privateKey: privateKey2,
|
|
32446
|
+
primaryDid: material.primaryDid,
|
|
32447
|
+
recoveryShare: plaintext.recoveryShare,
|
|
32448
|
+
authShare,
|
|
32449
|
+
shareVersion: material.shareVersion
|
|
32450
|
+
},
|
|
32451
|
+
input.pin,
|
|
32452
|
+
pinBefore
|
|
32453
|
+
);
|
|
32454
|
+
}
|
|
32009
32455
|
pendingIdentityRecovery = {
|
|
32010
32456
|
privateKey: privateKey2,
|
|
32011
32457
|
primaryDid: material.primaryDid,
|
|
32012
32458
|
recoveryShare: plaintext.recoveryShare,
|
|
32013
32459
|
authShare,
|
|
32014
32460
|
rebindSessionToken: material.rebindSessionToken,
|
|
32015
|
-
fromEscrow: true
|
|
32461
|
+
fromEscrow: true,
|
|
32462
|
+
// The PIN itself is not kept across the new-login step.
|
|
32463
|
+
...input.method === "escrow-pin" ? { pinKeep: { shareVersion: material.shareVersion } } : {}
|
|
32016
32464
|
};
|
|
32017
32465
|
if (!token) return { privateKey: privateKey2, did: material.primaryDid };
|
|
32018
|
-
return
|
|
32466
|
+
return completeIdentityRecoveryWith({
|
|
32019
32467
|
token,
|
|
32020
32468
|
providerType,
|
|
32021
32469
|
signDidAuthVp,
|
|
@@ -32590,125 +33038,128 @@ function createSSSStrategy(config) {
|
|
|
32590
33038
|
pendingIdentityRecovery = void 0;
|
|
32591
33039
|
},
|
|
32592
33040
|
async completeIdentityRecovery(params) {
|
|
32593
|
-
|
|
32594
|
-
|
|
32595
|
-
|
|
32596
|
-
|
|
32597
|
-
|
|
32598
|
-
|
|
32599
|
-
|
|
33041
|
+
return completeIdentityRecoveryWith(params);
|
|
33042
|
+
},
|
|
33043
|
+
/**
|
|
33044
|
+
* "Secure my account": one atomic server update re-splits the key and drops all
|
|
33045
|
+
* older auth share versions, signing out other devices and turning off the old
|
|
33046
|
+
* phrase/backup/passkey/email key. Staged through the pending-candidate slot, so
|
|
33047
|
+
* a lost acknowledgement is promoted by the usual reconciliation. Escrow is then
|
|
33048
|
+
* re-enrolled with `pin` (fresh salt) or, for `null`, without a PIN. The PIN is
|
|
33049
|
+
* used in this call only and never kept in retry state.
|
|
33050
|
+
*/
|
|
33051
|
+
async revokeOtherDevices(params) {
|
|
33052
|
+
const { token, providerType, privateKey, did, signDidAuthVp, pin } = params;
|
|
33053
|
+
if (!signDidAuthVp) throw new Error("DID proof signing is required");
|
|
33054
|
+
if (pin !== null) {
|
|
33055
|
+
const validation = validatePin(pin);
|
|
33056
|
+
if (!validation.ok)
|
|
33057
|
+
throw new Error(
|
|
33058
|
+
validation.reason === "length" ? "PIN must contain 6\u201312 digits." : "Choose a PIN without trivial or sequential patterns."
|
|
33059
|
+
);
|
|
32600
33060
|
}
|
|
33061
|
+
const storage2 = guardedStorage();
|
|
32601
33062
|
const storageId = activeStorageId;
|
|
33063
|
+
const assertUser = captureActiveUserGuard();
|
|
33064
|
+
const assertActive = /* @__PURE__ */ __name(() => {
|
|
33065
|
+
assertUser();
|
|
33066
|
+
storage2.assertCurrent();
|
|
33067
|
+
}, "assertActive");
|
|
33068
|
+
const before = await fetchAuthShareRaw(
|
|
33069
|
+
serverUrl,
|
|
33070
|
+
token,
|
|
33071
|
+
providerType,
|
|
33072
|
+
void 0,
|
|
33073
|
+
tenantId
|
|
33074
|
+
);
|
|
33075
|
+
if (!before || before.primaryDid !== did) {
|
|
33076
|
+
throw new Error("This account could not be found. Sign in again.");
|
|
33077
|
+
}
|
|
33078
|
+
const hadEscrow = !before.escrowOptedOut && (before.priorEscrowEnrollment === true || Array.isArray(before.recoveryMethods) && before.recoveryMethods.some(
|
|
33079
|
+
(method) => method?.type === "escrow"
|
|
33080
|
+
));
|
|
33081
|
+
const didFromKey = /* @__PURE__ */ __name(async (key) => key === privateKey ? did : `${did}:mismatch`, "didFromKey");
|
|
32602
33082
|
const { shares, shareVersion } = await withShareUpdateLock(
|
|
32603
33083
|
storage2,
|
|
32604
33084
|
storageId,
|
|
32605
33085
|
() => withRotationLock(async () => {
|
|
32606
|
-
const
|
|
32607
|
-
|
|
32608
|
-
|
|
32609
|
-
|
|
32610
|
-
|
|
32611
|
-
|
|
32612
|
-
|
|
32613
|
-
|
|
32614
|
-
|
|
32615
|
-
|
|
32616
|
-
if (candidates.some(
|
|
32617
|
-
(candidate) => candidate.share !== pending.rebind?.shares.deviceShare
|
|
32618
|
-
)) {
|
|
32619
|
-
throw new Error(
|
|
32620
|
-
"Reconcile the pending share update before binding a sign-in"
|
|
32621
|
-
);
|
|
32622
|
-
}
|
|
32623
|
-
let shareVersion2;
|
|
32624
|
-
const retry = pending.rebind?.attempted ?? false;
|
|
32625
|
-
if (retry && pending.rebind) {
|
|
32626
|
-
const current = await fetchAuthShareRaw(
|
|
32627
|
-
serverUrl,
|
|
32628
|
-
params.token,
|
|
32629
|
-
params.providerType,
|
|
32630
|
-
void 0,
|
|
32631
|
-
tenantId
|
|
32632
|
-
);
|
|
32633
|
-
const authShare = authShareToString(current?.authShare);
|
|
32634
|
-
if (authShare && current?.shareVersion != null) {
|
|
32635
|
-
const health = await verifyStoredShares(
|
|
32636
|
-
{
|
|
32637
|
-
getDevice: /* @__PURE__ */ __name(async () => pending.rebind.shares.deviceShare, "getDevice"),
|
|
32638
|
-
getAuth: /* @__PURE__ */ __name(async () => authShare, "getAuth")
|
|
32639
|
-
},
|
|
32640
|
-
pending.primaryDid,
|
|
32641
|
-
async (key) => key === pending.privateKey ? pending.primaryDid : ""
|
|
33086
|
+
const { snapshot } = await resolvePendingShareCandidates(
|
|
33087
|
+
storage2,
|
|
33088
|
+
storageId,
|
|
33089
|
+
async () => {
|
|
33090
|
+
const data = await fetchAuthShareRaw(
|
|
33091
|
+
serverUrl,
|
|
33092
|
+
token,
|
|
33093
|
+
providerType,
|
|
33094
|
+
void 0,
|
|
33095
|
+
tenantId
|
|
32642
33096
|
);
|
|
32643
|
-
|
|
32644
|
-
|
|
33097
|
+
return {
|
|
33098
|
+
currentVersion: data?.shareVersion ?? null,
|
|
33099
|
+
authShare: authShareToString(data?.authShare)
|
|
33100
|
+
};
|
|
33101
|
+
},
|
|
33102
|
+
did,
|
|
33103
|
+
didFromKey,
|
|
33104
|
+
assertActive,
|
|
33105
|
+
recordPromotion(did),
|
|
33106
|
+
async (version) => authShareToString(
|
|
33107
|
+
(await fetchAuthShareRaw(
|
|
33108
|
+
serverUrl,
|
|
33109
|
+
token,
|
|
33110
|
+
providerType,
|
|
33111
|
+
version,
|
|
33112
|
+
tenantId
|
|
33113
|
+
))?.authShare
|
|
33114
|
+
)
|
|
33115
|
+
);
|
|
33116
|
+
if (!snapshot.currentVersion) {
|
|
33117
|
+
throw new Error("This account could not be found. Sign in again.");
|
|
32645
33118
|
}
|
|
33119
|
+
const expectedShareVersion = snapshot.currentVersion;
|
|
33120
|
+
const didAuthVp = await requestFreshDidAuthVp(
|
|
33121
|
+
serverUrl,
|
|
33122
|
+
privateKey,
|
|
33123
|
+
did,
|
|
33124
|
+
signDidAuthVp,
|
|
33125
|
+
tenantId
|
|
33126
|
+
);
|
|
32646
33127
|
assertActive();
|
|
32647
|
-
|
|
32648
|
-
|
|
32649
|
-
|
|
32650
|
-
|
|
32651
|
-
|
|
32652
|
-
|
|
32653
|
-
tenantId
|
|
32654
|
-
);
|
|
32655
|
-
assertActive();
|
|
32656
|
-
pending.rebind ??= {
|
|
32657
|
-
shares: (await splitAndVerify(pending.privateKey)).shares,
|
|
32658
|
-
storageId,
|
|
32659
|
-
attempted: false
|
|
32660
|
-
};
|
|
32661
|
-
const rebind = pending.rebind;
|
|
32662
|
-
if (!candidates.some(
|
|
32663
|
-
(candidate) => candidate.share === rebind.shares.deviceShare
|
|
32664
|
-
)) {
|
|
33128
|
+
let shareVersion2;
|
|
33129
|
+
let stagedShare = "";
|
|
33130
|
+
const shares2 = await atomicShareUpdate(privateKey, {
|
|
33131
|
+
storeDevice: /* @__PURE__ */ __name(async (share) => {
|
|
33132
|
+
assertActive();
|
|
33133
|
+
stagedShare = share;
|
|
32665
33134
|
await addPendingShareCandidate(
|
|
32666
33135
|
storage2,
|
|
32667
|
-
{ share
|
|
33136
|
+
{ share, createdAt: Date.now() },
|
|
32668
33137
|
storageId
|
|
32669
33138
|
);
|
|
32670
|
-
}
|
|
32671
|
-
|
|
32672
|
-
|
|
32673
|
-
|
|
33139
|
+
}, "storeDevice"),
|
|
33140
|
+
clearDevice: /* @__PURE__ */ __name(() => removePendingShareCandidate(storage2, stagedShare, storageId), "clearDevice"),
|
|
33141
|
+
storeAuth: /* @__PURE__ */ __name(async (share) => {
|
|
33142
|
+
assertActive();
|
|
32674
33143
|
const response = await postJson(
|
|
32675
|
-
`${serverUrl}/keys/
|
|
33144
|
+
`${serverUrl}/keys/revoke-other-devices`,
|
|
32676
33145
|
{
|
|
32677
|
-
|
|
32678
|
-
providerType
|
|
32679
|
-
primaryDid:
|
|
32680
|
-
authShare: {
|
|
32681
|
-
|
|
32682
|
-
encryptedDek: "",
|
|
32683
|
-
iv: ""
|
|
32684
|
-
}
|
|
33146
|
+
authToken: token,
|
|
33147
|
+
providerType,
|
|
33148
|
+
primaryDid: did,
|
|
33149
|
+
authShare: { encryptedData: share, encryptedDek: "", iv: "" },
|
|
33150
|
+
expectedShareVersion
|
|
32685
33151
|
},
|
|
32686
|
-
|
|
32687
|
-
...buildHeaders("", didAuthVp, tenantId),
|
|
32688
|
-
"X-Auth-Token": params.token
|
|
32689
|
-
}
|
|
33152
|
+
buildHeaders(token, didAuthVp, tenantId)
|
|
32690
33153
|
);
|
|
32691
33154
|
shareVersion2 = response.shareVersion;
|
|
32692
|
-
}
|
|
32693
|
-
|
|
32694
|
-
|
|
32695
|
-
|
|
32696
|
-
rebind.shares.deviceShare,
|
|
32697
|
-
storageId
|
|
32698
|
-
);
|
|
32699
|
-
pending.rebind = void 0;
|
|
32700
|
-
}
|
|
32701
|
-
throw error;
|
|
32702
|
-
}
|
|
32703
|
-
}
|
|
32704
|
-
if (shareVersion2 === void 0 || !pending.rebind) {
|
|
32705
|
-
throw new Error("Server did not confirm the new share");
|
|
33155
|
+
}, "storeAuth")
|
|
33156
|
+
});
|
|
33157
|
+
if (shareVersion2 === void 0) {
|
|
33158
|
+
throw new Error("Server did not return a share version");
|
|
32706
33159
|
}
|
|
32707
|
-
assertActive();
|
|
32708
|
-
const shares2 = pending.rebind.shares;
|
|
32709
33160
|
await storage2.storeDeviceShare(shares2.deviceShare, storageId);
|
|
32710
33161
|
await storage2.storeShareVersion(shareVersion2, storageId);
|
|
32711
|
-
await
|
|
33162
|
+
await removePendingShareCandidate(storage2, shares2.deviceShare, storageId);
|
|
32712
33163
|
assertActive();
|
|
32713
33164
|
lastEmailShare = shares2.emailShare;
|
|
32714
33165
|
lastShareVersion = shareVersion2;
|
|
@@ -32716,44 +33167,36 @@ function createSSSStrategy(config) {
|
|
|
32716
33167
|
currentVersion: shareVersion2,
|
|
32717
33168
|
resolvedVersion: shareVersion2,
|
|
32718
33169
|
authShare: shares2.authShare,
|
|
32719
|
-
primaryDid:
|
|
33170
|
+
primaryDid: did
|
|
32720
33171
|
};
|
|
32721
|
-
pendingIdentityRecovery = void 0;
|
|
32722
33172
|
return { shares: shares2, shareVersion: shareVersion2 };
|
|
32723
33173
|
})
|
|
32724
33174
|
);
|
|
32725
|
-
|
|
32726
|
-
|
|
32727
|
-
|
|
32728
|
-
|
|
32729
|
-
|
|
33175
|
+
if (!hadEscrow || !config.escrow?.enabled) {
|
|
33176
|
+
return { shareVersion, escrowEnrolled: false, pinKept: false };
|
|
33177
|
+
}
|
|
33178
|
+
const pinMaterial = pin === null ? void 0 : await freshPinMaterial(pin);
|
|
33179
|
+
const enrollArgs = [
|
|
33180
|
+
token,
|
|
33181
|
+
providerType,
|
|
33182
|
+
privateKey,
|
|
33183
|
+
did,
|
|
32730
33184
|
shares,
|
|
32731
33185
|
shareVersion,
|
|
32732
33186
|
signDidAuthVp,
|
|
32733
33187
|
void 0,
|
|
32734
|
-
|
|
32735
|
-
|
|
33188
|
+
pinMaterial,
|
|
33189
|
+
!pinMaterial,
|
|
32736
33190
|
storage2.assertCurrent,
|
|
32737
33191
|
params.options?.recoveryEmail,
|
|
32738
33192
|
params.options?.recoveryLanguage
|
|
32739
|
-
|
|
32740
|
-
|
|
32741
|
-
|
|
32742
|
-
}
|
|
33193
|
+
];
|
|
33194
|
+
const attempt = await attemptEnrollEscrow(...enrollArgs);
|
|
33195
|
+
const enrolled = attempt.enrolled || attempt.error instanceof EscrowRequestError && attempt.error.status === 403 && await tryEnrollEscrow(...enrollArgs);
|
|
32743
33196
|
if (!enrolled) {
|
|
32744
|
-
unenrolledRotation = {
|
|
32745
|
-
shares,
|
|
32746
|
-
shareVersion,
|
|
32747
|
-
primaryDid: pending.primaryDid,
|
|
32748
|
-
clearPin: true
|
|
32749
|
-
};
|
|
33197
|
+
unenrolledRotation = { shares, shareVersion, primaryDid: did, clearPin: true };
|
|
32750
33198
|
}
|
|
32751
|
-
return {
|
|
32752
|
-
privateKey: pending.privateKey,
|
|
32753
|
-
did: pending.primaryDid,
|
|
32754
|
-
escrowEnrolled: enrolled,
|
|
32755
|
-
escrowRecovery: pending.fromEscrow
|
|
32756
|
-
};
|
|
33199
|
+
return { shareVersion, escrowEnrolled: enrolled, pinKept: enrolled && !!pinMaterial };
|
|
32757
33200
|
},
|
|
32758
33201
|
// --- Contact method management ---
|
|
32759
33202
|
async upgradeContactMethod(token, providerType, previousPhone, email, code) {
|