|
1 | 1 | import { expect, test } from '@playwright/test'; |
| 2 | +import * as crypto from 'node:crypto'; |
| 3 | +import * as fs from 'node:fs'; |
| 4 | +import * as path from 'node:path'; |
2 | 5 | import { generateECDSAKeyPair, generateEd25519KeyPair } from '../../utils/crypto/keyUtil.js'; |
3 | 6 | import { setupSettingsKeysSuite } from '../helpers/fixtures/settingsKeysSuite.js'; |
| 7 | +import { fileURLToPath } from 'node:url'; |
| 8 | +import { clearDialogMockState, setDialogMockState } from '../../utils/runtime/dialogMocks.js'; |
4 | 9 |
|
5 | 10 | test.describe('Settings keys import tests @local-basic', () => { |
6 | 11 | const suite = setupSettingsKeysSuite(); |
@@ -53,6 +58,56 @@ test.describe('Settings keys import tests @local-basic', () => { |
53 | 58 | expect(publicKey).toBeTruthy(); |
54 | 59 | }); |
55 | 60 |
|
| 61 | + test('Verify user can import an encrypted private key', async () => { |
| 62 | + // Generate private key and encrypt it with a password |
| 63 | + const password = 'encrypted-key-password'; |
| 64 | + const privateKey = crypto |
| 65 | + .createPrivateKey({ |
| 66 | + key: Buffer.from(generateEd25519KeyPair().privateKey, 'hex'), |
| 67 | + type: 'pkcs8', |
| 68 | + format: 'der', |
| 69 | + }) |
| 70 | + .export({ type: 'pkcs8', format: 'pem', cipher: 'aes-256-cbc', passphrase: password }); |
| 71 | + |
| 72 | + // Ensure the data directory exists |
| 73 | + const __filename = fileURLToPath(import.meta.url); |
| 74 | + const __dirname = path.dirname(__filename); |
| 75 | + const dataDirectory = path.resolve(__dirname, '../../data'); |
| 76 | + if (!fs.existsSync(dataDirectory)) { |
| 77 | + fs.mkdirSync(dataDirectory, { recursive: true }); |
| 78 | + } |
| 79 | + |
| 80 | + // Write the file |
| 81 | + const fileName = `encrypted-import-${Date.now()}.pem`; |
| 82 | + const filePath = path.resolve(dataDirectory, fileName); |
| 83 | + fs.writeFileSync(filePath, privateKey); |
| 84 | + |
| 85 | + console.log(`Encrypted private key file generated at: ${filePath}`); |
| 86 | + |
| 87 | + try { |
| 88 | + await suite.settingsPage.clickOnKeysTab(); |
| 89 | + await suite.settingsPage.clickOnImportButton(); |
| 90 | + await suite.settingsPage.clickOnEncryptedKeysDropdown(); |
| 91 | + |
| 92 | + // Browse opens Electron's native dialog through IPC, not a browser file chooser. |
| 93 | + await setDialogMockState(suite.window, { openPaths: [filePath] }); |
| 94 | + await suite.settingsPage.clickOnBrowseEncryptedKeyButton(); |
| 95 | + await suite.settingsPage.clickOnImportEncryptedKeyButton(); |
| 96 | + |
| 97 | + await suite.settingsPage.clickOnSkipImportRecoveryPhraseButton(); |
| 98 | + await suite.settingsPage.fillInDecryptKeysPassword(password); |
| 99 | + await suite.settingsPage.clickOnDecryptEncryptedKeyButton(); |
| 100 | + |
| 101 | + await expect.poll(() => suite.settingsPage.getKeyRowCount()).toBe(2); |
| 102 | + await expect |
| 103 | + .poll(() => suite.registrationPage.getToastMessage()) |
| 104 | + .toBe('Keys imported successfully'); |
| 105 | + } finally { |
| 106 | + await clearDialogMockState(suite.window); |
| 107 | + fs.rmSync(filePath, { force: true }); |
| 108 | + } |
| 109 | + }); |
| 110 | + |
56 | 111 | test('Verify user can filter keys by All, Recovery Phrase, and Private Key', async () => { |
57 | 112 | await suite.settingsPage.clickOnKeysTab(); |
58 | 113 |
|
|
0 commit comments