Use file-saver to export accounts (#701)

* use file-saver

* bring back the fake implementation

* we never know

* fix background test
This commit is contained in:
Thibaut Sardan 2021-04-22 14:34:14 +02:00 committed by GitHub
parent f4308112f7
commit 5a45e1daea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 41 additions and 22 deletions

View File

@ -69,8 +69,8 @@ describe('Extension', () => {
password
}, {} as chrome.runtime.Port);
expect(result.exportedJson).toContain(address);
expect(result.exportedJson).toContain('"encoded"');
expect(result.exportedJson.address).toBe(address);
expect(result.exportedJson.encoded).toBeDefined();
});
describe('account derivation', () => {

View File

@ -5,7 +5,7 @@ import type { MetadataDef } from '@polkadot/extension-inject/types';
import type { KeyringPair, KeyringPair$Json, KeyringPair$Meta } from '@polkadot/keyring/types';
import type { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types';
import type { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
import type { AccountJson, AllowedPath, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountBatchExport, RequestAccountChangePassword, RequestAccountCreateExternal, RequestAccountCreateHardware, RequestAccountCreateSuri, RequestAccountEdit, RequestAccountExport, RequestAccountForget, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestAuthorizeApprove, RequestAuthorizeReject, RequestBatchRestore, RequestDeriveCreate, RequestDeriveValidate, RequestJsonRestore, RequestMetadataApprove, RequestMetadataReject, RequestSeedCreate, RequestSeedValidate, RequestSigningApprovePassword, RequestSigningApproveSignature, RequestSigningCancel, RequestSigningIsLocked, RequestTypes, ResponseAccountExport, ResponseAuthorizeList, ResponseDeriveValidate, ResponseJsonGetAccountInfo, ResponseSeedCreate, ResponseSeedValidate, ResponseSigningIsLocked, ResponseType, SigningRequest } from '../types';
import type { AccountJson, AllowedPath, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountBatchExport, RequestAccountChangePassword, RequestAccountCreateExternal, RequestAccountCreateHardware, RequestAccountCreateSuri, RequestAccountEdit, RequestAccountExport, RequestAccountForget, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestAuthorizeApprove, RequestAuthorizeReject, RequestBatchRestore, RequestDeriveCreate, RequestDeriveValidate, RequestJsonRestore, RequestMetadataApprove, RequestMetadataReject, RequestSeedCreate, RequestSeedValidate, RequestSigningApprovePassword, RequestSigningApproveSignature, RequestSigningCancel, RequestSigningIsLocked, RequestTypes, ResponseAccountExport, ResponseAccountsExport, ResponseAuthorizeList, ResponseDeriveValidate, ResponseJsonGetAccountInfo, ResponseSeedCreate, ResponseSeedValidate, ResponseSigningIsLocked, ResponseType, SigningRequest } from '../types';
import { ALLOWED_PATH, PASSWORD_EXPIRY_MS } from '@polkadot/extension-base/defaults';
import chrome from '@polkadot/extension-inject/chrome';
@ -97,14 +97,12 @@ export default class Extension {
}
private accountsExport ({ address, password }: RequestAccountExport): ResponseAccountExport {
return { exportedJson: JSON.stringify(keyring.backupAccount(keyring.getPair(address), password)) };
return { exportedJson: keyring.backupAccount(keyring.getPair(address), password) };
}
private async accountsBatchExport ({ addresses, password }: RequestAccountBatchExport): Promise<ResponseAccountExport> {
private async accountsBatchExport ({ addresses, password }: RequestAccountBatchExport): Promise<ResponseAccountsExport> {
return {
exportedJson: JSON.stringify(
await keyring.backupAccounts(addresses, password)
)
exportedJson: await keyring.backupAccounts(addresses, password)
};
}

View File

@ -79,7 +79,7 @@ export interface RequestSignatures {
'pri(accounts.create.suri)': [RequestAccountCreateSuri, boolean];
'pri(accounts.edit)': [RequestAccountEdit, boolean];
'pri(accounts.export)': [RequestAccountExport, ResponseAccountExport];
'pri(accounts.batchExport)': [RequestAccountBatchExport, ResponseAccountExport]
'pri(accounts.batchExport)': [RequestAccountBatchExport, ResponseAccountsExport]
'pri(accounts.forget)': [RequestAccountForget, boolean];
'pri(accounts.show)': [RequestAccountShow, boolean];
'pri(accounts.tie)': [RequestAccountTie, boolean];
@ -352,7 +352,11 @@ export interface ResponseSeedValidate {
}
export interface ResponseAccountExport {
exportedJson: string;
exportedJson: KeyringPair$Json;
}
export interface ResponseAccountsExport {
exportedJson: KeyringPairs$Json;
}
export type ResponseRpcListProviders = ProviderList;

View File

@ -21,6 +21,7 @@
"@polkadot/react-qr": "^0.72.1",
"@polkadot/util": "^6.0.5",
"@polkadot/util-crypto": "^6.0.5",
"file-saver": "^2.0.5",
"i18next": "^19.9.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
@ -35,6 +36,7 @@
"@types/bn.js": "^4.11.6",
"@types/enzyme": "^3.10.8",
"@types/enzyme-adapter-react-16": "^1.0.6",
"@types/file-saver": "^2.0.2",
"@types/react-copy-to-clipboard": "^5.0.0",
"@types/react-dom": "^17.0.3",
"@types/react-router": "^5.1.13",

View File

@ -10,6 +10,8 @@ import { act } from 'react-dom/test-utils';
import { MemoryRouter, Route } from 'react-router';
import { ThemeProvider } from 'styled-components';
import { KeyringPair$Json } from '@polkadot/keyring/types';
import { Button, themes } from '../components';
import * as messaging from '../messaging';
import { flushAllPromises } from '../testHelpers';
@ -27,7 +29,7 @@ describe('Export component', () => {
};
beforeEach(() => {
jest.spyOn(messaging, 'exportAccount').mockResolvedValue({ exportedJson: '{ "meta": { "name": "account_name" } }' });
jest.spyOn(messaging, 'exportAccount').mockResolvedValue({ exportedJson: { meta: { name: 'account_name' } } as unknown as KeyringPair$Json });
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
wrapper = mount(

View File

@ -3,6 +3,7 @@
import type { ThemeProps } from '../types';
import { saveAs } from 'file-saver';
import React, { useCallback, useContext, useState } from 'react';
import { RouteComponentProps, withRouter } from 'react-router';
import styled from 'styled-components';
@ -43,12 +44,9 @@ function Export ({ className, match: { params: { address } } }: Props): React.Re
exportAccount(address, pass)
.then(({ exportedJson }) => {
const element = document.createElement('a');
const { meta } = JSON.parse(exportedJson) as { meta: { name: string } };
const blob = new Blob([JSON.stringify(exportedJson)], { type: 'application/json; charset=utf-8' });
element.href = `data:text/plain;charset=utf-8,${exportedJson}`;
element.download = `${meta.name}_exported_account_${Date.now()}.json`;
element.click();
saveAs(blob, `${address}.json`);
onAction('/');
})

View File

@ -3,6 +3,7 @@
import type { ThemeProps } from '../types';
import { saveAs } from 'file-saver';
import React, { useCallback, useContext, useState } from 'react';
import { RouteComponentProps, withRouter } from 'react-router';
import styled from 'styled-components';
@ -44,11 +45,9 @@ function ExportAll ({ className }: Props): React.ReactElement<Props> {
exportAccounts(accounts.map((account) => account.address), pass)
.then(({ exportedJson }) => {
const element = document.createElement('a');
const blob = new Blob([JSON.stringify(exportedJson)], { type: 'application/json; charset=utf-8' });
element.href = `data:text/plain;charset=utf-8,${exportedJson}`;
element.download = `batch_exported_account_${Date.now()}.json`;
element.click();
saveAs(blob, `batch_exported_account_${Date.now()}.json`);
onAction('/');
})

View File

@ -79,11 +79,11 @@ export async function tieAccount (address: string, genesisHash: string | null):
return sendMessage('pri(accounts.tie)', { address, genesisHash });
}
export async function exportAccount (address: string, password: string): Promise<{ exportedJson: string }> {
export async function exportAccount (address: string, password: string): Promise<{ exportedJson: KeyringPair$Json }> {
return sendMessage('pri(accounts.export)', { address, password });
}
export async function exportAccounts (addresses: string[], password: string): Promise<{ exportedJson: string }> {
export async function exportAccounts (addresses: string[], password: string): Promise<{ exportedJson: KeyringPairs$Json }> {
return sendMessage('pri(accounts.batchExport)', { addresses, password });
}

View File

@ -2150,6 +2150,7 @@ __metadata:
"@types/bn.js": ^4.11.6
"@types/enzyme": ^3.10.8
"@types/enzyme-adapter-react-16": ^1.0.6
"@types/file-saver": ^2.0.2
"@types/react-copy-to-clipboard": ^5.0.0
"@types/react-dom": ^17.0.3
"@types/react-router": ^5.1.13
@ -2159,6 +2160,7 @@ __metadata:
"@wojtekmaj/enzyme-adapter-react-17": ^0.6.0
enzyme: ^3.11.0
enzyme-adapter-react-16: ^1.15.6
file-saver: ^2.0.5
i18next: ^19.9.2
react: ^17.0.2
react-dom: ^17.0.2
@ -2787,6 +2789,13 @@ __metadata:
languageName: node
linkType: hard
"@types/file-saver@npm:^2.0.2":
version: 2.0.2
resolution: "@types/file-saver@npm:2.0.2"
checksum: ccdfbbe45c68b54192d1a9fb9c5f7594c7eabe64ad55982839f0e758b72a62ae0e2edcee16af2b7c197d53f57047b5e11dac5d7805326718d0cb5a5e2f4dc382
languageName: node
linkType: hard
"@types/filesystem@npm:*":
version: 0.0.29
resolution: "@types/filesystem@npm:0.0.29"
@ -7611,6 +7620,13 @@ __metadata:
languageName: node
linkType: hard
"file-saver@npm:^2.0.5":
version: 2.0.5
resolution: "file-saver@npm:2.0.5"
checksum: 0f835236534377c9b7591b995d94ae5061166452fb1f784548b706ff48984930e45a7947cfe393ce86b84ef2ec89064120c5d5ab5186146c508bb022c71ced3d
languageName: node
linkType: hard
"file-selector@npm:^0.2.2":
version: 0.2.4
resolution: "file-selector@npm:0.2.4"