Merge pull request #11631 from vector-im/dbkr/remove_origin_migrator

Remove the code that calls the origin migrator
pull/11658/head
David Baker 2019-12-09 15:18:20 +00:00 committed by GitHub
commit 26eff8d372
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 2 additions and 479 deletions

View File

@ -35,7 +35,6 @@ const tray = require('./tray');
const vectorMenu = require('./vectormenu');
const webContentsHandler = require('./webcontents-handler');
const updater = require('./updater');
const { migrateFromOldOrigin } = require('./originMigrator');
const windowStateKeeper = require('electron-window-state');
const Store = require('electron-store');
@ -64,11 +63,6 @@ if (argv["help"]) {
app.exit();
}
// boolean flag set whilst we are doing one-time origin migration
// We only serve the origin migration script while we're actually
// migrating to mitigate any risk of it being used maliciously.
let migratingOrigin = false;
if (argv['profile-dir']) {
app.setPath('userData', argv['profile-dir']);
} else if (argv['profile']) {
@ -231,11 +225,6 @@ ipcMain.on('ipcCall', async function(ev, payload) {
mainWindow.focus();
}
break;
case 'origin_migrate':
migratingOrigin = true;
await migrateFromOldOrigin();
migratingOrigin = false;
break;
case 'getConfig':
ret = vectorConfig;
break;
@ -477,13 +466,7 @@ app.on('ready', () => {
let baseDir;
// first part of the path determines where we serve from
if (migratingOrigin && target[1] === 'origin_migrator_dest') {
// the origin migrator destination page
// (only the destination script needs to come from the
// custom protocol: the source part is loaded from a
// file:// as that's the origin we're migrating from).
baseDir = __dirname + "/../../origin_migrator/dest";
} else if (target[1] === 'webapp') {
if (target[1] === 'webapp') {
baseDir = __dirname + "/../../webapp";
} else {
callback({error: -6}); // FILE_NOT_FOUND

View File

@ -1,72 +0,0 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const { BrowserWindow, ipcMain } = require('electron');
const path = require('path');
async function migrateFromOldOrigin() {
console.log("Attempting to migrate data between origins");
// We can use the same preload script: we just need ipcRenderer exposed
const preloadScript = path.normalize(`${__dirname}/preload.js`);
await new Promise(resolve => {
const migrateWindow = new BrowserWindow({
show: false,
webPreferences: {
preload: preloadScript,
nodeIntegration: false,
sandbox: true,
enableRemoteModule: false,
webgl: false,
},
});
const onOriginMigrationComplete = (e, success, sentSummary, storedSummary) => {
// we use once but we'll only get one of these events,
// so remove the listener for the other one
ipcMain.removeListener('origin_migration_nodata', onOriginMigrationNoData);
if (success) {
console.log("Origin migration completed successfully!");
} else {
console.error("Origin migration failed!");
}
console.error("Data sent", sentSummary);
console.error("Data stored", storedSummary);
migrateWindow.close();
resolve();
};
const onOriginMigrationNoData = (e, success, sentSummary, storedSummary) => {
ipcMain.removeListener('origin_migration_complete', onOriginMigrationComplete);
console.log("No session to migrate from old origin");
migrateWindow.close();
resolve();
};
ipcMain.once('origin_migration_complete', onOriginMigrationComplete);
ipcMain.once('origin_migration_nodata', onOriginMigrationNoData);
// Normalise the path because in the distribution, __dirname will be inside the
// electron asar.
const sourcePagePath = path.normalize(__dirname + '/../../origin_migrator/source.html');
console.log("Loading path: " + sourcePagePath);
migrateWindow.loadURL('file://' + sourcePagePath);
});
}
module.exports = {
migrateFromOldOrigin,
};

File diff suppressed because one or more lines are too long

View File

@ -1,6 +0,0 @@
<html>
<body>
<script src="browser-matrix.min.js"></script>
<script src="dest.js"></script>
</body>
</html>

View File

@ -1,125 +0,0 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const SOURCE_ORIGIN = 'file://';
const IndexedDBCryptoStore = window.matrixcs.IndexedDBCryptoStore;
const cryptoStore = new IndexedDBCryptoStore(window.indexedDB, 'matrix-js-sdk:crypto');
let accountStored = 0;
let sessionsStored = 0;
let inboundGroupSessionsStored = 0;
let deviceDataStored = 0;
let roomsStored = 0;
let localStorageKeysStored = 0;
const promises = [];
async function onMessage(e) {
if (e.origin !== SOURCE_ORIGIN) return;
const data = e.data.data; // bleh, naming clash
switch (e.data.cmd) {
case 'init':
// start with clean stores before we migrate data in
window.localStorage.clear();
await cryptoStore.deleteAllData();
e.source.postMessage({
cmd: 'initOK',
}, SOURCE_ORIGIN);
break;
case 'storeAccount':
promises.push(cryptoStore.doTxn(
'readwrite', [IndexedDBCryptoStore.STORE_ACCOUNT],
(txn) => {
cryptoStore.storeAccount(txn, data);
},
).then(() => {
++accountStored;
}));
break;
case 'storeSessions':
promises.push(cryptoStore.doTxn(
'readwrite', [IndexedDBCryptoStore.STORE_SESSIONS],
(txn) => {
for (const sess of data) {
cryptoStore.storeEndToEndSession(sess.deviceKey, sess.sessionId, sess, txn);
}
},
).then(() => {
sessionsStored += data.length;
}));
break;
case 'storeInboundGroupSessions':
promises.push(cryptoStore.doTxn(
'readwrite', [IndexedDBCryptoStore.STORE_INBOUND_GROUP_SESSIONS],
(txn) => {
for (const sess of data) {
cryptoStore.addEndToEndInboundGroupSession(
sess.senderKey, sess.sessionId, sess.sessionData, txn,
);
}
},
).then(() => {
inboundGroupSessionsStored += data.length;
}));
break;
case 'storeDeviceData':
promises.push(cryptoStore.doTxn(
'readwrite', [IndexedDBCryptoStore.STORE_DEVICE_DATA],
(txn) => {
cryptoStore.storeEndToEndDeviceData(data, txn);
},
).then(() => {
++deviceDataStored;
}));
break;
case 'storeRooms':
promises.push(cryptoStore.doTxn(
'readwrite', [IndexedDBCryptoStore.STORE_ROOMS],
(txn) => {
for (const [roomId, roomInfo] of Object.entries(data)) {
cryptoStore.storeEndToEndRoom(roomId, roomInfo, txn);
}
},
).then(() => {
++roomsStored;
}));
break;
case 'storeLocalStorage':
window.localStorage.setItem(data.key, data.val);
++localStorageKeysStored;
break;
case 'getSummary':
await Promise.all(promises);
e.source.postMessage({
cmd: 'summary',
data: {
accountStored,
sessionsStored,
inboundGroupSessionsStored,
deviceDataStored,
roomsStored,
localStorageKeysStored,
},
}, SOURCE_ORIGIN);
break;
}
}
window.addEventListener('message', onMessage);

View File

@ -1,7 +0,0 @@
<html>
<body>
<script src="dest/browser-matrix.min.js"></script>
<script src="source.js"></script>
<iframe name="dest" src="vector://vector/origin_migrator_dest/dest.html" onload="doMigrate()"></iframe>
</body>
</html>

View File

@ -1,210 +0,0 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const TARGET_ORIGIN = 'vector://vector';
const BATCH_SIZE = 500;
let destFrame;
let initResolver = null;
let getSummaryResolver = null;
function onMessage(e) {
if (e.origin !== TARGET_ORIGIN) return;
if (e.data.cmd === 'initOK' && initResolver) {
initResolver();
initResolver = null;
} else if (e.data.cmd === 'summary' && getSummaryResolver) {
getSummaryResolver(e.data.data);
getSummaryResolver = null;
}
}
async function initDestFrame() {
return new Promise(resolve => {
initResolver = resolve;
destFrame.postMessage({
cmd: 'init',
}, TARGET_ORIGIN);
});
}
async function getSummary() {
return new Promise(resolve => {
getSummaryResolver = resolve;
destFrame.postMessage({
cmd: 'getSummary',
}, TARGET_ORIGIN);
});
}
async function doMigrate() {
let accountSent = 0;
let sessionsSent = 0;
let inboundGroupSessionsSent = 0;
let deviceDataSent = 0;
let roomsSent = 0;
let localStorageKeysSent = 0;
if (!window.ipcRenderer) {
console.error("ipcRenderer not found");
return;
}
if (window.localStorage.getItem('mx_user_id') === null) {
window.ipcRenderer.send("origin_migration_nodata");
return;
}
destFrame = window.parent.frames.dest;
await initDestFrame();
const IndexedDBCryptoStore = window.matrixcs.IndexedDBCryptoStore;
const cryptoStore = new IndexedDBCryptoStore(window.indexedDB, 'matrix-js-sdk:crypto');
await cryptoStore.doTxn(
'readonly', [IndexedDBCryptoStore.STORE_ACCOUNT],
(txn) => {
cryptoStore.getAccount(txn, (account) => {
destFrame.postMessage({
cmd: 'storeAccount',
data: account,
}, TARGET_ORIGIN);
++accountSent;
});
},
);
await cryptoStore.doTxn(
'readonly', [IndexedDBCryptoStore.STORE_SESSIONS],
(txn) => {
let sessBatch = [];
cryptoStore.getAllEndToEndSessions(txn, (sessInfo) => {
if (sessInfo) {
++sessionsSent;
sessBatch.push(sessInfo);
}
if (sessBatch.length >= BATCH_SIZE || sessInfo === null) {
destFrame.postMessage({
cmd: 'storeSessions',
data: sessBatch,
}, TARGET_ORIGIN);
sessBatch = [];
}
});
},
);
await cryptoStore.doTxn(
'readonly', [IndexedDBCryptoStore.STORE_INBOUND_GROUP_SESSIONS],
(txn) => {
let sessBatch = [];
cryptoStore.getAllEndToEndInboundGroupSessions(txn, (sessInfo) => {
if (sessInfo) {
++inboundGroupSessionsSent;
sessBatch.push(sessInfo);
}
if (sessBatch.length >= BATCH_SIZE || sessInfo === null) {
destFrame.postMessage({
cmd: 'storeInboundGroupSessions',
data: sessBatch,
}, TARGET_ORIGIN);
sessBatch = [];
}
});
},
);
await cryptoStore.doTxn(
'readonly', [IndexedDBCryptoStore.STORE_DEVICE_DATA],
(txn) => {
cryptoStore.getEndToEndDeviceData(txn, (deviceData) => {
destFrame.postMessage({
cmd: 'storeDeviceData',
data: deviceData,
}, TARGET_ORIGIN);
++deviceDataSent;
});
},
);
await cryptoStore.doTxn(
'readonly', [IndexedDBCryptoStore.STORE_ROOMS],
(txn) => {
cryptoStore.getEndToEndRooms(txn, (rooms) => {
destFrame.postMessage({
cmd: 'storeRooms',
data: rooms,
}, TARGET_ORIGIN);
++roomsSent;
});
},
);
// we don't bother migrating;
// * sync data (we can just initialsync again)
// * logs
// * key requests (worst case they'll just be re-sent)
// * sessions needing backup (feature isn't available on Electron)
for (let i = 0; i < window.localStorage.length; ++i) {
const key = window.localStorage.key(i);
const val = window.localStorage.getItem(key);
destFrame.postMessage({
cmd: 'storeLocalStorage',
data: { key, val },
}, TARGET_ORIGIN);
++localStorageKeysSent;
}
const summary = await getSummary();
let success = false;
if (
summary.accountStored === accountSent &&
summary.sessionsStored === sessionsSent &&
summary.inboundGroupSessionsStored === inboundGroupSessionsSent &&
summary.deviceDataStored === deviceDataSent &&
summary.roomsStored === roomsSent &&
summary.localStorageKeysStored === localStorageKeysSent
) {
success = true;
window.localStorage.clear();
await cryptoStore.deleteAllData();
// we don't bother migrating them, but also blow away the sync & logs db,
// otherwise they'll just hang about taking up space
await new Promise(resolve => {
const req = window.indexedDB.deleteDatabase('matrix-js-sdk:riot-web-sync');
req.onsuccess = resolve;
req.onerror = resolve;
});
await new Promise(resolve => {
const req = window.indexedDB.deleteDatabase('logs');
req.onsuccess = resolve;
req.onerror = resolve;
});
}
window.ipcRenderer.send("origin_migration_complete", success, {
accountSent, sessionsSent, inboundGroupSessionsSent,
deviceDataSent, roomsSent, localStorageKeysSent,
}, summary);
}
window.addEventListener('message', onMessage);

View File

@ -166,8 +166,7 @@
"from": "electron_app/img",
"to": "img"
},
"webapp/**/*",
"origin_migrator/**/*"
"webapp/**/*"
],
"linux": {
"target": "deb",

View File

@ -191,14 +191,6 @@ async function loadApp() {
console.log("Using Electron platform");
const plaf = new ElectronPlatform();
PlatformPeg.set(plaf);
// Electron only: see if we need to do a one-time data
// migration
if (window.localStorage.getItem('mx_user_id') === null) {
console.log("Migrating session from old origin...");
await plaf.migrateFromOldOrigin();
console.log("Origin migration complete");
}
} else {
console.log("Using Web platform");
PlatformPeg.set(new WebPlatform());

View File

@ -355,10 +355,6 @@ export default class ElectronPlatform extends VectorBasePlatform {
window.location.reload(false);
}
async migrateFromOldOrigin() {
return this._ipcCall('origin_migrate');
}
async _ipcCall(name, ...args) {
const ipcCallId = ++this._nextIpcCallId;
return new Promise((resolve, reject) => {

View File

@ -173,12 +173,4 @@ export default class VectorBasePlatform extends BasePlatform {
getDefaultDeviceDisplayName(): string {
return _t("Unknown device");
}
/**
* Migrate account data from a previous origin
* Used only for the electron app
*/
async migrateFromOldOrigin() {
return false;
}
}