Skip to content

Commit

Permalink
wip: metadata encryption version migration
Browse files Browse the repository at this point in the history
  • Loading branch information
mroz22 committed Aug 9, 2023
1 parent 924fe06 commit ab1b36a
Show file tree
Hide file tree
Showing 28 changed files with 984 additions and 467 deletions.
76 changes: 73 additions & 3 deletions packages/e2e-utils/src/mocks/dropbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const port = 30002;
* Mock implementation of Dropbox service intended to be used in e2e tests.
*/
export class DropboxMock {
files: Record<string, any> = {};
files: Record<string, Buffer> = {};
uploadSessionFiles: Record<string, Buffer> = {};
nextResponse: null | Record<string, any> = null;
// store requests for assertions in tests
requests: string[] = [];
Expand Down Expand Up @@ -139,6 +140,69 @@ export class DropboxMock {
res.end();
});

// https://api.dropboxapi.com/2/files/list_folder
app.post('/2/files/list_folder', (_req, res) => {
const entries = Object.keys(this.files).map(name => {
const formattedName = name.replace('/apps/trezor/', '');

return { name: formattedName };
});

res.write(
JSON.stringify({
entries,
}),
);

return res.send();
});

// https://api.dropboxapi.com/2/files/upload_session/start_batch
app.post('/2/files/upload_session/start_batch', (req, res) => {
const { num_sessions } = req.body as { num_sessions: number };

res.write(
JSON.stringify({
session_ids: Array.from({ length: num_sessions }, (_, i) => i),
}),
);

return res.send();
});

// https://content.dropboxapi.com/2/files/upload_session/append_v2
app.post('/2/files/upload_session/append_v2', (req, res) => {
// @ts-expect-error
const dropboxApiArgs = JSON.parse(req.headers['dropbox-api-arg']);
const { cursor } = dropboxApiArgs;
const file = req.body;

this.uploadSessionFiles[cursor.session_id] = file;

return res.send();
});

// https://content.dropboxapi.com/2/files/upload_session/finish_batch_v2
app.post('/2/files/upload_session/finish_batch_v2', (req, res) => {
const { entries } = req.body as {
entries: Array<{
cursor: {
session_id: number;
};
commit: {
path: string;
};
}>;
};

entries.forEach(({ cursor, commit }) => {
const file = this.uploadSessionFiles[cursor.session_id];
this.files[`/apps/trezor${commit.path.toLowerCase()}`] = file;
});

return res.send();
});

// https://content.dropboxapi.com/2/files/download
app.post('/2/files/download', (req, res) => {
// @ts-expect-error
Expand Down Expand Up @@ -169,8 +233,14 @@ export class DropboxMock {
(req, res) => {
// @ts-expect-error
const dropboxApiArgs = JSON.parse(req.headers['dropbox-api-arg']);
const { path } = dropboxApiArgs;
this.files[path.toLowerCase()] = req.body;
const { path } = dropboxApiArgs as { path: string };

let formattedPath = path;
if (!path.includes('apps/trezor')) {
formattedPath = `/apps/trezor${path}`;
}

this.files[formattedPath.toLowerCase()] = req.body;

res.send();
},
Expand Down
8 changes: 7 additions & 1 deletion packages/e2e-utils/src/mocks/google.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class File {
* Mock implementation of Google Drive service intended to be used in e2e tests.
*/
export class GoogleMock {
files: Record<string, any> = {};
files: Record<string, File> = {};
nextResponse: null | Record<string, any> = null;
// store requests for assertions in tests
requests: string[] = [];
Expand Down Expand Up @@ -154,6 +154,12 @@ export class GoogleMock {
});
});

app.get('/drive/api/v3/reference/files/list', express.json(), (_req, res) => {
res.json({
files: Object.keys(this.files),
});
});

app.get('/drive/v3/about', express.json(), (_req, res) => {
console.log('[mockGoogleDrive]: about');
res.send({
Expand Down
14 changes: 13 additions & 1 deletion packages/suite-web/e2e/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export default defineConfig({
addMatchImageSnapshotPlugin(on, config);
});
on('task', {
metadataStartProvider: async provider => {
metadataStartProvider: async (provider: 'dropbox' | 'google') => {
switch (provider) {
case 'dropbox':
await mocked.dropbox.start();
Expand Down Expand Up @@ -141,6 +141,18 @@ export default defineConfig({
throw new Error('not a valid case');
}
},
metadataGetFilesList: ({ provider }) => {
switch (provider) {
case 'dropbox':
return Object.keys(mocked.dropbox.files).map(name =>
name.replace('/apps/trezor/', ''),
);
case 'google':
return Object.keys(mocked.google.files);
default:
throw new Error('not a valid case');
}
},
startMockedBridge: async har => {
await mocked.bridge.start(har);
return null;
Expand Down
2 changes: 0 additions & 2 deletions packages/suite-web/e2e/support/utils/shortcuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ export const passThroughBackupShamir = (shares: number, threshold: number) => {
};

export const passThroughInitMetadata = (provider: 'dropbox' | 'google') => {
cy.getConfirmActionOnDeviceModal();
cy.task('pressYes');
cy.getTestElement(`@modal/metadata-provider/${provider}-button`).click();
cy.getTestElement('@modal/metadata-provider').should('not.exist');
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Hovering over fields that may be labeled shows "add label" button upon which is
cy.getTestElement('@metadata/input').type(
'{backspace}{backspace}{backspace}{backspace}{backspace}cool new label{enter}',
);

cy.getTestElement('@account-menu/btc/normal/0/label').should(
'contain',
'cool new label',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ describe('Dropbox api errors', () => {
// prepare some initial files
cy.task('metadataSetFileContent', {
provider: 'dropbox',
file: '/apps/trezor/f7acc942eeb83921892a95085e409b3e6b5325db6400ae5d8de523a305291dca.mtdt',
file: '/apps/trezor/b9b5e1fd2800d4dc68e2f4e775fd819f4da3fb9e1bcc2cacd7f04fa543eac8a0_2.mtdt',
content: {
version: '1.0.0',
accountLabel: 'already existing label',
outputLabels: {},
addressLabels: {},
},
aesKey: 'c785ef250807166bffc141960c525df97647fcc1bca57f6892ca3742ba86ed8d',
aesKey: '998daf71f3fbc486076f0ee8d5737a61b82bceacb0ec69100cbe4d45cd79676a',
});
cy.prefixedVisit('/', {
onBeforeLoad: (win: Window) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ const fixtures = [
{
provider: 'google',
desc: 'does NOT watch files over time',
file: 'f7acc942eeb83921892a95085e409b3e6b5325db6400ae5d8de523a305291dca.mtdt',
file: 'b9b5e1fd2800d4dc68e2f4e775fd819f4da3fb9e1bcc2cacd7f04fa543eac8a0_2.mtdt',
content: 'already existing label',
},
{
provider: 'dropbox',
desc: 'does watch files over time',
file: '/apps/trezor/f7acc942eeb83921892a95085e409b3e6b5325db6400ae5d8de523a305291dca.mtdt',
file: '/apps/trezor/b9b5e1fd2800d4dc68e2f4e775fd819f4da3fb9e1bcc2cacd7f04fa543eac8a0_2.mtdt',
content: 'label from another window',
},
] as const;
Expand Down Expand Up @@ -44,7 +44,7 @@ describe('Metadata - suite is watching cloud provider and syncs periodically', (
outputLabels: {},
addressLabels: {},
},
aesKey: 'c785ef250807166bffc141960c525df97647fcc1bca57f6892ca3742ba86ed8d',
aesKey: '998daf71f3fbc486076f0ee8d5737a61b82bceacb0ec69100cbe4d45cd79676a',
});
cy.prefixedVisit('/', {
onBeforeLoad: win => {
Expand Down Expand Up @@ -81,7 +81,7 @@ describe('Metadata - suite is watching cloud provider and syncs periodically', (
outputLabels: {},
addressLabels: {},
},
aesKey: 'c785ef250807166bffc141960c525df97647fcc1bca57f6892ca3742ba86ed8d',
aesKey: '998daf71f3fbc486076f0ee8d5737a61b82bceacb0ec69100cbe4d45cd79676a',
});

// and this does the time travel to trigger fetch
Expand Down
87 changes: 87 additions & 0 deletions packages/suite-web/e2e/tests/metadata/metadata-migration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { rerouteMetadataToMockProvider, stubOpen } from '../../stubs/metadata';

const providers = ['google', 'dropbox'] as const;

const fileName = 'f7acc942eeb83921892a95085e409b3e6b5325db6400ae5d8de523a305291dca.mtdt';
const migratedFileName = 'b9b5e1fd2800d4dc68e2f4e775fd819f4da3fb9e1bcc2cacd7f04fa543eac8a0_v2.mtdt';

const fileLocation = {
google: fileName,
dropbox: `/apps/trezor/${fileName}`,
};

const checkLabel = () => {
cy.getTestElement('@suite/menu/wallet-index').click();
cy.getTestElement('@account-menu/btc/normal/0/label').should('contain', 'some account label');
};

describe('Metadata - metadata files are properly migrated from ENCRYPTION_VERSION v1 to v2', () => {
beforeEach(() => {
cy.viewport(1080, 1440).resetDb();
cy.task('startEmu', { wipe: true });
cy.task('setupEmu', {
mnemonic: 'all all all all all all all all all all all all',
});
cy.task('startBridge');
cy.prefixedVisit('/', {
onBeforeLoad: (win: Window) => {
cy.stub(win, 'open').callsFake(stubOpen(win));
cy.stub(win, 'fetch').callsFake(rerouteMetadataToMockProvider);
},
});

cy.passThroughInitialRun();
cy.discoveryShouldFinish();

cy.getTestElement('@suite/menu/settings').click();
});

providers.forEach(provider => {
it(`should migrate metadata file from v1 to v2 using ${provider}`, () => {
// initialize provider
cy.task('metadataStartProvider', provider);
cy.task('metadataSetFileContent', {
provider,
file: fileLocation[provider],
content: {
version: '1.0.0',
accountLabel: 'some account label',
outputLabels: {},
addressLabels: {},
},
aesKey: 'c785ef250807166bffc141960c525df97647fcc1bca57f6892ca3742ba86ed8d',
});

// enable labeling
cy.getTestElement('@settings/metadata-switch').click({ force: true });
cy.passThroughInitMetadata(provider);

// appears only when a migration is needed
cy.getConfirmActionOnDeviceModal();
cy.task('pressYes');

// wait until migration finishes
cy.getTestElement('@settings/metadata-switch').get('input').should('not.be.disabled');

// check if the file has been migrated
cy.task('metadataGetFilesList', { provider }).then(files => {
const isFileMigrated = (files as string[]).includes(migratedFileName);
expect(isFileMigrated).to.be.true;
});

// check if the label is there after migration
checkLabel();

// toggle labeling to see if the migration is not run again (no device prompt modal = no migration)
cy.getTestElement('@suite/menu/settings').click();
cy.getTestElement('@settings/metadata-switch').click({ force: false });
cy.getTestElement('@settings/metadata-switch').click({ force: true });

// wait until migration finishes
cy.getTestElement('@settings/metadata-switch').get('input').should('not.be.disabled');

// check if the label is still there
checkLabel();
});
});
});
13 changes: 6 additions & 7 deletions packages/suite-web/e2e/tests/metadata/remembered-device.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { rerouteMetadataToMockProvider, stubOpen } from '../../stubs/metadata';
const providers = [
{
provider: 'google',
file: 'f7acc942eeb83921892a95085e409b3e6b5325db6400ae5d8de523a305291dca.mtdt',
file: 'b9b5e1fd2800d4dc68e2f4e775fd819f4da3fb9e1bcc2cacd7f04fa543eac8a0_2.mtdt',
},
{
provider: 'dropbox',
file: '/apps/trezor/f7acc942eeb83921892a95085e409b3e6b5325db6400ae5d8de523a305291dca.mtdt',
file: '/apps/trezor/b9b5e1fd2800d4dc68e2f4e775fd819f4da3fb9e1bcc2cacd7f04fa543eac8a0_2.mtdt',
},
] as const;

Expand Down Expand Up @@ -40,7 +40,7 @@ On disable, it throws away all metadata related records from memory.`, () => {
outputLabels: {},
addressLabels: {},
},
aesKey: 'c785ef250807166bffc141960c525df97647fcc1bca57f6892ca3742ba86ed8d',
aesKey: '998daf71f3fbc486076f0ee8d5737a61b82bceacb0ec69100cbe4d45cd79676a',
});

cy.prefixedVisit('/', {
Expand Down Expand Up @@ -105,11 +105,10 @@ On disable, it throws away all metadata related records from memory.`, () => {
cy.getTestElement('@account-menu/btc/normal/0/label').should('not.contain', 'label');
cy.hoverTestElement("@metadata/accountLabel/m/84'/0'/0'/hover-container");
cy.getTestElement("@metadata/accountLabel/m/84'/0'/0'/add-label-button").click();
cy.log(
'disabling metadata removed also all keys, so metadata init flow takes all steps now expect for providers, these stay connected',
cy.getTestElement('@account-menu/btc/normal/0/label').should(
'contain',
'already existing label',
);
cy.getConfirmActionOnDeviceModal();
cy.task('pressYes');

// device saved, disconnect provider
cy.getTestElement('@menu/switch-device').click();
Expand Down
2 changes: 0 additions & 2 deletions packages/suite-web/e2e/tests/metadata/wallet-metadata.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ describe('Metadata - wallet labeling', () => {
cy.getConfirmActionOnDeviceModal();
cy.task('pressYes');
cy.getTestElement('@menu/switch-device').click();
cy.getConfirmActionOnDeviceModal();
cy.task('pressYes');
cy.getTestElement(`@metadata/walletLabel/${standardWalletState}`).should(
'contain',
'wallet for drugs',
Expand Down
Loading

0 comments on commit ab1b36a

Please sign in to comment.