pull/1390/head v1.2.1
Mikunj Varsani 5 years ago committed by GitHub
commit 9fdd1518a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1302,22 +1302,6 @@
"message": "Typing Indicators",
"description": "Title of the typing indicators setting"
},
"multiDeviceDisabledTemporary": {
"message": "MultiDevice disabled temporarily",
"description": "Description of why multi device is disabled"
},
"multiDeviceDisabledTemporaryTitle": {
"message": "Changes to Multi-device",
"description": "Description of why multi device is disabled on app start"
},
"multiDeviceDisabledTemporaryDescriptionPrimary": {
"message": "Youre seeing this because you have a secondary device linked to your Session ID. To improve reliability and stability, weve decided to temporarily disable Sessions multi-device functionality. Device linking has been disabled, and existing secondary clients will be erased on <span style=\"color:#00f782\">August 6th</span>.</br></br>To read more about this change, visit the Session FAQ at <a href=\"https://getsession.org/faq\">getsession.org/faq</a>.",
"description": "Description of why multi device is disabled on app start for a primary device"
},
"multiDeviceDisabledTemporaryDescriptionSecondary": {
"message": "Youre seeing this because this is a secondary device in a multi-device setup. To improve reliability and stability, weve decided to temporarily disable Sessions multi-device functionality. Device linking has been disabled, and existing secondary clients will be erased on <span style=\"color:#00f782\">August 6th</span>.</br></br>To read more about this change, visit the Session FAQ at <a href=\"https://getsession.org/faq\">getsession.org/faq</a>.",
"description": "Description of why multi device is disabled on app start for a secondary device"
},
"messageTTL": {
"message": "Message TTL",
"description": "Title of the Message TTL setting"
@ -1752,6 +1736,9 @@
"unlinked": {
"message": "Unlinked"
},
"successUnlinked": {
"message": "Your device was unlinked successfully"
},
"relink": {
"message": "Relink"
},

@ -810,6 +810,7 @@ const LOKI_SCHEMA_VERSIONS = [
updateToLokiSchemaVersion4,
updateToLokiSchemaVersion5,
updateToLokiSchemaVersion6,
updateToLokiSchemaVersion7,
];
async function updateToLokiSchemaVersion1(currentVersion, instance) {
@ -1027,6 +1028,30 @@ async function updateToLokiSchemaVersion6(currentVersion, instance) {
console.log('updateToLokiSchemaVersion6: success!');
}
async function updateToLokiSchemaVersion7(currentVersion, instance) {
if (currentVersion >= 7) {
return;
}
console.log('updateToLokiSchemaVersion7: starting...');
await instance.run('BEGIN TRANSACTION;');
// Remove multi device data
await instance.run('DELETE FROM pairingAuthorisations;');
await instance.run(
`INSERT INTO loki_schema (
version
) values (
7
);`
);
await instance.run('COMMIT TRANSACTION;');
console.log('updateToLokiSchemaVersion7: success!');
}
async function updateLokiSchema(instance) {
const result = await instance.get(
"SELECT name FROM sqlite_master WHERE type = 'table' AND name='loki_schema';"

@ -129,6 +129,52 @@
// of preload.js processing
window.setImmediate = window.nodeSetImmediate;
window.toasts = new Map();
window.pushToast = options => {
// Setting toasts with the same ID can be used to prevent identical
// toasts from appearing at once (stacking).
// If toast already exists, it will be reloaded (updated)
const params = {
title: options.title,
id: options.id || window.generateID(),
description: options.description || '',
type: options.type || '',
icon: options.icon || '',
shouldFade: options.shouldFade,
};
// Give all toasts an ID. User may define.
let currentToast;
const toastID = params.id;
const toast = !!toastID && window.toasts.get(toastID);
if (toast) {
currentToast = window.toasts.get(toastID);
currentToast.update(params);
} else {
// Make new Toast
window.toasts.set(
toastID,
new Whisper.SessionToastView({
el: $('body'),
})
);
currentToast = window.toasts.get(toastID);
currentToast.render();
currentToast.update(params);
}
// Remove some toasts if too many exist
const maxToasts = 6;
while (window.toasts.size > maxToasts) {
const finalToastID = window.toasts.keys().next().value;
window.toasts.get(finalToastID).fadeToast();
}
return toastID;
};
const { IdleDetector, MessageDataMigrator } = Signal.Workflow;
const {
mandatoryMessageUpgrade,
@ -151,6 +197,20 @@
window.log.info('background page reloaded');
window.log.info('environment:', window.getEnvironment());
const restartReason = localStorage.getItem('restart-reason');
window.log.info('restartReason:', restartReason);
if (restartReason === 'unlink') {
setTimeout(() => {
localStorage.removeItem('restart-reason');
window.pushToast({
title: window.i18n('successUnlinked'),
type: 'info',
id: '123',
});
}, 2000);
}
let idleDetector;
let initialLoadComplete = false;
@ -300,6 +360,12 @@
storage.put('primaryDevicePubKey', textsecure.storage.user.getNumber());
}
// 4th August 2020 - Force wipe of secondary devices as multi device is being disabled.
if (storage.get('isSecondaryDevice')) {
await window.deleteAccount('unlink');
return;
}
// These make key operations available to IPC handlers created in preload.js
window.Events = {
getThemeSetting: () => 'dark', // storage.get('theme-setting', 'dark')
@ -754,76 +820,9 @@
.toString(36)
.substring(3);
window.toasts = new Map();
window.pushToast = options => {
// Setting toasts with the same ID can be used to prevent identical
// toasts from appearing at once (stacking).
// If toast already exists, it will be reloaded (updated)
const params = {
title: options.title,
id: options.id || window.generateID(),
description: options.description || '',
type: options.type || '',
icon: options.icon || '',
shouldFade: options.shouldFade,
};
// Give all toasts an ID. User may define.
let currentToast;
const toastID = params.id;
const toast = !!toastID && window.toasts.get(toastID);
if (toast) {
currentToast = window.toasts.get(toastID);
currentToast.update(params);
} else {
// Make new Toast
window.toasts.set(
toastID,
new Whisper.SessionToastView({
el: $('body'),
})
);
currentToast = window.toasts.get(toastID);
currentToast.render();
currentToast.update(params);
}
// Remove some toasts if too many exist
const maxToasts = 6;
while (window.toasts.size > maxToasts) {
const finalToastID = window.toasts.keys().next().value;
window.toasts.get(finalToastID).fadeToast();
}
return toastID;
};
// Get memberlist. This function is not accurate >>
// window.getMemberList = window.lokiPublicChatAPI.getListOfMembers();
window.deleteAccount = async () => {
try {
window.log.info('Deleting everything!');
const { Logs } = window.Signal;
await Logs.deleteAll();
await window.Signal.Data.removeAll();
await window.Signal.Data.close();
await window.Signal.Data.removeDB();
await window.Signal.Data.removeOtherData();
} catch (error) {
window.log.error(
'Something went wrong deleting all data:',
error && error.stack ? error.stack : error
);
}
window.restart();
};
window.toggleTheme = () => {
const theme = window.Events.getThemeSetting();
const updatedTheme = theme === 'dark' ? 'light' : 'dark';

@ -137,6 +137,6 @@ window.onerror = (message, script, line, col, error) => {
window.addEventListener('unhandledrejection', rejectionEvent => {
const error = rejectionEvent.reason;
const errorInfo = error && error.stack ? error.stack : JSON.stringify(error);
window.log.error(`Top-level unhandled promise rejection: ${errorInfo}`);
const errorInfo = error && error.stack ? error.stack : error;
window.log.error('Top-level unhandled promise rejection:', errorInfo);
});

@ -2210,16 +2210,20 @@
return;
}
const profileKeyBuffer = window.Signal.Crypto.base64ToArrayBuffer(
profileKey
);
const accessKeyBuffer = await window.Signal.Crypto.deriveAccessKey(
profileKeyBuffer
);
const accessKey = window.Signal.Crypto.arrayBufferToBase64(
accessKeyBuffer
);
this.set({ accessKey });
try {
const profileKeyBuffer = window.Signal.Crypto.base64ToArrayBuffer(
profileKey
);
const accessKeyBuffer = await window.Signal.Crypto.deriveAccessKey(
profileKeyBuffer
);
const accessKey = window.Signal.Crypto.arrayBufferToBase64(
accessKeyBuffer
);
this.set({ accessKey });
} catch (e) {
window.log.warn(`Failed to derive access key for ${this.id}`);
}
},
async upgradeMessages(messages) {

@ -1710,8 +1710,9 @@ class LokiPublicChannelAPI {
sigString += [...attachmentAnnotations, ...previewAnnotations]
.map(data => data.id || data.image.id)
.sort()
.join();
.join('');
sigString += sigVer;
return dcodeIO.ByteBuffer.wrap(sigString, 'utf8').toArrayBuffer();
}

@ -218,6 +218,10 @@ class LokiHomeServerInstance extends LokiFileServerInstance {
}
async updateOurDeviceMapping() {
if (!window.lokiFeatureFlags.useMultiDevice) {
return undefined;
}
const isPrimary = !storage.get('isSecondaryDevice');
const authorisations = await window.libsession.Protocols.MultiDeviceProtocol.getPairingAuthorisations(
this.ourKey

@ -2,7 +2,7 @@
"name": "session-messenger-desktop",
"productName": "Session",
"description": "Private messaging from your desktop",
"version": "1.2.0",
"version": "1.2.1",
"license": "GPL-3.0",
"author": {
"name": "Loki Project",

@ -456,6 +456,7 @@ window.lokiFeatureFlags = {
enableSenderKeys: false,
onionRequestHops: 3,
debugMessageLogs: process.env.ENABLE_MESSAGE_LOGS,
useMultiDevice: false,
};
// eslint-disable-next-line no-extend-native,func-names
@ -492,6 +493,7 @@ if (config.environment.includes('test-integration')) {
useFileOnionRequests: false,
debugMessageLogs: true,
enableSenderKeys: true,
useMultiDevice: false,
};
}
@ -502,3 +504,26 @@ const {
} = require('./ts/util/blockedNumberController');
window.BlockedNumberController = BlockedNumberController;
window.deleteAccount = async reason => {
try {
window.log.info('Deleting everything!');
const { Logs } = window.Signal;
await Logs.deleteAll();
await window.Signal.Data.removeAll();
await window.Signal.Data.close();
await window.Signal.Data.removeDB();
await window.Signal.Data.removeOtherData();
// 'unlink' => toast will be shown on app restart
window.localStorage.setItem('restart-reason', reason);
} catch (error) {
window.log.error(
'Something went wrong deleting all data:',
error && error.stack ? error.stack : error
);
}
window.restart();
};

@ -59,48 +59,6 @@ export class ActionsPanel extends React.Component<Props, State> {
},
'refreshAvatarCallback'
);
setTimeout(async () => {
const disabledMultiDeviceCountDb = await getItemById(
'disabledMultiDeviceCount'
);
const disabledMultiDeviceCount =
Number(disabledMultiDeviceCountDb?.value) || 0;
const data = {
id: 'disabledMultiDeviceCount',
value: String(disabledMultiDeviceCount + 1),
};
await createOrUpdateItem(data);
if (disabledMultiDeviceCount % 5 !== 0) {
return;
}
const currentDevice = await UserUtil.getCurrentDevicePubKey();
if (!currentDevice) {
return;
}
const secondaryDevices = await MultiDeviceProtocol.getSecondaryDevices(
currentDevice
);
const isSecondary =
secondaryDevices.find(s => s.key === currentDevice) ||
!!window.textsecure.storage.get('isSecondaryDevice');
const hasMultipleDevices =
(await MultiDeviceProtocol.getOurDevices()).length > 1;
const primaryWithSecondary = !isSecondary && hasMultipleDevices;
if (!primaryWithSecondary && !isSecondary) {
return;
}
const opts = {
hideCancel: true,
title: window.i18n('multiDeviceDisabledTemporaryTitle'),
message: primaryWithSecondary
? window.i18n('multiDeviceDisabledTemporaryDescriptionPrimary')
: window.i18n('multiDeviceDisabledTemporaryDescriptionSecondary'),
};
window.Whisper.events.trigger('showConfirmationDialog', opts);
}, 1000);
}
);
}

@ -225,7 +225,7 @@ export class LeftPaneSettingSection extends React.Component<Props, State> {
{
id: SessionSettingCategory.Devices,
title: window.i18n('devicesSettingsTitle'),
hidden: isSecondaryDevice,
hidden: !window.lokiFeatureFlags.useMultiDevice || isSecondaryDevice,
},
];
}

@ -557,9 +557,12 @@ export class RegistrationTabs extends React.Component<{}, State> {
SessionButtonType.BrandOutline,
SessionButtonColor.Green
)}
{/*<h4>{or}</h4>*/}
{/* FIXME enable back to allow linking of device
this.renderLinkDeviceToExistingAccountButton() */}
{window.lokiFeatureFlags.useMultiDevice && (
<>
<h4>{or}</h4>
{this.renderLinkDeviceToExistingAccountButton()}
</>
)}
</div>
);
}
@ -584,9 +587,12 @@ export class RegistrationTabs extends React.Component<{}, State> {
return (
<div>
{this.renderContinueYourSessionButton()}
{/*<h4>{or}</h4>*/}
{/* FIXME enable back to allow linking of device
this.renderLinkDeviceToExistingAccountButton()*/}
{window.lokiFeatureFlags.useMultiDevice && (
<>
<h4>{or}</h4>
{this.renderLinkDeviceToExistingAccountButton()}
</>
)}
</div>
);
}

@ -644,7 +644,7 @@ export class SettingsView extends React.Component<SettingsViewProps, State> {
id: 'no-linked-device',
title: noPairedDeviceText,
type: undefined,
description: window.i18n('multiDeviceDisabledTemporary'),
description: '',
category: SessionSettingCategory.Devices,
content: {},
comparisonValue: undefined,

@ -74,12 +74,9 @@ export class SettingsHeader extends React.Component<Props, any> {
? `${categoryTitlePrefix.slice(0, -1)} Settings`
: `${categoryTitlePrefix} Settings`;
const showSearch = false;
const showAddDevice = false;
/* FIXME enable back to allow linking of device
const showAddDevice =
const showAddDevice =
category === SessionSettingCategory.Devices &&
this.props.showLinkDeviceButton;
*/
return (
<div className="session-settings-header">

@ -87,6 +87,14 @@ export async function handlePairingAuthorisationMessage(
pairingAuthorisation: SignalService.IPairingAuthorisationMessage,
dataMessage: SignalService.IDataMessage | undefined | null
): Promise<void> {
if (!window.lokiFeatureFlags.useMultiDevice) {
window.log.info(
`Received a pairing authorisation message from ${envelope.source} while multi device is disabled.`
);
await removeFromCache(envelope);
return;
}
const { secondaryDevicePubKey, grantSignature } = pairingAuthorisation;
const isGrant =
grantSignature &&

@ -28,6 +28,11 @@ export class MultiDeviceProtocol {
public static async fetchPairingAuthorisationsIfNeeded(
device: PubKey
): Promise<void> {
// Disable fetching if we don't want to use multi device
if (!window.lokiFeatureFlags.useMultiDevice) {
return;
}
// This return here stops an infinite loop when we get all our other devices
const ourKey = await UserUtil.getCurrentDevicePubKey();
if (!ourKey || device.key === ourKey) {

@ -25,6 +25,13 @@ function generateFakeAuthorisations(
describe('MultiDeviceProtocol', () => {
const sandbox = sinon.createSandbox();
beforeEach(() => {
// Enable multidevice for tests
TestUtils.stubWindow('lokiFeatureFlags', {
useMultiDevice: true,
});
});
afterEach(() => {
TestUtils.restoreStubs();
sandbox.restore();

12
ts/window.d.ts vendored

@ -51,7 +51,17 @@ declare global {
libloki: Libloki;
libsignal: LibsignalProtocol;
log: any;
lokiFeatureFlags: any;
lokiFeatureFlags: {
multiDeviceUnpairing: boolean;
privateGroupChats: boolean;
useSnodeProxy: boolean;
useOnionRequests: boolean;
useFileOnionRequests: boolean;
enableSenderKeys: boolean;
onionRequestHops: number;
debugMessageLogs: boolean;
useMultiDevice: boolean;
};
lokiFileServerAPI: LokiFileServerInstance;
lokiMessageAPI: LokiMessageInterface;
lokiPublicChatAPI: LokiPublicChatFactoryInterface;

Loading…
Cancel
Save