Skip to content

[DDW-563] Re-enable wallet import feature #2308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Feb 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b271112
add utility code for decoding legacy keystores from cardano-sl
KtorZ Jan 19, 2021
5a7e5ab
Merge branch 'develop' into KtorZ/1234/legacy-keystore
nikolaglumac Jan 21, 2021
c27198d
Merge branch 'develop' into KtorZ/1234/legacy-keystore
nikolaglumac Jan 28, 2021
a46e4ce
Merge branch 'develop' into KtorZ/1234/legacy-keystore
nikolaglumac Jan 29, 2021
5b5c59b
Merge branch 'develop' into KtorZ/1234/legacy-keystore
nikolaglumac Jan 29, 2021
8f9c607
Merge branch 'develop' into KtorZ/1234/legacy-keystore
nikolaglumac Feb 1, 2021
5c4d389
Merge branch 'develop' into KtorZ/1234/legacy-keystore
nikolaglumac Feb 5, 2021
a82994e
add 'executable' to restore and show a keystore at a given path
KtorZ Feb 8, 2021
b4fcef4
[DDW-563] Import TS
nikolaglumac Feb 9, 2021
e915a10
[DDW-563] Integrate restore-keystore lib
nikolaglumac Feb 10, 2021
f2d5752
Merge branch 'develop' into KtorZ/1234/legacy-keystore
nikolaglumac Feb 10, 2021
28a387b
[DDW-563] Adds CHANGELOG, improves import
nikolaglumac Feb 10, 2021
d5f26c7
[DDW-563] Improve import
nikolaglumac Feb 10, 2021
9bd9d06
[DDW-563] Move restore-keystore.js into Release
nikolaglumac Feb 10, 2021
7fc4867
[DDW-563] Force add dist dir to GH
nikolaglumac Feb 10, 2021
e88b4af
[DDW-563] Remove unnecessary files
nikolaglumac Feb 10, 2021
5bfb486
[DDW-563] Styling fixes
nikolaglumac Feb 10, 2021
6e5532e
[DDW-563] Merges develop
nikolaglumac Feb 11, 2021
d8d3ca7
[DDW-563] Merges develop
nikolaglumac Feb 11, 2021
1f1ba29
[DDW-563] Updates text copy
nikolaglumac Feb 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Changelog

### Features

- Re-enabled "Wallet import" feature ([PR 2308](https://github.com/input-output-hk/daedalus/pull/2308))
- Implemented Voting Centar ([PR 2315](https://github.com/input-output-hk/daedalus/pull/2315), [PR 2353](https://github.com/input-output-hk/daedalus/pull/2353), [PR 2354](https://github.com/input-output-hk/daedalus/pull/2354))
- Implemented transaction metadata display ([PR 2338](https://github.com/input-output-hk/daedalus/pull/2338))
- Displayed fee and deposit info in transaction details and in the delegation wizard ([PR 2339](https://github.com/input-output-hk/daedalus/pull/2339))
Expand Down
47 changes: 21 additions & 26 deletions source/main/cardano/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { spawnSync } from 'child_process';
import { logger } from '../utils/logging';
import { getTranslation } from '../utils/getTranslation';
import ensureDirectoryExists from '../utils/ensureDirectoryExists';
import { decodeKeystore } from '../utils/restoreKeystore';
import type { LauncherConfig } from '../config';
import type { ExportWalletsMainResponse } from '../../common/ipc/api';
import type {
Expand All @@ -19,7 +20,6 @@ import {
CardanoProcessNameOptions,
CardanoNodeImplementationOptions,
NetworkNameOptions,
TESTNET_MAGIC,
} from '../../common/types/cardano-node.types';

export type Process = {
Expand Down Expand Up @@ -176,7 +176,6 @@ export const exportWallets = async (
locale: string
): Promise<ExportWalletsMainResponse> => {
const {
exportWalletsBin,
legacySecretKey,
legacyWalletDB,
stateDir,
Expand All @@ -186,7 +185,6 @@ export const exportWallets = async (

logger.info('ipcMain: Starting wallets export...', {
exportSourcePath,
exportWalletsBin,
legacySecretKey,
legacyWalletDB,
stateDir,
Expand Down Expand Up @@ -226,41 +224,38 @@ export const exportWallets = async (
}
}

// Export tool flags
const exportWalletsBinFlags = [];

// Cluster flags
if (cluster === 'testnet') {
exportWalletsBinFlags.push('--testnet', TESTNET_MAGIC.toString());
} else {
exportWalletsBinFlags.push('--mainnet');
}

// Secret key flags
exportWalletsBinFlags.push('--keyfile', legacySecretKeyPath);

// Wallet DB flags
const legacyWalletDBPathExists = await fs.pathExists(
`${legacyWalletDBPath}-acid`
);
if (legacyWalletDBPathExists) {
exportWalletsBinFlags.push('--wallet-db-path', legacyWalletDBPath);
}

logger.info('ipcMain: Exporting wallets...', {
exportWalletsBin,
exportWalletsBinFlags,
legacySecretKeyPath,
legacyWalletDBPath,
legacyWalletDBPathExists,
});

const { stdout, stderr } = spawnSync(exportWalletsBin, exportWalletsBinFlags);
const wallets = JSON.parse(stdout.toString() || '[]');
const errors = stderr.toString();
let wallets = [];
let errors = '';
try {
const legacySecretKeyFile = fs.readFileSync(legacySecretKeyPath);
// $FlowFixMe
const rawWallets = await decodeKeystore(legacySecretKeyFile);
wallets = rawWallets.map((w) => ({
name: null,
id: w.walletId,
isEmptyPassphrase: w.isEmptyPassphrase,
passphrase_hash: w.passphraseHash.toString('hex'),
encrypted_root_private_key: w.encryptedPayload.toString('hex'),
}));
} catch (error) {
errors = error.toString();
}

logger.info(`ipcMain: Exported ${wallets.length} wallets`, {
walletsData: wallets.map((w) => ({
name: w.name,
id: w.id,
hasPassword: w.is_passphrase_empty,
hasPassword: !w.isEmptyPassphrase,
})),
errors,
});
Expand Down
1 change: 0 additions & 1 deletion source/main/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export type LauncherConfig = {
configPath: string,
syncTolerance: string,
cliBin: string,
exportWalletsBin: string,
legacyStateDir: string,
legacySecretKey: string,
legacyWalletDB: string,
Expand Down
52 changes: 52 additions & 0 deletions source/main/utils/restoreKeystore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// @flow
import * as cbor from 'cbor';
import * as blake2b from 'blake2b';
import * as crypto from 'crypto';

export type EncryptedSecretKeys = Array<EncryptedSecretKey>;

export type EncryptedSecretKey = {
encryptedPayload: Buffer,
passphraseHash: Buffer,
isEmptyPassphrase: boolean,
walletId: WalletId,
};

export type WalletId = string;

export const decodeKeystore = async (
bytes: Buffer
): Promise<EncryptedSecretKeys> => {
return cbor
.decodeAll(bytes)
.then((obj) => obj[0][2].map(toEncryptedSecretKey));
};

const toEncryptedSecretKey = ([encryptedPayload, passphraseHash]: [
Buffer,
Buffer
]): EncryptedSecretKey => {
const isEmptyPassphrase = $isEmptyPassphrase(passphraseHash);
return {
walletId: mkWalletId(encryptedPayload),
encryptedPayload,
passphraseHash,
isEmptyPassphrase,
};
};

const mkWalletId = (xprv: Buffer): WalletId => {
const xpub = xprv.slice(64);
return blake2b(20).update(xpub).digest('hex');
};

const $isEmptyPassphrase = (pwd: Buffer): boolean => {
const cborEmptyBytes = Buffer.from('40', 'hex');
const [logN, r, p, salt, hashA] = pwd.toString('utf8').split('|');
const opts = { N: 2 ** Number(logN), r: Number(r), p: Number(p) };
// $FlowFixMe
const hashB = crypto
.scryptSync(cborEmptyBytes, Buffer.from(salt, 'base64'), 32, opts)
.toString('base64');
return hashA === hashB;
};
1 change: 0 additions & 1 deletion source/renderer/app/components/wallet/WalletAdd.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ export default class WalletAdd extends Component<Props> {
label={intl.formatMessage(messages.importLabel)}
description={intl.formatMessage(messages.importDescription)}
isDisabled={
true || // This feature is currently unavailable as export tool is disabled
isMaxNumberOfWalletsReached ||
(isProduction && !(isMainnet || isTestnet))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export default class WalletSelectImportDialog extends Component<Props> {
walletStatus = alreadyExistsStatus;
} else if (wallet.import.status === WalletImportStatuses.COMPLETED) {
walletStatus = walletImportedStatus;
} else if (wallet.is_passphrase_empty) {
} else if (wallet.isEmptyPassphrase) {
walletStatus = noPasswordStatus;
} else {
walletStatus = hasPasswordStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@
display: flex;
padding-right: 20px;

:global {
.InlineEditingSmallInput_component {
margin-bottom: 0 !important;
}
}

.walletsInputFieldInner {
input {
color: var(--theme-wallet-import-button-text-color);
Expand Down Expand Up @@ -258,6 +264,14 @@
margin-top: -3px;
}
}

.LoadingSpinner_component {
margin: 0 !important;

.LoadingSpinner_icon svg path {
fill: var(--theme-wallet-import-button-text-color) !important;
}
}
}

.walletsStatusIconCheckmark {
Expand Down
3 changes: 3 additions & 0 deletions source/renderer/app/config/walletsConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,8 @@ export const RECOVERY_PHRASE_WORD_COUNT_OPTIONS = {
export const WALLET_PUBLIC_KEY_NOTIFICATION_SEGMENT_LENGTH = 15;
export const WALLET_PUBLIC_KEY_SHARING_ENABLED = false;

// Automatic wallet migration from pre Daedalus 1.0.0 versions has been disabled
export const IS_AUTOMATIC_WALLET_MIGRATION_ENABLED = false;

// Byron wallet migration has been temporarily disabled due to missing Api support after Mary HF
export const IS_BYRON_WALLET_MIGRATION_ENABLED = false;
2 changes: 1 addition & 1 deletion source/renderer/app/i18n/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@
"wallet.hardware.deviceStatus.wrong_firmware.link.label": "Firmware update instructions",
"wallet.hardware.deviceStatus.wrong_firmware.link.url": "https://trezor.io/start/",
"wallet.import.file.dialog.buttonLabel": "Import wallets",
"wallet.import.file.dialog.description": "<p>This feature enables you to import wallets from the previous version of Daedalus, from the Daedalus state directory, or from a ‘secret.key’ file.</p> <p>It can be used to import wallets quickly without entering the wallet recovery phrase for each wallet, or to import wallets for which you have lost your wallet recovery phrase.</p> <p>After importing a wallet for which you have lost your wallet recovery phrase, please create a new wallet and transfer all funds from the old wallet to the new wallet. <strong>Keep the wallet recovery phrase for your new wallet secure.</strong></p>",
"wallet.import.file.dialog.description": "<p>This feature enables you to import wallets from ‘secret.key’ files of old versions of Daedalus (Daedalus version 0.15.1 and previous). Importing wallets from state directories of version Daedalus 1.0 onwards is currently not supported.</p> <p>It can be used to import wallets quickly without entering the wallet recovery phrase for each wallet, or to import wallets for which you have lost your wallet recovery phrase.</p> <p>After importing a wallet for which you have lost your wallet recovery phrase, please create a new wallet and transfer all funds from the old wallet to the new wallet. <strong>Keep the wallet recovery phrase for your new wallet secure.</strong></p>",
"wallet.import.file.dialog.importFromLabel": "Import from:",
"wallet.import.file.dialog.linkLabel": "Learn more",
"wallet.import.file.dialog.linkUrl": "https://iohk.zendesk.com/hc/en-us/articles/900000623463",
Expand Down
2 changes: 1 addition & 1 deletion source/renderer/app/i18n/locales/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@
"wallet.hardware.deviceStatus.wrong_firmware.link.label": "ファームウェア更新ガイド",
"wallet.hardware.deviceStatus.wrong_firmware.link.url": "https://trezor.io/start/",
"wallet.import.file.dialog.buttonLabel": "ウォレットをインポートする",
"wallet.import.file.dialog.description": "<p>この機能により、Daedalusの旧バージョン、Daedalusステータスディレクトリー、またはsecret.keyファイルからウォレットをインポートすることができます。</p> <p>各ウォレットの復元フレーズを入力せずに素早くウォレットをインポートできるほか、復元フレーズを紛失したウォレットのインポートも可能です。</p> <p>復元フレーズを紛失したウォレットをインポートした場合は、インポート後に新規ウォレットを作成してすべての資金を旧ウォレットから移し、<strong>新しいウォレットの復元フレーズを安全な場所に保管してください。</strong></p>",
"wallet.import.file.dialog.description": "<p>この機能により、Daedalus旧バージョン(Daedalus 0.15.1以前)の「secret.key」からウォレットをインポートすることができます。Daedalus 1.0以降のステータスディレクトリーからのウォレットインポートは現在サポートされていません。</p> <p>各ウォレットの復元フレーズを入力せずに素早くウォレットをインポートできるほか、復元フレーズを紛失したウォレットのインポートも可能です。</p> <p>復元フレーズを紛失したウォレットをインポートした場合は、インポート後に新規ウォレットを作成してすべての資金を旧ウォレットから移し、<strong>新しいウォレットの復元フレーズを安全な場所に保管してください。</strong></p>",
"wallet.import.file.dialog.importFromLabel": "インポート元:",
"wallet.import.file.dialog.linkLabel": "もっと知る",
"wallet.import.file.dialog.linkUrl": "https://iohk.zendesk.com/hc/ja/articles/900000623463",
Expand Down
14 changes: 7 additions & 7 deletions source/renderer/app/stores/WalletMigrationStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
ImportFromOptions,
} from '../types/walletExportTypes';
import { IMPORT_WALLET_STEPS } from '../config/walletRestoreConfig';
import { IS_AUTOMATIC_WALLET_MIGRATION_ENABLED } from '../config/walletsConfig';
import type { ImportWalletStep } from '../types/walletRestoreTypes';

export type WalletMigrationStatus =
Expand Down Expand Up @@ -245,7 +246,7 @@ export default class WalletMigrationStore extends Store {
: WalletImportStatuses.UNSTARTED;
return { ...wallet, hasName, import: { status, error: null } };
}),
['hasName', 'id', 'name', 'is_passphrase_empty'],
['hasName', 'id', 'name', 'isEmptyPassphrase'],
['desc', 'asc', 'asc', 'asc']
);

Expand Down Expand Up @@ -286,7 +287,7 @@ export default class WalletMigrationStore extends Store {
{
id: wallet.id,
name: wallet.name,
hasPassword: wallet.is_passphrase_empty,
hasPassword: !wallet.isEmptyPassphrase,
}
);
return this._restoreWallet(wallet);
Expand Down Expand Up @@ -333,15 +334,15 @@ export default class WalletMigrationStore extends Store {
});
} catch (error) {
runInAction('update restorationErrors', () => {
const { name, is_passphrase_empty: hasPassword } = exportedWallet;
const { name, isEmptyPassphrase } = exportedWallet;
this._updateWalletImportStatus(
index,
WalletImportStatuses.ERRORED,
error
);
this.restorationErrors.push({
error,
wallet: { id, name, hasPassword },
wallet: { id, name, hasPassword: !isEmptyPassphrase },
});
});
}
Expand Down Expand Up @@ -381,8 +382,7 @@ export default class WalletMigrationStore extends Store {
};

@action _startMigration = async () => {
// eslint-disable-next-line
if (true) return; // This feature is currently unavailable as export tool is disabled
if (!IS_AUTOMATIC_WALLET_MIGRATION_ENABLED) return;

const { isMainnet, isTestnet, isTest } = this.environment;
if (isMainnet || isTestnet || (isTest && this.isTestMigrationEnabled)) {
Expand Down Expand Up @@ -514,7 +514,7 @@ export default class WalletMigrationStore extends Store {
return this.exportedWallets.map((wallet) => ({
id: wallet.id,
name: wallet.name,
hasPassword: wallet.is_passphrase_empty,
hasPassword: !wallet.isEmptyPassphrase,
import: wallet.import,
}));
}
Expand Down
2 changes: 1 addition & 1 deletion source/renderer/app/types/walletExportTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type ExportedByronWallet = {
name: ?string,
id: string,
passphrase_hash: string,
is_passphrase_empty: boolean,
isEmptyPassphrase: boolean,

// Daedalus derived wallet props
hasName: boolean,
Expand Down