Sending and handling of special UNPAIRING_REQUEST message

pull/641/head
sachaaaaa 6 years ago
parent 8cd8c8d4f9
commit db0068b429

@ -1025,6 +1025,15 @@
pubKey pubKey
); );
}); });
Whisper.events.on('deviceUnpairingRequested', async pubKey => {
await libloki.storage.removePairingAuthorisationForSecondaryPubKey(
pubKey
);
await window.lokiFileServerAPI.updateOurDeviceMapping();
// TODO: we should ensure the message was sent and retry automatically if not
await libloki.api.sendUnpairingMessageToSecondary(pubKey);
});
} }
window.getSyncRequest = () => window.getSyncRequest = () =>

@ -224,6 +224,10 @@ class LokiFileServerAPI {
uploadPrivateAttachment(data) { uploadPrivateAttachment(data) {
return this._server.uploadData(data); return this._server.uploadData(data);
} }
clearOurDeviceMappingAnnotations() {
return this._server.setSelfAnnotation(DEVICE_MAPPING_ANNOTATION_KEY, null);
}
} }
module.exports = LokiFileServerAPI; module.exports = LokiFileServerAPI;

@ -223,6 +223,9 @@
dialog.on('devicePairingRequestRejected', pubKey => dialog.on('devicePairingRequestRejected', pubKey =>
Whisper.events.trigger('devicePairingRequestRejected', pubKey) Whisper.events.trigger('devicePairingRequestRejected', pubKey)
); );
dialog.on('deviceUnpairingRequested', pubKey =>
Whisper.events.trigger('deviceUnpairingRequested', pubKey)
);
dialog.once('close', () => { dialog.once('close', () => {
Whisper.events.off('devicePairingRequestReceived'); Whisper.events.off('devicePairingRequestReceived');
}); });

@ -117,10 +117,7 @@
this.pubKey = this.pubKeyRequests.pop(); this.pubKey = this.pubKeyRequests.pop();
}, },
async confirmUnpairDevice() { async confirmUnpairDevice() {
await libloki.storage.removePairingAuthorisationForSecondaryPubKey( this.trigger('deviceUnpairingRequested', this.pubKeyToUnpair);
this.pubKeyToUnpair
);
await lokiFileServerAPI.updateOurDeviceMapping();
this.reset(); this.reset();
this.showView(); this.showView();
}, },

@ -107,6 +107,27 @@
secondaryDevicePubKey, secondaryDevicePubKey,
}); });
} }
function sendUnpairingMessageToSecondary(pubKey) {
const flags = textsecure.protobuf.DataMessage.Flags.UNPAIRING_REQUEST;
const dataMessage = new textsecure.protobuf.DataMessage({
flags,
});
const content = new textsecure.protobuf.Content({
dataMessage,
});
const options = { messageType: 'device-unpairing' };
const outgoingMessage = new textsecure.OutgoingMessage(
null, // server
Date.now(), // timestamp,
[pubKey], // numbers
content, // message
true, // silent
() => null, // callback
options
);
return outgoingMessage.sendToNumber(pubKey);
}
// Serialise as <Element0.length><Element0><Element1.length><Element1>... // Serialise as <Element0.length><Element0><Element1.length><Element1>...
// This is an implementation of the reciprocal of contacts_parser.js // This is an implementation of the reciprocal of contacts_parser.js
function serialiseByteBuffers(buffers) { function serialiseByteBuffers(buffers) {
@ -226,6 +247,7 @@
broadcastOnlineStatus, broadcastOnlineStatus,
sendPairingAuthorisation, sendPairingAuthorisation,
createPairingAuthorisationProtoMessage, createPairingAuthorisationProtoMessage,
sendUnpairingMessageToSecondary,
createContactSyncProtoMessage, createContactSyncProtoMessage,
}; };
})(); })();

@ -1286,7 +1286,8 @@ MessageReceiver.prototype.extend({
this.processDecrypted(envelope, msg).then(async message => { this.processDecrypted(envelope, msg).then(async message => {
const groupId = message.group && message.group.id; const groupId = message.group && message.group.id;
const isBlocked = this.isGroupBlocked(groupId); const isBlocked = this.isGroupBlocked(groupId);
const isMe = envelope.source === textsecure.storage.user.getNumber(); const ourPubKey = textsecure.storage.user.getNumber();
const isMe = envelope.source === ourPubKey;
const conversation = window.ConversationController.get(envelope.source); const conversation = window.ConversationController.get(envelope.source);
const isLeavingGroup = Boolean( const isLeavingGroup = Boolean(
message.group && message.group &&
@ -1294,6 +1295,72 @@ MessageReceiver.prototype.extend({
); );
const friendRequest = const friendRequest =
envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST; envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST;
const { UNPAIRING_REQUEST } = textsecure.protobuf.DataMessage.Flags;
// eslint-disable-next-line no-bitwise
const isUnpairingRequest = Boolean(message.flags & UNPAIRING_REQUEST);
if (isUnpairingRequest) {
// TODO: move high-level pairing logic to libloki.multidevice.xx
const unpairingRequestIsLegit = async () => {
const isSecondary = textsecure.storage.get('isSecondaryDevice');
if (!isSecondary) {
return false;
}
const primaryPubKey = window.storage.get('primaryDevicePubKey');
// TODO: allow unpairing from any paired device?
if (envelope.source !== primaryPubKey) {
return false;
}
const primaryMapping = await lokiFileServerAPI.getUserDeviceMapping(
primaryPubKey
);
if (!primaryMapping) {
return false;
}
// We expect the primary device to have updated its mapping
// before sending the unpairing request
const found = primaryMapping.authorisations.find(
authorisation => authorisation.secondaryDevicePubKey === ourPubKey
);
// our pubkey should NOT be in the primary device mapping
if (found) {
return false;
}
return true;
};
const legit = await unpairingRequestIsLegit();
this.removeFromCache(envelope);
if (legit) {
// remove our device mapping annotations from file server
await lokiFileServerAPI.clearOurDeviceMappingAnnotations();
// Delete the account and restart
try {
await window.Signal.Logs.deleteAll();
await window.Signal.Data.removeAll();
await window.Signal.Data.close();
await window.Signal.Data.removeDB();
await window.Signal.Data.removeOtherData();
// TODO generate an empty db with a flag
// to display a message about the unpairing
// after the app restarts
} catch (error) {
window.log.error(
'Something went wrong deleting all data:',
error && error.stack ? error.stack : error
);
}
window.restart();
}
}
// Check if we need to update any profile names // Check if we need to update any profile names
if (!isMe && conversation) { if (!isMe && conversation) {
@ -1787,6 +1854,8 @@ MessageReceiver.prototype.extend({
decrypted.attachments = []; decrypted.attachments = [];
} else if (decrypted.flags & FLAGS.BACKGROUND_FRIEND_REQUEST) { } else if (decrypted.flags & FLAGS.BACKGROUND_FRIEND_REQUEST) {
// do nothing // do nothing
} else if (decrypted.flags & FLAGS.UNPAIRING_REQUEST) {
// do nothing
} else if (decrypted.flags !== 0) { } else if (decrypted.flags !== 0) {
throw new Error('Unknown flags in message'); throw new Error('Unknown flags in message');
} }

@ -443,6 +443,8 @@ OutgoingMessage.prototype = {
switch (type) { switch (type) {
case 'friend-request': case 'friend-request':
return 4 * 24 * 60 * 60 * 1000; // 4 days for friend request message return 4 * 24 * 60 * 60 * 1000; // 4 days for friend request message
case 'device-unpairing':
return 4 * 24 * 60 * 60 * 1000; // 4 days for device unpairing
case 'onlineBroadcast': case 'onlineBroadcast':
return 60 * 1000; // 1 minute for online broadcast message return 60 * 1000; // 1 minute for online broadcast message
case 'typing': case 'typing':

@ -469,6 +469,6 @@ window.pubkeyPattern = /@[a-fA-F0-9]{64,66}\b/g;
window.SMALL_GROUP_SIZE_LIMIT = 10; window.SMALL_GROUP_SIZE_LIMIT = 10;
window.lokiFeatureFlags = { window.lokiFeatureFlags = {
multiDeviceUnpairing: false, multiDeviceUnpairing: true,
privateGroupChats: false, privateGroupChats: false,
}; };

@ -105,6 +105,7 @@ message DataMessage {
END_SESSION = 1; END_SESSION = 1;
EXPIRATION_TIMER_UPDATE = 2; EXPIRATION_TIMER_UPDATE = 2;
PROFILE_KEY_UPDATE = 4; PROFILE_KEY_UPDATE = 4;
UNPAIRING_REQUEST = 128;
BACKGROUND_FRIEND_REQUEST = 256; BACKGROUND_FRIEND_REQUEST = 256;
} }

Loading…
Cancel
Save