Skip to content

Commit 1a0901f

Browse files
committed
feat(recovery): send backup public keys for validation during account recovery
1 parent ba121e0 commit 1a0901f

5 files changed

Lines changed: 44 additions & 14 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"@iconscout/react-unicons": "^1.1.6",
99
"@internxt/css-config": "1.1.0",
1010
"@internxt/lib": "1.4.1",
11-
"@internxt/sdk": "=1.11.17",
11+
"@internxt/sdk": "=1.12.0",
1212
"@internxt/ui": "0.1.1",
1313
"@phosphor-icons/react": "^2.1.7",
1414
"@popperjs/core": "^2.11.6",

src/services/auth.service.test.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,7 @@ describe('updateCredentialsWithToken', () => {
687687
expect(keys).toBeUndefined();
688688
});
689689

690-
it('should successfully update credentials with token and with backup data (ECC only)', async () => {
690+
it('should not send keys when backup data has no publicKeys (legacy backup)', async () => {
691691
const mockToken = 'test-reset-token';
692692
const mockNewPassword = 'newPassword123';
693693
const mockMnemonic =
@@ -721,13 +721,10 @@ describe('updateCredentialsWithToken', () => {
721721
expect(encryptedPassword).toBeDefined();
722722
expect(encryptedSalt).toBeDefined();
723723
expect(encryptedMnemonic).toBeDefined();
724-
expect(keys).toBeDefined();
725-
726-
expect(keys.ecc).toBe('mock-encrypted-data');
727-
expect(keys.kyber).toBeUndefined();
724+
expect(keys).toBeUndefined();
728725
});
729726

730-
it('should successfully update credentials with token and with backup data (ECC and Kyber)', async () => {
727+
it('should send both private and public keys when backup data has publicKeys', async () => {
731728
const mockToken = 'test-reset-token';
732729
const mockNewPassword = 'newPassword123';
733730
const mockMnemonic =
@@ -739,6 +736,10 @@ describe('updateCredentialsWithToken', () => {
739736
ecc: 'test-ecc-private-key',
740737
kyber: 'test-kyber-private-key',
741738
},
739+
publicKeys: {
740+
ecc: 'test-ecc-public-key',
741+
kyber: 'test-kyber-public-key',
742+
},
742743
};
743744

744745
(validateMnemonic as any).mockReturnValue(true);
@@ -763,8 +764,12 @@ describe('updateCredentialsWithToken', () => {
763764
expect(encryptedMnemonic).toBeDefined();
764765
expect(keys).toBeDefined();
765766

766-
expect(keys.ecc).toBe('mock-encrypted-data');
767-
expect(keys.kyber).toBe('mock-encrypted-data');
767+
expect(keys.private.ecc).toBe('mock-encrypted-data');
768+
expect(keys.private.kyber).toBe('mock-encrypted-data');
769+
expect(keys.public).toEqual({
770+
ecc: 'test-ecc-public-key',
771+
kyber: 'test-kyber-public-key',
772+
});
768773
});
769774

770775
it('should throw an error when mnemonic is invalid', async () => {

src/services/auth.service.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,14 +339,22 @@ export const updateCredentialsWithToken = async (
339339

340340
const authClient = SdkFactory.getNewApiInstance().createAuthClient();
341341

342-
const keys =
342+
const privateKeys =
343343
encryptedEccPrivateKey || encryptedKyberPrivateKey
344344
? {
345345
ecc: encryptedEccPrivateKey,
346346
kyber: encryptedKyberPrivateKey,
347347
}
348348
: undefined;
349349

350+
const keys =
351+
privateKeys && backupData?.publicKeys
352+
? {
353+
private: privateKeys,
354+
public: backupData?.publicKeys,
355+
}
356+
: undefined;
357+
350358
return authClient.changePasswordWithLinkV2(
351359
token,
352360
encryptedHashedNewPassword,

src/utils/backupKeyUtils.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import { encryptMessageWithPublicKey, hybridEncryptMessageWithPublicKey } from '
1616
* @property {Object} keys - The user's encryption keys
1717
* @property {string} keys.ecc - The user's ECC private key
1818
* @property {string} keys.kyber - The user's Kyber private key
19+
* @property {Object} [publicKeys] - The user's public keys (for backup validation)
20+
* @property {string} [publicKeys.ecc] - The user's ECC public key
21+
* @property {string} [publicKeys.kyber] - The user's Kyber public key
1922
*/
2023
export interface BackupData {
2124
mnemonic: string;
@@ -24,6 +27,10 @@ export interface BackupData {
2427
ecc: string;
2528
kyber: string;
2629
};
30+
publicKeys?: {
31+
ecc?: string;
32+
kyber?: string;
33+
};
2734
}
2835

2936
/**
@@ -49,6 +56,10 @@ export function handleExportBackupKey(translate) {
4956
ecc: user.keys?.ecc?.privateKey || user.privateKey,
5057
kyber: user.keys?.kyber?.privateKey || '',
5158
},
59+
publicKeys: {
60+
ecc: user.keys?.ecc?.publicKey || '',
61+
kyber: user.keys?.kyber?.publicKey || '',
62+
},
5263
};
5364

5465
const backupContent = JSON.stringify(backupData, null, 2);
@@ -84,6 +95,12 @@ export const detectBackupKeyFormat = (
8495
ecc: parsedData.keys.ecc,
8596
kyber: parsedData.keys.kyber,
8697
},
98+
publicKeys: parsedData.publicKeys
99+
? {
100+
ecc: parsedData.publicKeys.ecc,
101+
kyber: parsedData.publicKeys.kyber,
102+
}
103+
: undefined,
87104
};
88105
return {
89106
type: 'new',

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,10 +1906,10 @@
19061906
version "1.0.2"
19071907
resolved "https://codeload.github.com/internxt/prettier-config/tar.gz/9fa74e9a2805e1538b50c3809324f1c9d0f3e4f9"
19081908

1909-
"@internxt/sdk@=1.11.17":
1910-
version "1.11.17"
1911-
resolved "https://registry.yarnpkg.com/@internxt/sdk/-/sdk-1.11.17.tgz#2f5bdada5d3cbf5cfc685a21c24b5df3ff51d8c8"
1912-
integrity sha512-91iEUvZizlwX6KBEFJ3JdFiGrhMBQ9R54sTc3Pei9QtV2FYTU8nTVEPYAg39tLOGzT/kVuplYOtBxfk6wFtSDA==
1909+
"@internxt/sdk@=1.12.0":
1910+
version "1.12.0"
1911+
resolved "https://npm.pkg.github.com/download/@internxt/sdk/1.12.0/9555d9e53cc9ee728e5c56746a969a4d61792e5a#9555d9e53cc9ee728e5c56746a969a4d61792e5a"
1912+
integrity sha512-W5DS3ligEoE7YSuqKBh9dzVMpTPa+1LGJAGfGP+51zJZ8KfzeDDVBgaNRxTwBnbUYNZ3nvQJkA28AN6Vk8TqQA==
19131913
dependencies:
19141914
axios "1.13.2"
19151915
uuid "11.1.0"

0 commit comments

Comments
 (0)