diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a0a1f80f..73b564ab8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +- fixed: Allow duplicate sync keys when performing a wallet split, in case a previous failed attempt left a repo behind. +- fixed: Do not lose wallet import history when doing a split-archive-split. + ## 2.38.3 (2026-01-06) - added: Added `change2.edge.app` server to default change server list. diff --git a/src/core/fake/fake-server.ts b/src/core/fake/fake-server.ts index f0397dce1..b3e5de2ad 100644 --- a/src/core/fake/fake-server.ts +++ b/src/core/fake/fake-server.ts @@ -275,6 +275,7 @@ function createLogin(request: ApiRequest, login?: DbLogin): HttpResponse { // Set up repos: const keys = asMaybe(asCreateKeysPayload, () => ({ + allowExisting: false, newSyncKeys: [], keyBoxes: [] }))(body.data) diff --git a/src/core/login/keys.ts b/src/core/login/keys.ts index 9b7b2db63..a18c91161 100644 --- a/src/core/login/keys.ts +++ b/src/core/login/keys.ts @@ -67,11 +67,15 @@ export function makeKeyInfo( /** * Assembles all the resources needed to attach new keys to the account. + * @param allowExisting True if the sync keys were derived deterministically, + * which implies that duplicate sync keys on the server are not errors, + * but leftovers from an earlier failed splitting attempt. */ export function makeKeysKit( ai: ApiInput, sessionKey: SessionKey, - keyInfos: EdgeWalletInfo[] + keyInfos: EdgeWalletInfo[], + allowExisting: boolean = false ): LoginKit { // For crash errors: ai.props.log.breadcrumb('makeKeysKit', {}) @@ -95,7 +99,7 @@ export function makeKeysKit( return { loginId: sessionKey.loginId, - server: wasCreateKeysPayload({ keyBoxes, newSyncKeys }), + server: wasCreateKeysPayload({ allowExisting, keyBoxes, newSyncKeys }), serverPath: '/v2/login/keys', stash: { keyBoxes } } diff --git a/src/core/login/splitting.ts b/src/core/login/splitting.ts index 957b1ad36..aefc7a3a0 100644 --- a/src/core/login/splitting.ts +++ b/src/core/login/splitting.ts @@ -147,7 +147,7 @@ export async function splitWalletInfo( walletInfos[newWalletInfo.id] = { archived: false, deleted: false, - migratedFromWalletId: undefined + migratedFromWalletId: existingWalletInfo.migratedFromWalletId } await changeWalletStates(ai, accountId, walletInfos) return newWalletInfo.id @@ -157,7 +157,7 @@ export async function splitWalletInfo( } // Add the keys to the login: - const kit = makeKeysKit(ai, sessionKey, [newWalletInfo]) + const kit = makeKeysKit(ai, sessionKey, [newWalletInfo], true) await applyKit(ai, sessionKey, kit) // Try to copy metadata on a best-effort basis. diff --git a/src/types/server-cleaners.ts b/src/types/server-cleaners.ts index e135c8c9d..84db52cd8 100644 --- a/src/types/server-cleaners.ts +++ b/src/types/server-cleaners.ts @@ -245,6 +245,7 @@ export const asChangeVouchersPayload: Cleaner = asObject( ) export const asCreateKeysPayload: Cleaner = asObject({ + allowExisting: asOptional(asBoolean, false), keyBoxes: asArray(asEdgeBox), newSyncKeys: asOptional(asArray(asString), () => []) }) diff --git a/src/types/server-types.ts b/src/types/server-types.ts index eaed80a88..885c7a406 100644 --- a/src/types/server-types.ts +++ b/src/types/server-types.ts @@ -168,6 +168,7 @@ export interface ChangeVouchersPayload { } export interface CreateKeysPayload { + allowExisting: boolean keyBoxes: EdgeBox[] newSyncKeys: string[] }