2014-10-29 03:30:35 +00:00
|
|
|
/* vim: ts=4:sw=4
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
;(function() {
|
|
|
|
/**********************
|
|
|
|
*** Device Storage ***
|
|
|
|
**********************/
|
|
|
|
window.textsecure = window.textsecure || {};
|
|
|
|
window.textsecure.storage = window.textsecure.storage || {};
|
|
|
|
|
|
|
|
window.textsecure.storage.devices = {
|
|
|
|
saveDeviceObject: function(deviceObject) {
|
|
|
|
return internalSaveDeviceObject(deviceObject, false);
|
|
|
|
},
|
|
|
|
|
|
|
|
saveKeysToDeviceObject: function(deviceObject) {
|
|
|
|
return internalSaveDeviceObject(deviceObject, true);
|
|
|
|
},
|
|
|
|
|
2015-01-19 19:56:48 +00:00
|
|
|
removeTempKeysFromDevice: function(encodedNumber) {
|
|
|
|
var deviceObject = textsecure.storage.devices.getDeviceObject(encodedNumber);
|
|
|
|
try {
|
|
|
|
delete deviceObject['signedKey'];
|
|
|
|
delete deviceObject['signedKeyId'];
|
|
|
|
delete deviceObject['signedKeySignature'];
|
|
|
|
delete deviceObject['preKey'];
|
|
|
|
delete deviceObject['preKeyId'];
|
2015-01-21 08:47:03 +00:00
|
|
|
delete deviceObject['registrationId'];
|
2015-01-19 19:56:48 +00:00
|
|
|
} catch(_) {}
|
|
|
|
return internalSaveDeviceObject(deviceObject, false);
|
|
|
|
},
|
|
|
|
|
2014-10-29 03:30:35 +00:00
|
|
|
getDeviceObjectsForNumber: function(number) {
|
2015-03-24 23:20:36 +00:00
|
|
|
var map = textsecure.storage.get("devices" + number);
|
2015-01-21 08:29:23 +00:00
|
|
|
if (map === undefined)
|
|
|
|
return [];
|
|
|
|
for (key in map.devices) {
|
|
|
|
if (map.devices[key].sessions !== undefined) {
|
|
|
|
var record = new axolotl.sessions.RecipientRecord();
|
|
|
|
record.deserialize(map.devices[key].sessions);
|
|
|
|
if (getString(map.identityKey) !== getString(record.identityKey))
|
|
|
|
throw new Error("Got mismatched identity key on device object load");
|
|
|
|
map.devices[key].sessions = record;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return map.devices;
|
2014-10-29 03:30:35 +00:00
|
|
|
},
|
|
|
|
|
2015-01-21 08:14:44 +00:00
|
|
|
getIdentityKeyForNumber: function(number) {
|
2015-03-24 23:20:36 +00:00
|
|
|
var map = textsecure.storage.get("devices" + number);
|
2015-01-21 08:14:44 +00:00
|
|
|
return map === undefined ? undefined : map.identityKey;
|
|
|
|
},
|
|
|
|
|
|
|
|
checkSaveIdentityKeyForNumber: function(number, identityKey) {
|
2015-03-24 23:20:36 +00:00
|
|
|
var map = textsecure.storage.get("devices" + number);
|
2015-01-21 08:14:44 +00:00
|
|
|
if (map === undefined)
|
2015-03-24 23:20:36 +00:00
|
|
|
textsecure.storage.put("devices" + number, { devices: [], identityKey: identityKey});
|
2015-01-21 08:14:44 +00:00
|
|
|
else if (getString(map.identityKey) !== getString(identityKey))
|
|
|
|
throw new Error("Attempted to overwrite a different identity key");
|
|
|
|
},
|
|
|
|
|
2015-02-20 22:43:22 +00:00
|
|
|
removeIdentityKeyForNumber: function(number) {
|
2015-03-24 23:20:36 +00:00
|
|
|
var map = textsecure.storage.get("devices" + number);
|
2015-02-20 22:43:22 +00:00
|
|
|
if (map === undefined)
|
|
|
|
throw new Error("Tried to remove identity for unknown number");
|
2015-03-24 23:20:36 +00:00
|
|
|
textsecure.storage.remove("devices" + number);
|
2015-02-20 22:43:22 +00:00
|
|
|
},
|
|
|
|
|
2015-01-19 19:56:48 +00:00
|
|
|
getDeviceObject: function(encodedNumber, returnIdentityKey) {
|
|
|
|
var number = textsecure.utils.unencodeNumber(encodedNumber)[0];
|
|
|
|
var devices = textsecure.storage.devices.getDeviceObjectsForNumber(number);
|
|
|
|
if (devices.length == 0) {
|
|
|
|
if (returnIdentityKey) {
|
|
|
|
var identityKey = textsecure.storage.devices.getIdentityKeyForNumber(number);
|
|
|
|
if (identityKey !== undefined)
|
|
|
|
return {identityKey: identityKey};
|
|
|
|
}
|
2014-10-29 03:30:35 +00:00
|
|
|
return undefined;
|
2015-01-19 19:56:48 +00:00
|
|
|
}
|
2014-10-29 03:30:35 +00:00
|
|
|
|
|
|
|
for (var i in devices)
|
|
|
|
if (devices[i].encodedNumber == encodedNumber)
|
|
|
|
return devices[i];
|
|
|
|
|
2015-01-19 19:56:48 +00:00
|
|
|
if (returnIdentityKey)
|
|
|
|
return {identityKey: devices[0].identityKey};
|
|
|
|
|
2014-10-29 03:30:35 +00:00
|
|
|
return undefined;
|
|
|
|
},
|
|
|
|
|
|
|
|
removeDeviceIdsForNumber: function(number, deviceIdsToRemove) {
|
2015-03-24 23:20:36 +00:00
|
|
|
var map = textsecure.storage.get("devices" + number);
|
2014-10-29 03:30:35 +00:00
|
|
|
if (map === undefined)
|
|
|
|
throw new Error("Tried to remove device for unknown number");
|
|
|
|
|
|
|
|
var newDevices = [];
|
|
|
|
var devicesRemoved = 0;
|
|
|
|
for (var i in map.devices) {
|
|
|
|
var keep = true;
|
|
|
|
for (var j in deviceIdsToRemove)
|
|
|
|
if (map.devices[i].encodedNumber == number + "." + deviceIdsToRemove[j])
|
|
|
|
keep = false;
|
|
|
|
|
|
|
|
if (keep)
|
|
|
|
newDevices.push(map.devices[i]);
|
|
|
|
else
|
|
|
|
devicesRemoved++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devicesRemoved != deviceIdsToRemove.length)
|
|
|
|
throw new Error("Tried to remove unknown device");
|
2015-01-19 19:57:05 +00:00
|
|
|
|
|
|
|
if (newDevices.length === 0)
|
2015-03-24 23:20:36 +00:00
|
|
|
textsecure.storage.remove("devices" + number);
|
2015-01-19 19:57:05 +00:00
|
|
|
else {
|
|
|
|
map.devices = newDevices;
|
2015-03-24 23:20:36 +00:00
|
|
|
textsecure.storage.put("devices" + number, map);
|
2015-01-19 19:57:05 +00:00
|
|
|
}
|
2014-10-29 03:30:35 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var internalSaveDeviceObject = function(deviceObject, onlyKeys) {
|
2015-01-21 08:47:03 +00:00
|
|
|
if (deviceObject.identityKey === undefined || deviceObject.encodedNumber === undefined)
|
2014-10-29 03:30:35 +00:00
|
|
|
throw new Error("Tried to store invalid deviceObject");
|
|
|
|
|
|
|
|
var number = textsecure.utils.unencodeNumber(deviceObject.encodedNumber)[0];
|
2015-03-24 23:20:36 +00:00
|
|
|
var map = textsecure.storage.get("devices" + number);
|
2014-10-29 03:30:35 +00:00
|
|
|
|
2015-01-21 08:29:23 +00:00
|
|
|
if (deviceObject.sessions !== undefined)
|
|
|
|
deviceObject.sessions = deviceObject.sessions.serialize()
|
|
|
|
|
2014-10-29 03:30:35 +00:00
|
|
|
if (map === undefined)
|
|
|
|
map = { devices: [deviceObject], identityKey: deviceObject.identityKey };
|
|
|
|
else if (map.identityKey != getString(deviceObject.identityKey))
|
|
|
|
throw new Error("Identity key changed");
|
|
|
|
else {
|
|
|
|
var updated = false;
|
|
|
|
for (var i in map.devices) {
|
|
|
|
if (map.devices[i].encodedNumber == deviceObject.encodedNumber) {
|
|
|
|
if (!onlyKeys)
|
|
|
|
map.devices[i] = deviceObject;
|
|
|
|
else {
|
|
|
|
map.devices[i].preKey = deviceObject.preKey;
|
|
|
|
map.devices[i].preKeyId = deviceObject.preKeyId;
|
|
|
|
map.devices[i].signedKey = deviceObject.signedKey;
|
|
|
|
map.devices[i].signedKeyId = deviceObject.signedKeyId;
|
2015-01-19 19:56:48 +00:00
|
|
|
map.devices[i].signedKeySignature = deviceObject.signedKeySignature;
|
2014-10-29 03:30:35 +00:00
|
|
|
map.devices[i].registrationId = deviceObject.registrationId;
|
|
|
|
}
|
|
|
|
updated = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!updated)
|
|
|
|
map.devices.push(deviceObject);
|
|
|
|
}
|
|
|
|
|
2015-03-24 23:20:36 +00:00
|
|
|
textsecure.storage.put("devices" + number, map);
|
2014-10-29 03:30:35 +00:00
|
|
|
};
|
|
|
|
})();
|