Sending and handling of special UNPAIRING_REQUEST message
This commit is contained in:
parent
8cd8c8d4f9
commit
db0068b429
|
@ -1025,6 +1025,15 @@
|
|||
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 = () =>
|
||||
|
|
|
@ -224,6 +224,10 @@ class LokiFileServerAPI {
|
|||
uploadPrivateAttachment(data) {
|
||||
return this._server.uploadData(data);
|
||||
}
|
||||
|
||||
clearOurDeviceMappingAnnotations() {
|
||||
return this._server.setSelfAnnotation(DEVICE_MAPPING_ANNOTATION_KEY, null);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LokiFileServerAPI;
|
||||
|
|
|
@ -223,6 +223,9 @@
|
|||
dialog.on('devicePairingRequestRejected', pubKey =>
|
||||
Whisper.events.trigger('devicePairingRequestRejected', pubKey)
|
||||
);
|
||||
dialog.on('deviceUnpairingRequested', pubKey =>
|
||||
Whisper.events.trigger('deviceUnpairingRequested', pubKey)
|
||||
);
|
||||
dialog.once('close', () => {
|
||||
Whisper.events.off('devicePairingRequestReceived');
|
||||
});
|
||||
|
|
|
@ -117,10 +117,7 @@
|
|||
this.pubKey = this.pubKeyRequests.pop();
|
||||
},
|
||||
async confirmUnpairDevice() {
|
||||
await libloki.storage.removePairingAuthorisationForSecondaryPubKey(
|
||||
this.pubKeyToUnpair
|
||||
);
|
||||
await lokiFileServerAPI.updateOurDeviceMapping();
|
||||
this.trigger('deviceUnpairingRequested', this.pubKeyToUnpair);
|
||||
this.reset();
|
||||
this.showView();
|
||||
},
|
||||
|
|
|
@ -107,6 +107,27 @@
|
|||
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>...
|
||||
// This is an implementation of the reciprocal of contacts_parser.js
|
||||
function serialiseByteBuffers(buffers) {
|
||||
|
@ -226,6 +247,7 @@
|
|||
broadcastOnlineStatus,
|
||||
sendPairingAuthorisation,
|
||||
createPairingAuthorisationProtoMessage,
|
||||
sendUnpairingMessageToSecondary,
|
||||
createContactSyncProtoMessage,
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -1286,7 +1286,8 @@ MessageReceiver.prototype.extend({
|
|||
this.processDecrypted(envelope, msg).then(async message => {
|
||||
const groupId = message.group && message.group.id;
|
||||
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 isLeavingGroup = Boolean(
|
||||
message.group &&
|
||||
|
@ -1294,6 +1295,72 @@ MessageReceiver.prototype.extend({
|
|||
);
|
||||
const friendRequest =
|
||||
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
|
||||
if (!isMe && conversation) {
|
||||
|
@ -1787,6 +1854,8 @@ MessageReceiver.prototype.extend({
|
|||
decrypted.attachments = [];
|
||||
} else if (decrypted.flags & FLAGS.BACKGROUND_FRIEND_REQUEST) {
|
||||
// do nothing
|
||||
} else if (decrypted.flags & FLAGS.UNPAIRING_REQUEST) {
|
||||
// do nothing
|
||||
} else if (decrypted.flags !== 0) {
|
||||
throw new Error('Unknown flags in message');
|
||||
}
|
||||
|
|
|
@ -443,6 +443,8 @@ OutgoingMessage.prototype = {
|
|||
switch (type) {
|
||||
case 'friend-request':
|
||||
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':
|
||||
return 60 * 1000; // 1 minute for online broadcast message
|
||||
case 'typing':
|
||||
|
|
|
@ -469,6 +469,6 @@ window.pubkeyPattern = /@[a-fA-F0-9]{64,66}\b/g;
|
|||
window.SMALL_GROUP_SIZE_LIMIT = 10;
|
||||
|
||||
window.lokiFeatureFlags = {
|
||||
multiDeviceUnpairing: false,
|
||||
multiDeviceUnpairing: true,
|
||||
privateGroupChats: false,
|
||||
};
|
||||
|
|
|
@ -105,6 +105,7 @@ message DataMessage {
|
|||
END_SESSION = 1;
|
||||
EXPIRATION_TIMER_UPDATE = 2;
|
||||
PROFILE_KEY_UPDATE = 4;
|
||||
UNPAIRING_REQUEST = 128;
|
||||
BACKGROUND_FRIEND_REQUEST = 256;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue