Convert all storage.devices methods to be asynchronous

This commit is contained in:
lilia 2015-04-13 17:16:09 -07:00
parent 71715c95bc
commit 9de1572ba6
4 changed files with 366 additions and 322 deletions

View file

@ -89,12 +89,12 @@
getIdentityKey: function(identifier) { getIdentityKey: function(identifier) {
if (identifier === null || identifier === undefined) if (identifier === null || identifier === undefined)
throw new Error("Tried to get identity key for undefined/null key"); throw new Error("Tried to get identity key for undefined/null key");
return Promise.resolve(convertToArrayBuffer(textsecure.storage.devices.getIdentityKeyForNumber(textsecure.utils.unencodeNumber(identifier)[0]))); return convertToArrayBuffer(textsecure.storage.devices.getIdentityKeyForNumber(textsecure.utils.unencodeNumber(identifier)[0]));
}, },
putIdentityKey: function(identifier, identityKey) { putIdentityKey: function(identifier, identityKey) {
if (identifier === null || identifier === undefined) if (identifier === null || identifier === undefined)
throw new Error("Tried to put identity key for undefined/null key"); throw new Error("Tried to put identity key for undefined/null key");
return Promise.resolve(textsecure.storage.devices.checkSaveIdentityKeyForNumber(textsecure.utils.unencodeNumber(identifier)[0], identityKey)); return textsecure.storage.devices.checkSaveIdentityKeyForNumber(textsecure.utils.unencodeNumber(identifier)[0], identityKey);
}, },
/* Returns a prekeypair object or undefined */ /* Returns a prekeypair object or undefined */

View file

@ -38111,26 +38111,26 @@ axolotlInternal.RecipientRecord = function() {
}, },
putSessionsForDevice: function(encodedNumber, record) { putSessionsForDevice: function(encodedNumber, record) {
return Promise.resolve((function() { var number = textsecure.utils.unencodeNumber(encodedNumber)[0];
var number = textsecure.utils.unencodeNumber(encodedNumber)[0]; var deviceId = textsecure.utils.unencodeNumber(encodedNumber)[1];
var deviceId = textsecure.utils.unencodeNumber(encodedNumber)[1];
var sessions = textsecure.storage.get("sessions" + number); var sessions = textsecure.storage.get("sessions" + number);
if (sessions === undefined) if (sessions === undefined)
sessions = {}; sessions = {};
sessions[deviceId] = record; sessions[deviceId] = record;
textsecure.storage.put("sessions" + number, sessions); textsecure.storage.put("sessions" + number, sessions);
var device = textsecure.storage.devices.getDeviceObject(encodedNumber); return textsecure.storage.devices.getDeviceObject(encodedNumber).then(function(device) {
if (device === undefined) { if (device === undefined) {
var identityKey = textsecure.storage.devices.getIdentityKeyForNumber(number); return textsecure.storage.devices.getIdentityKeyForNumber(number).then(function(identityKey) {
device = { encodedNumber: encodedNumber, device = { encodedNumber: encodedNumber,
//TODO: Remove this duplication //TODO: Remove this duplication
identityKey: identityKey identityKey: identityKey
}; };
return textsecure.storage.devices.saveDeviceObject(device);
});
} }
return textsecure.storage.devices.saveDeviceObject(device); });
})());
}, },
// Use textsecure.storage.devices.removeIdentityKeyForNumber (which calls this) instead // Use textsecure.storage.devices.removeIdentityKeyForNumber (which calls this) instead
@ -38150,122 +38150,135 @@ axolotlInternal.RecipientRecord = function() {
}, },
removeTempKeysFromDevice: function(encodedNumber) { removeTempKeysFromDevice: function(encodedNumber) {
var deviceObject = textsecure.storage.devices.getDeviceObject(encodedNumber); return textsecure.storage.devices.getDeviceObject(encodedNumber).then(function(deviceObject) {
try { try {
delete deviceObject['signedKey']; delete deviceObject['signedKey'];
delete deviceObject['signedKeyId']; delete deviceObject['signedKeyId'];
delete deviceObject['signedKeySignature']; delete deviceObject['signedKeySignature'];
delete deviceObject['preKey']; delete deviceObject['preKey'];
delete deviceObject['preKeyId']; delete deviceObject['preKeyId'];
delete deviceObject['registrationId']; delete deviceObject['registrationId'];
} catch(_) {} } catch(_) {}
return internalSaveDeviceObject(deviceObject, false); return internalSaveDeviceObject(deviceObject, false);
});
}, },
getDeviceObjectsForNumber: function(number) { getDeviceObjectsForNumber: function(number) {
var map = textsecure.storage.get("devices" + number); return Promise.resolve((function() {
if (map === undefined) var map = textsecure.storage.get("devices" + number);
return []; if (map === undefined)
return map.devices; return [];
return map.devices;
})());
}, },
getIdentityKeyForNumber: function(number) { getIdentityKeyForNumber: function(number) {
var map = textsecure.storage.get("devices" + number); return Promise.resolve((function() {
return map === undefined ? undefined : map.identityKey; var map = textsecure.storage.get("devices" + number);
return map === undefined ? undefined : map.identityKey;
})());
}, },
checkSaveIdentityKeyForNumber: function(number, identityKey) { checkSaveIdentityKeyForNumber: function(number, identityKey) {
var map = textsecure.storage.get("devices" + number); return Promise.resolve((function() {
if (map === undefined) var map = textsecure.storage.get("devices" + number);
textsecure.storage.put("devices" + number, { devices: [], identityKey: identityKey}); if (map === undefined)
else if (getString(map.identityKey) !== getString(identityKey)) textsecure.storage.put("devices" + number, { devices: [], identityKey: identityKey});
throw new Error("Attempted to overwrite a different identity key"); else if (getString(map.identityKey) !== getString(identityKey))
throw new Error("Attempted to overwrite a different identity key");
})());
}, },
removeIdentityKeyForNumber: function(number) { removeIdentityKeyForNumber: function(number) {
var map = textsecure.storage.get("devices" + number); return Promise.resolve((function() {
if (map === undefined) var map = textsecure.storage.get("devices" + number);
throw new Error("Tried to remove identity for unknown number"); if (map === undefined)
textsecure.storage.remove("devices" + number); throw new Error("Tried to remove identity for unknown number");
return textsecure.storage.sessions._removeIdentityKeyForNumber(number); textsecure.storage.remove("devices" + number);
return textsecure.storage.sessions._removeIdentityKeyForNumber(number);
})());
}, },
getDeviceObject: function(encodedNumber) { getDeviceObject: function(encodedNumber) {
var number = textsecure.utils.unencodeNumber(encodedNumber)[0]; var number = textsecure.utils.unencodeNumber(encodedNumber)[0];
var devices = textsecure.storage.devices.getDeviceObjectsForNumber(number); return textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devices) {
for (var i in devices)
if (devices[i].encodedNumber == encodedNumber)
return devices[i];
for (var i in devices) return undefined;
if (devices[i].encodedNumber == encodedNumber) });
return devices[i];
return undefined;
}, },
removeDeviceIdsForNumber: function(number, deviceIdsToRemove) { removeDeviceIdsForNumber: function(number, deviceIdsToRemove) {
var map = textsecure.storage.get("devices" + number); return Promise.resolve((function() {
if (map === undefined) var map = textsecure.storage.get("devices" + number);
throw new Error("Tried to remove device for unknown number"); if (map === undefined)
throw new Error("Tried to remove device for unknown number");
var newDevices = []; var newDevices = [];
var devicesRemoved = 0; var devicesRemoved = 0;
for (var i in map.devices) { for (var i in map.devices) {
var keep = true; var keep = true;
for (var j in deviceIdsToRemove) for (var j in deviceIdsToRemove)
if (map.devices[i].encodedNumber == number + "." + deviceIdsToRemove[j]) if (map.devices[i].encodedNumber == number + "." + deviceIdsToRemove[j])
keep = false; keep = false;
if (keep) if (keep)
newDevices.push(map.devices[i]); newDevices.push(map.devices[i]);
else else
devicesRemoved++; devicesRemoved++;
} }
if (devicesRemoved != deviceIdsToRemove.length) if (devicesRemoved != deviceIdsToRemove.length)
throw new Error("Tried to remove unknown device"); throw new Error("Tried to remove unknown device");
if (newDevices.length === 0) if (newDevices.length === 0)
textsecure.storage.remove("devices" + number); textsecure.storage.remove("devices" + number);
else { else {
map.devices = newDevices; map.devices = newDevices;
textsecure.storage.put("devices" + number, map); textsecure.storage.put("devices" + number, map);
} }
})());
} }
}; };
var internalSaveDeviceObject = function(deviceObject, onlyKeys) { var internalSaveDeviceObject = function(deviceObject, onlyKeys) {
if (deviceObject.identityKey === undefined || deviceObject.encodedNumber === undefined) return Promise.resolve((function() {
throw new Error("Tried to store invalid deviceObject"); if (deviceObject.identityKey === undefined || deviceObject.encodedNumber === undefined)
throw new Error("Tried to store invalid deviceObject");
var number = textsecure.utils.unencodeNumber(deviceObject.encodedNumber)[0]; var number = textsecure.utils.unencodeNumber(deviceObject.encodedNumber)[0];
var map = textsecure.storage.get("devices" + number); var map = textsecure.storage.get("devices" + number);
if (map === undefined) if (map === undefined)
map = { devices: [deviceObject], identityKey: deviceObject.identityKey }; map = { devices: [deviceObject], identityKey: deviceObject.identityKey };
else if (map.identityKey != getString(deviceObject.identityKey)) else if (map.identityKey != getString(deviceObject.identityKey))
throw new Error("Identity key changed"); throw new Error("Identity key changed");
else { else {
var updated = false; var updated = false;
for (var i in map.devices) { for (var i in map.devices) {
if (map.devices[i].encodedNumber == deviceObject.encodedNumber) { if (map.devices[i].encodedNumber == deviceObject.encodedNumber) {
if (!onlyKeys) if (!onlyKeys)
map.devices[i] = deviceObject; map.devices[i] = deviceObject;
else { else {
map.devices[i].preKey = deviceObject.preKey; map.devices[i].preKey = deviceObject.preKey;
map.devices[i].preKeyId = deviceObject.preKeyId; map.devices[i].preKeyId = deviceObject.preKeyId;
map.devices[i].signedKey = deviceObject.signedKey; map.devices[i].signedKey = deviceObject.signedKey;
map.devices[i].signedKeyId = deviceObject.signedKeyId; map.devices[i].signedKeyId = deviceObject.signedKeyId;
map.devices[i].signedKeySignature = deviceObject.signedKeySignature; map.devices[i].signedKeySignature = deviceObject.signedKeySignature;
map.devices[i].registrationId = deviceObject.registrationId; map.devices[i].registrationId = deviceObject.registrationId;
}
updated = true;
} }
updated = true;
} }
if (!updated)
map.devices.push(deviceObject);
} }
if (!updated) textsecure.storage.put("devices" + number, map);
map.devices.push(deviceObject); })());
}
textsecure.storage.put("devices" + number, map);
}; };
})(); })();
@ -39623,19 +39636,19 @@ window.textsecure.messaging = function() {
//TODO: Dont hit disk for any of the key-fetching! //TODO: Dont hit disk for any of the key-fetching!
function getKeysForNumber(number, updateDevices) { function getKeysForNumber(number, updateDevices) {
var handleResult = function(response) { var handleResult = function(response) {
for (var i in response.devices) { return Promise.all(response.devices.map(function(device) {
if (updateDevices === undefined || updateDevices.indexOf(response.devices[i].deviceId) > -1) if (updateDevices === undefined || updateDevices.indexOf(device.deviceId) > -1)
textsecure.storage.devices.saveKeysToDeviceObject({ return textsecure.storage.devices.saveKeysToDeviceObject({
encodedNumber: number + "." + response.devices[i].deviceId, encodedNumber: number + "." + device.deviceId,
identityKey: response.identityKey, identityKey: response.identityKey,
preKey: response.devices[i].preKey.publicKey, preKey: device.preKey.publicKey,
preKeyId: response.devices[i].preKey.keyId, preKeyId: device.preKey.keyId,
signedKey: response.devices[i].signedPreKey.publicKey, signedKey: device.signedPreKey.publicKey,
signedKeyId: response.devices[i].signedPreKey.keyId, signedKeyId: device.signedPreKey.keyId,
signedKeySignature: response.devices[i].signedPreKey.signature, signedKeySignature: device.signedPreKey.signature,
registrationId: response.devices[i].registrationId registrationId: device.registrationId
}); });
} }));
}; };
var promises = []; var promises = [];
@ -39670,18 +39683,18 @@ window.textsecure.messaging = function() {
return textsecure.protocol_wrapper.encryptMessageFor(deviceObjectList[i], message).then(function(encryptedMsg) { return textsecure.protocol_wrapper.encryptMessageFor(deviceObjectList[i], message).then(function(encryptedMsg) {
return textsecure.protocol_wrapper.getRegistrationId(deviceObjectList[i].encodedNumber).then(function(registrationId) { return textsecure.protocol_wrapper.getRegistrationId(deviceObjectList[i].encodedNumber).then(function(registrationId) {
textsecure.storage.devices.removeTempKeysFromDevice(deviceObjectList[i].encodedNumber); return textsecure.storage.devices.removeTempKeysFromDevice(deviceObjectList[i].encodedNumber).then(function() {
jsonData[i] = {
type: encryptedMsg.type,
destinationDeviceId: textsecure.utils.unencodeNumber(deviceObjectList[i].encodedNumber)[1],
destinationRegistrationId: registrationId,
body: encryptedMsg.body,
timestamp: timestamp
};
jsonData[i] = { if (deviceObjectList[i].relay !== undefined)
type: encryptedMsg.type, jsonData[i].relay = deviceObjectList[i].relay;
destinationDeviceId: textsecure.utils.unencodeNumber(deviceObjectList[i].encodedNumber)[1], });
destinationRegistrationId: registrationId,
body: encryptedMsg.body,
timestamp: timestamp
};
if (deviceObjectList[i].relay !== undefined)
jsonData[i].relay = deviceObjectList[i].relay;
}); });
}); });
} }
@ -39768,10 +39781,11 @@ window.textsecure.messaging = function() {
var doSendMessage; var doSendMessage;
var reloadDevicesAndSend = function(number, recurse) { var reloadDevicesAndSend = function(number, recurse) {
return function() { return function() {
var devicesForNumber = textsecure.storage.devices.getDeviceObjectsForNumber(number); return textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devicesForNumber) {
if (devicesForNumber.length == 0) if (devicesForNumber.length == 0)
return registerError(number, "Got empty device list when loading device keys", null); return registerError(number, "Got empty device list when loading device keys", null);
doSendMessage(number, devicesForNumber, recurse); doSendMessage(number, devicesForNumber, recurse);
});
} }
} }
@ -39789,46 +39803,52 @@ window.textsecure.messaging = function() {
if (!recurse) if (!recurse)
return registerError(number, "Hit retry limit attempting to reload device list", error); return registerError(number, "Hit retry limit attempting to reload device list", error);
if (error.message == 409) var p;
textsecure.storage.devices.removeDeviceIdsForNumber(number, error.response.extraDevices); if (error.message == 409) {
p = textsecure.storage.devices.removeDeviceIdsForNumber(number, error.response.extraDevices);
} else {
p = Promise.resolve();
}
var resetDevices = ((error.message == 410) ? error.response.staleDevices : error.response.missingDevices); p.then(function() {
getKeysForNumber(number, resetDevices) var resetDevices = ((error.message == 410) ? error.response.staleDevices : error.response.missingDevices);
.then(reloadDevicesAndSend(number, false)) getKeysForNumber(number, resetDevices)
.catch(function(error) { .then(reloadDevicesAndSend(number, false))
if (error.message !== "Identity key changed") .catch(function(error) {
registerError(number, "Failed to reload device keys", error); if (error.message !== "Identity key changed")
else { registerError(number, "Failed to reload device keys", error);
error = new textsecure.OutgoingIdentityKeyError(number, message.toArrayBuffer(), timestamp); else {
registerError(number, "Identity key changed", error); error = new textsecure.OutgoingIdentityKeyError(number, message.toArrayBuffer(), timestamp);
} registerError(number, "Identity key changed", error);
}); }
});
});
} else } else
registerError(number, "Failed to create or send message", error); registerError(number, "Failed to create or send message", error);
}); });
} }
var getDevicesAndSendToNumber = function(number) { var getDevicesAndSendToNumber = function(number) {
var devicesForNumber = textsecure.storage.devices.getDeviceObjectsForNumber(number); textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devicesForNumber) {
return Promise.all(devicesForNumber.map(function(device) {
return Promise.all(devicesForNumber.map(function(device) { return textsecure.protocol_wrapper.hasOpenSession(device.encodedNumber).then(function(result) {
return textsecure.protocol_wrapper.hasOpenSession(device.encodedNumber).then(function(result) { if (!result)
if (!result) return getKeysForNumber(number, [parseInt(textsecure.utils.unencodeNumber(device.encodedNumber)[1])]);
return getKeysForNumber(number, [parseInt(textsecure.utils.unencodeNumber(device.encodedNumber)[1])]); });
})).then(function() {
return textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devicesForNumber) {
if (devicesForNumber.length == 0) {
getKeysForNumber(number)
.then(reloadDevicesAndSend(number, true))
.catch(function(error) {
registerError(number, "Failed to retreive new device keys for number " + number, error);
});
} else
doSendMessage(number, devicesForNumber, true);
});
}); });
})).then(function() {
devicesForNumber = textsecure.storage.devices.getDeviceObjectsForNumber(number);
if (devicesForNumber.length == 0) {
getKeysForNumber(number)
.then(reloadDevicesAndSend(number, true))
.catch(function(error) {
registerError(number, "Failed to retreive new device keys for number " + number, error);
});
} else
doSendMessage(number, devicesForNumber, true);
}); });
} };
for (var i in numbers) for (var i in numbers)
getDevicesAndSendToNumber(numbers[i]); getDevicesAndSendToNumber(numbers[i]);
@ -39908,11 +39928,13 @@ window.textsecure.messaging = function() {
proto.body = "TERMINATE"; proto.body = "TERMINATE";
proto.flags = textsecure.protobuf.PushMessageContent.Flags.END_SESSION; proto.flags = textsecure.protobuf.PushMessageContent.Flags.END_SESSION;
return sendIndividualProto(number, proto, Date.now()).then(function(res) { return sendIndividualProto(number, proto, Date.now()).then(function(res) {
var devices = textsecure.storage.devices.getDeviceObjectsForNumber(number); return textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devices) {
for (var i in devices) return Promise.all(devices.map(function(device) {
textsecure.protocol_wrapper.closeOpenSessionForDevice(devices[i].encodedNumber); return textsecure.protocol_wrapper.closeOpenSessionForDevice(devices.encodedNumber);
})).then(function() {
return res; return res;
});
});
}); });
} }

View file

@ -22,19 +22,19 @@ window.textsecure.messaging = function() {
//TODO: Dont hit disk for any of the key-fetching! //TODO: Dont hit disk for any of the key-fetching!
function getKeysForNumber(number, updateDevices) { function getKeysForNumber(number, updateDevices) {
var handleResult = function(response) { var handleResult = function(response) {
for (var i in response.devices) { return Promise.all(response.devices.map(function(device) {
if (updateDevices === undefined || updateDevices.indexOf(response.devices[i].deviceId) > -1) if (updateDevices === undefined || updateDevices.indexOf(device.deviceId) > -1)
textsecure.storage.devices.saveKeysToDeviceObject({ return textsecure.storage.devices.saveKeysToDeviceObject({
encodedNumber: number + "." + response.devices[i].deviceId, encodedNumber: number + "." + device.deviceId,
identityKey: response.identityKey, identityKey: response.identityKey,
preKey: response.devices[i].preKey.publicKey, preKey: device.preKey.publicKey,
preKeyId: response.devices[i].preKey.keyId, preKeyId: device.preKey.keyId,
signedKey: response.devices[i].signedPreKey.publicKey, signedKey: device.signedPreKey.publicKey,
signedKeyId: response.devices[i].signedPreKey.keyId, signedKeyId: device.signedPreKey.keyId,
signedKeySignature: response.devices[i].signedPreKey.signature, signedKeySignature: device.signedPreKey.signature,
registrationId: response.devices[i].registrationId registrationId: device.registrationId
}); });
} }));
}; };
var promises = []; var promises = [];
@ -69,18 +69,18 @@ window.textsecure.messaging = function() {
return textsecure.protocol_wrapper.encryptMessageFor(deviceObjectList[i], message).then(function(encryptedMsg) { return textsecure.protocol_wrapper.encryptMessageFor(deviceObjectList[i], message).then(function(encryptedMsg) {
return textsecure.protocol_wrapper.getRegistrationId(deviceObjectList[i].encodedNumber).then(function(registrationId) { return textsecure.protocol_wrapper.getRegistrationId(deviceObjectList[i].encodedNumber).then(function(registrationId) {
textsecure.storage.devices.removeTempKeysFromDevice(deviceObjectList[i].encodedNumber); return textsecure.storage.devices.removeTempKeysFromDevice(deviceObjectList[i].encodedNumber).then(function() {
jsonData[i] = {
type: encryptedMsg.type,
destinationDeviceId: textsecure.utils.unencodeNumber(deviceObjectList[i].encodedNumber)[1],
destinationRegistrationId: registrationId,
body: encryptedMsg.body,
timestamp: timestamp
};
jsonData[i] = { if (deviceObjectList[i].relay !== undefined)
type: encryptedMsg.type, jsonData[i].relay = deviceObjectList[i].relay;
destinationDeviceId: textsecure.utils.unencodeNumber(deviceObjectList[i].encodedNumber)[1], });
destinationRegistrationId: registrationId,
body: encryptedMsg.body,
timestamp: timestamp
};
if (deviceObjectList[i].relay !== undefined)
jsonData[i].relay = deviceObjectList[i].relay;
}); });
}); });
} }
@ -167,10 +167,11 @@ window.textsecure.messaging = function() {
var doSendMessage; var doSendMessage;
var reloadDevicesAndSend = function(number, recurse) { var reloadDevicesAndSend = function(number, recurse) {
return function() { return function() {
var devicesForNumber = textsecure.storage.devices.getDeviceObjectsForNumber(number); return textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devicesForNumber) {
if (devicesForNumber.length == 0) if (devicesForNumber.length == 0)
return registerError(number, "Got empty device list when loading device keys", null); return registerError(number, "Got empty device list when loading device keys", null);
doSendMessage(number, devicesForNumber, recurse); doSendMessage(number, devicesForNumber, recurse);
});
} }
} }
@ -188,46 +189,52 @@ window.textsecure.messaging = function() {
if (!recurse) if (!recurse)
return registerError(number, "Hit retry limit attempting to reload device list", error); return registerError(number, "Hit retry limit attempting to reload device list", error);
if (error.message == 409) var p;
textsecure.storage.devices.removeDeviceIdsForNumber(number, error.response.extraDevices); if (error.message == 409) {
p = textsecure.storage.devices.removeDeviceIdsForNumber(number, error.response.extraDevices);
} else {
p = Promise.resolve();
}
var resetDevices = ((error.message == 410) ? error.response.staleDevices : error.response.missingDevices); p.then(function() {
getKeysForNumber(number, resetDevices) var resetDevices = ((error.message == 410) ? error.response.staleDevices : error.response.missingDevices);
.then(reloadDevicesAndSend(number, false)) getKeysForNumber(number, resetDevices)
.catch(function(error) { .then(reloadDevicesAndSend(number, false))
if (error.message !== "Identity key changed") .catch(function(error) {
registerError(number, "Failed to reload device keys", error); if (error.message !== "Identity key changed")
else { registerError(number, "Failed to reload device keys", error);
error = new textsecure.OutgoingIdentityKeyError(number, message.toArrayBuffer(), timestamp); else {
registerError(number, "Identity key changed", error); error = new textsecure.OutgoingIdentityKeyError(number, message.toArrayBuffer(), timestamp);
} registerError(number, "Identity key changed", error);
}); }
});
});
} else } else
registerError(number, "Failed to create or send message", error); registerError(number, "Failed to create or send message", error);
}); });
} }
var getDevicesAndSendToNumber = function(number) { var getDevicesAndSendToNumber = function(number) {
var devicesForNumber = textsecure.storage.devices.getDeviceObjectsForNumber(number); textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devicesForNumber) {
return Promise.all(devicesForNumber.map(function(device) {
return Promise.all(devicesForNumber.map(function(device) { return textsecure.protocol_wrapper.hasOpenSession(device.encodedNumber).then(function(result) {
return textsecure.protocol_wrapper.hasOpenSession(device.encodedNumber).then(function(result) { if (!result)
if (!result) return getKeysForNumber(number, [parseInt(textsecure.utils.unencodeNumber(device.encodedNumber)[1])]);
return getKeysForNumber(number, [parseInt(textsecure.utils.unencodeNumber(device.encodedNumber)[1])]); });
})).then(function() {
return textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devicesForNumber) {
if (devicesForNumber.length == 0) {
getKeysForNumber(number)
.then(reloadDevicesAndSend(number, true))
.catch(function(error) {
registerError(number, "Failed to retreive new device keys for number " + number, error);
});
} else
doSendMessage(number, devicesForNumber, true);
});
}); });
})).then(function() {
devicesForNumber = textsecure.storage.devices.getDeviceObjectsForNumber(number);
if (devicesForNumber.length == 0) {
getKeysForNumber(number)
.then(reloadDevicesAndSend(number, true))
.catch(function(error) {
registerError(number, "Failed to retreive new device keys for number " + number, error);
});
} else
doSendMessage(number, devicesForNumber, true);
}); });
} };
for (var i in numbers) for (var i in numbers)
getDevicesAndSendToNumber(numbers[i]); getDevicesAndSendToNumber(numbers[i]);
@ -307,11 +314,13 @@ window.textsecure.messaging = function() {
proto.body = "TERMINATE"; proto.body = "TERMINATE";
proto.flags = textsecure.protobuf.PushMessageContent.Flags.END_SESSION; proto.flags = textsecure.protobuf.PushMessageContent.Flags.END_SESSION;
return sendIndividualProto(number, proto, Date.now()).then(function(res) { return sendIndividualProto(number, proto, Date.now()).then(function(res) {
var devices = textsecure.storage.devices.getDeviceObjectsForNumber(number); return textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devices) {
for (var i in devices) return Promise.all(devices.map(function(device) {
textsecure.protocol_wrapper.closeOpenSessionForDevice(devices[i].encodedNumber); return textsecure.protocol_wrapper.closeOpenSessionForDevice(devices.encodedNumber);
})).then(function() {
return res; return res;
});
});
}); });
} }

View file

@ -40,26 +40,26 @@
}, },
putSessionsForDevice: function(encodedNumber, record) { putSessionsForDevice: function(encodedNumber, record) {
return Promise.resolve((function() { var number = textsecure.utils.unencodeNumber(encodedNumber)[0];
var number = textsecure.utils.unencodeNumber(encodedNumber)[0]; var deviceId = textsecure.utils.unencodeNumber(encodedNumber)[1];
var deviceId = textsecure.utils.unencodeNumber(encodedNumber)[1];
var sessions = textsecure.storage.get("sessions" + number); var sessions = textsecure.storage.get("sessions" + number);
if (sessions === undefined) if (sessions === undefined)
sessions = {}; sessions = {};
sessions[deviceId] = record; sessions[deviceId] = record;
textsecure.storage.put("sessions" + number, sessions); textsecure.storage.put("sessions" + number, sessions);
var device = textsecure.storage.devices.getDeviceObject(encodedNumber); return textsecure.storage.devices.getDeviceObject(encodedNumber).then(function(device) {
if (device === undefined) { if (device === undefined) {
var identityKey = textsecure.storage.devices.getIdentityKeyForNumber(number); return textsecure.storage.devices.getIdentityKeyForNumber(number).then(function(identityKey) {
device = { encodedNumber: encodedNumber, device = { encodedNumber: encodedNumber,
//TODO: Remove this duplication //TODO: Remove this duplication
identityKey: identityKey identityKey: identityKey
}; };
return textsecure.storage.devices.saveDeviceObject(device);
});
} }
return textsecure.storage.devices.saveDeviceObject(device); });
})());
}, },
// Use textsecure.storage.devices.removeIdentityKeyForNumber (which calls this) instead // Use textsecure.storage.devices.removeIdentityKeyForNumber (which calls this) instead
@ -79,121 +79,134 @@
}, },
removeTempKeysFromDevice: function(encodedNumber) { removeTempKeysFromDevice: function(encodedNumber) {
var deviceObject = textsecure.storage.devices.getDeviceObject(encodedNumber); return textsecure.storage.devices.getDeviceObject(encodedNumber).then(function(deviceObject) {
try { try {
delete deviceObject['signedKey']; delete deviceObject['signedKey'];
delete deviceObject['signedKeyId']; delete deviceObject['signedKeyId'];
delete deviceObject['signedKeySignature']; delete deviceObject['signedKeySignature'];
delete deviceObject['preKey']; delete deviceObject['preKey'];
delete deviceObject['preKeyId']; delete deviceObject['preKeyId'];
delete deviceObject['registrationId']; delete deviceObject['registrationId'];
} catch(_) {} } catch(_) {}
return internalSaveDeviceObject(deviceObject, false); return internalSaveDeviceObject(deviceObject, false);
});
}, },
getDeviceObjectsForNumber: function(number) { getDeviceObjectsForNumber: function(number) {
var map = textsecure.storage.get("devices" + number); return Promise.resolve((function() {
if (map === undefined) var map = textsecure.storage.get("devices" + number);
return []; if (map === undefined)
return map.devices; return [];
return map.devices;
})());
}, },
getIdentityKeyForNumber: function(number) { getIdentityKeyForNumber: function(number) {
var map = textsecure.storage.get("devices" + number); return Promise.resolve((function() {
return map === undefined ? undefined : map.identityKey; var map = textsecure.storage.get("devices" + number);
return map === undefined ? undefined : map.identityKey;
})());
}, },
checkSaveIdentityKeyForNumber: function(number, identityKey) { checkSaveIdentityKeyForNumber: function(number, identityKey) {
var map = textsecure.storage.get("devices" + number); return Promise.resolve((function() {
if (map === undefined) var map = textsecure.storage.get("devices" + number);
textsecure.storage.put("devices" + number, { devices: [], identityKey: identityKey}); if (map === undefined)
else if (getString(map.identityKey) !== getString(identityKey)) textsecure.storage.put("devices" + number, { devices: [], identityKey: identityKey});
throw new Error("Attempted to overwrite a different identity key"); else if (getString(map.identityKey) !== getString(identityKey))
throw new Error("Attempted to overwrite a different identity key");
})());
}, },
removeIdentityKeyForNumber: function(number) { removeIdentityKeyForNumber: function(number) {
var map = textsecure.storage.get("devices" + number); return Promise.resolve((function() {
if (map === undefined) var map = textsecure.storage.get("devices" + number);
throw new Error("Tried to remove identity for unknown number"); if (map === undefined)
textsecure.storage.remove("devices" + number); throw new Error("Tried to remove identity for unknown number");
return textsecure.storage.sessions._removeIdentityKeyForNumber(number); textsecure.storage.remove("devices" + number);
return textsecure.storage.sessions._removeIdentityKeyForNumber(number);
})());
}, },
getDeviceObject: function(encodedNumber) { getDeviceObject: function(encodedNumber) {
var number = textsecure.utils.unencodeNumber(encodedNumber)[0]; var number = textsecure.utils.unencodeNumber(encodedNumber)[0];
var devices = textsecure.storage.devices.getDeviceObjectsForNumber(number); return textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devices) {
for (var i in devices)
if (devices[i].encodedNumber == encodedNumber)
return devices[i];
for (var i in devices) return undefined;
if (devices[i].encodedNumber == encodedNumber) });
return devices[i];
return undefined;
}, },
removeDeviceIdsForNumber: function(number, deviceIdsToRemove) { removeDeviceIdsForNumber: function(number, deviceIdsToRemove) {
var map = textsecure.storage.get("devices" + number); return Promise.resolve((function() {
if (map === undefined) var map = textsecure.storage.get("devices" + number);
throw new Error("Tried to remove device for unknown number"); if (map === undefined)
throw new Error("Tried to remove device for unknown number");
var newDevices = []; var newDevices = [];
var devicesRemoved = 0; var devicesRemoved = 0;
for (var i in map.devices) { for (var i in map.devices) {
var keep = true; var keep = true;
for (var j in deviceIdsToRemove) for (var j in deviceIdsToRemove)
if (map.devices[i].encodedNumber == number + "." + deviceIdsToRemove[j]) if (map.devices[i].encodedNumber == number + "." + deviceIdsToRemove[j])
keep = false; keep = false;
if (keep) if (keep)
newDevices.push(map.devices[i]); newDevices.push(map.devices[i]);
else else
devicesRemoved++; devicesRemoved++;
} }
if (devicesRemoved != deviceIdsToRemove.length) if (devicesRemoved != deviceIdsToRemove.length)
throw new Error("Tried to remove unknown device"); throw new Error("Tried to remove unknown device");
if (newDevices.length === 0) if (newDevices.length === 0)
textsecure.storage.remove("devices" + number); textsecure.storage.remove("devices" + number);
else { else {
map.devices = newDevices; map.devices = newDevices;
textsecure.storage.put("devices" + number, map); textsecure.storage.put("devices" + number, map);
} }
})());
} }
}; };
var internalSaveDeviceObject = function(deviceObject, onlyKeys) { var internalSaveDeviceObject = function(deviceObject, onlyKeys) {
if (deviceObject.identityKey === undefined || deviceObject.encodedNumber === undefined) return Promise.resolve((function() {
throw new Error("Tried to store invalid deviceObject"); if (deviceObject.identityKey === undefined || deviceObject.encodedNumber === undefined)
throw new Error("Tried to store invalid deviceObject");
var number = textsecure.utils.unencodeNumber(deviceObject.encodedNumber)[0]; var number = textsecure.utils.unencodeNumber(deviceObject.encodedNumber)[0];
var map = textsecure.storage.get("devices" + number); var map = textsecure.storage.get("devices" + number);
if (map === undefined) if (map === undefined)
map = { devices: [deviceObject], identityKey: deviceObject.identityKey }; map = { devices: [deviceObject], identityKey: deviceObject.identityKey };
else if (map.identityKey != getString(deviceObject.identityKey)) else if (map.identityKey != getString(deviceObject.identityKey))
throw new Error("Identity key changed"); throw new Error("Identity key changed");
else { else {
var updated = false; var updated = false;
for (var i in map.devices) { for (var i in map.devices) {
if (map.devices[i].encodedNumber == deviceObject.encodedNumber) { if (map.devices[i].encodedNumber == deviceObject.encodedNumber) {
if (!onlyKeys) if (!onlyKeys)
map.devices[i] = deviceObject; map.devices[i] = deviceObject;
else { else {
map.devices[i].preKey = deviceObject.preKey; map.devices[i].preKey = deviceObject.preKey;
map.devices[i].preKeyId = deviceObject.preKeyId; map.devices[i].preKeyId = deviceObject.preKeyId;
map.devices[i].signedKey = deviceObject.signedKey; map.devices[i].signedKey = deviceObject.signedKey;
map.devices[i].signedKeyId = deviceObject.signedKeyId; map.devices[i].signedKeyId = deviceObject.signedKeyId;
map.devices[i].signedKeySignature = deviceObject.signedKeySignature; map.devices[i].signedKeySignature = deviceObject.signedKeySignature;
map.devices[i].registrationId = deviceObject.registrationId; map.devices[i].registrationId = deviceObject.registrationId;
}
updated = true;
} }
updated = true;
} }
if (!updated)
map.devices.push(deviceObject);
} }
if (!updated) textsecure.storage.put("devices" + number, map);
map.devices.push(deviceObject); })());
}
textsecure.storage.put("devices" + number, map);
}; };
})(); })();