Make libtextsecure group storage asynchronous
This commit is contained in:
parent
c26c6fc317
commit
f774047935
5 changed files with 494 additions and 442 deletions
|
@ -38182,110 +38182,124 @@ axolotlInternal.RecipientRecord = function() {
|
||||||
|
|
||||||
window.textsecure.storage.groups = {
|
window.textsecure.storage.groups = {
|
||||||
createNewGroup: function(numbers, groupId) {
|
createNewGroup: function(numbers, groupId) {
|
||||||
if (groupId !== undefined && textsecure.storage.get("group" + groupId) !== undefined)
|
return Promise.resolve(function() {
|
||||||
throw new Error("Tried to recreate group");
|
if (groupId !== undefined && textsecure.storage.get("group" + groupId) !== undefined)
|
||||||
|
throw new Error("Tried to recreate group");
|
||||||
|
|
||||||
while (groupId === undefined || textsecure.storage.get("group" + groupId) !== undefined)
|
while (groupId === undefined || textsecure.storage.get("group" + groupId) !== undefined)
|
||||||
groupId = getString(textsecure.crypto.getRandomBytes(16));
|
groupId = getString(textsecure.crypto.getRandomBytes(16));
|
||||||
|
|
||||||
var me = textsecure.storage.user.getNumber();
|
var me = textsecure.storage.user.getNumber();
|
||||||
var haveMe = false;
|
var haveMe = false;
|
||||||
var finalNumbers = [];
|
var finalNumbers = [];
|
||||||
for (var i in numbers) {
|
for (var i in numbers) {
|
||||||
var number = numbers[i];
|
var number = numbers[i];
|
||||||
if (!textsecure.utils.isNumberSane(number))
|
if (!textsecure.utils.isNumberSane(number))
|
||||||
throw new Error("Invalid number in group");
|
throw new Error("Invalid number in group");
|
||||||
if (number == me)
|
if (number == me)
|
||||||
haveMe = true;
|
haveMe = true;
|
||||||
if (finalNumbers.indexOf(number) < 0)
|
if (finalNumbers.indexOf(number) < 0)
|
||||||
finalNumbers.push(number);
|
finalNumbers.push(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!haveMe)
|
if (!haveMe)
|
||||||
finalNumbers.push(me);
|
finalNumbers.push(me);
|
||||||
|
|
||||||
var groupObject = {numbers: finalNumbers, numberRegistrationIds: {}};
|
var groupObject = {numbers: finalNumbers, numberRegistrationIds: {}};
|
||||||
for (var i in finalNumbers)
|
for (var i in finalNumbers)
|
||||||
groupObject.numberRegistrationIds[finalNumbers[i]] = {};
|
groupObject.numberRegistrationIds[finalNumbers[i]] = {};
|
||||||
|
|
||||||
textsecure.storage.put("group" + groupId, groupObject);
|
textsecure.storage.put("group" + groupId, groupObject);
|
||||||
|
|
||||||
return {id: groupId, numbers: finalNumbers};
|
return {id: groupId, numbers: finalNumbers};
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
getNumbers: function(groupId) {
|
getNumbers: function(groupId) {
|
||||||
var group = textsecure.storage.get("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
if (group === undefined)
|
var group = textsecure.storage.get("group" + groupId);
|
||||||
return undefined;
|
if (group === undefined)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
return group.numbers;
|
return group.numbers;
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
removeNumber: function(groupId, number) {
|
removeNumber: function(groupId, number) {
|
||||||
var group = textsecure.storage.get("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
if (group === undefined)
|
var group = textsecure.storage.get("group" + groupId);
|
||||||
return undefined;
|
if (group === undefined)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
var me = textsecure.storage.user.getNumber();
|
var me = textsecure.storage.user.getNumber();
|
||||||
if (number == me)
|
if (number == me)
|
||||||
throw new Error("Cannot remove ourselves from a group, leave the group instead");
|
throw new Error("Cannot remove ourselves from a group, leave the group instead");
|
||||||
|
|
||||||
var i = group.numbers.indexOf(number);
|
var i = group.numbers.indexOf(number);
|
||||||
if (i > -1) {
|
if (i > -1) {
|
||||||
group.numbers.slice(i, 1);
|
group.numbers.slice(i, 1);
|
||||||
delete group.numberRegistrationIds[number];
|
delete group.numberRegistrationIds[number];
|
||||||
textsecure.storage.put("group" + groupId, group);
|
textsecure.storage.put("group" + groupId, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
return group.numbers;
|
return group.numbers;
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
addNumbers: function(groupId, numbers) {
|
addNumbers: function(groupId, numbers) {
|
||||||
var group = textsecure.storage.get("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
if (group === undefined)
|
var group = textsecure.storage.get("group" + groupId);
|
||||||
return undefined;
|
if (group === undefined)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
for (var i in numbers) {
|
for (var i in numbers) {
|
||||||
var number = numbers[i];
|
var number = numbers[i];
|
||||||
if (!textsecure.utils.isNumberSane(number))
|
if (!textsecure.utils.isNumberSane(number))
|
||||||
throw new Error("Invalid number in set to add to group");
|
throw new Error("Invalid number in set to add to group");
|
||||||
if (group.numbers.indexOf(number) < 0) {
|
if (group.numbers.indexOf(number) < 0) {
|
||||||
group.numbers.push(number);
|
group.numbers.push(number);
|
||||||
group.numberRegistrationIds[number] = {};
|
group.numberRegistrationIds[number] = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
textsecure.storage.put("group" + groupId, group);
|
textsecure.storage.put("group" + groupId, group);
|
||||||
return group.numbers;
|
return group.numbers;
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteGroup: function(groupId) {
|
deleteGroup: function(groupId) {
|
||||||
textsecure.storage.remove("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
|
textsecure.storage.remove("group" + groupId);
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
getGroup: function(groupId) {
|
getGroup: function(groupId) {
|
||||||
var group = textsecure.storage.get("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
if (group === undefined)
|
var group = textsecure.storage.get("group" + groupId);
|
||||||
return undefined;
|
if (group === undefined)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
return { id: groupId, numbers: group.numbers }; //TODO: avatar/name tracking
|
return { id: groupId, numbers: group.numbers }; //TODO: avatar/name tracking
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
needUpdateByDeviceRegistrationId: function(groupId, number, encodedNumber, registrationId) {
|
needUpdateByDeviceRegistrationId: function(groupId, number, encodedNumber, registrationId) {
|
||||||
var group = textsecure.storage.get("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
if (group === undefined)
|
var group = textsecure.storage.get("group" + groupId);
|
||||||
throw new Error("Unknown group for device registration id");
|
if (group === undefined)
|
||||||
|
throw new Error("Unknown group for device registration id");
|
||||||
|
|
||||||
if (group.numberRegistrationIds[number] === undefined)
|
if (group.numberRegistrationIds[number] === undefined)
|
||||||
throw new Error("Unknown number in group for device registration id");
|
throw new Error("Unknown number in group for device registration id");
|
||||||
|
|
||||||
if (group.numberRegistrationIds[number][encodedNumber] == registrationId)
|
if (group.numberRegistrationIds[number][encodedNumber] == registrationId)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var needUpdate = group.numberRegistrationIds[number][encodedNumber] !== undefined;
|
var needUpdate = group.numberRegistrationIds[number][encodedNumber] !== undefined;
|
||||||
group.numberRegistrationIds[number][encodedNumber] = registrationId;
|
group.numberRegistrationIds[number][encodedNumber] = registrationId;
|
||||||
textsecure.storage.put("group" + groupId, group);
|
textsecure.storage.put("group" + groupId, group);
|
||||||
return needUpdate;
|
return needUpdate;
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
@ -38732,65 +38746,66 @@ textsecure.processDecrypted = function(decrypted, source) {
|
||||||
|
|
||||||
if (decrypted.group !== null) {
|
if (decrypted.group !== null) {
|
||||||
decrypted.group.id = getString(decrypted.group.id);
|
decrypted.group.id = getString(decrypted.group.id);
|
||||||
var existingGroup = textsecure.storage.groups.getNumbers(decrypted.group.id);
|
promises.push(textsecure.storage.groups.getNumbers(decrypted.group.id).then(function(existingGroup) {
|
||||||
if (existingGroup === undefined) {
|
if (existingGroup === undefined) {
|
||||||
if (decrypted.group.type != textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE) {
|
if (decrypted.group.type != textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE) {
|
||||||
throw new Error("Got message for unknown group");
|
throw new Error("Got message for unknown group");
|
||||||
}
|
}
|
||||||
textsecure.storage.groups.createNewGroup(decrypted.group.members, decrypted.group.id);
|
if (decrypted.group.avatar !== null) {
|
||||||
if (decrypted.group.avatar !== null) {
|
|
||||||
promises.push(handleAttachment(decrypted.group.avatar));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var fromIndex = existingGroup.indexOf(source);
|
|
||||||
|
|
||||||
if (fromIndex < 0) {
|
|
||||||
//TODO: This could be indication of a race...
|
|
||||||
throw new Error("Sender was not a member of the group they were sending from");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(decrypted.group.type) {
|
|
||||||
case textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE:
|
|
||||||
if (decrypted.group.avatar !== null)
|
|
||||||
promises.push(handleAttachment(decrypted.group.avatar));
|
promises.push(handleAttachment(decrypted.group.avatar));
|
||||||
|
}
|
||||||
|
return textsecure.storage.groups.createNewGroup(decrypted.group.members, decrypted.group.id);
|
||||||
|
} else {
|
||||||
|
var fromIndex = existingGroup.indexOf(source);
|
||||||
|
|
||||||
if (decrypted.group.members.filter(function(number) { return !textsecure.utils.isNumberSane(number); }).length != 0)
|
if (fromIndex < 0) {
|
||||||
throw new Error("Invalid number in new group members");
|
//TODO: This could be indication of a race...
|
||||||
|
throw new Error("Sender was not a member of the group they were sending from");
|
||||||
if (existingGroup.filter(function(number) { decrypted.group.members.indexOf(number) < 0 }).length != 0)
|
|
||||||
throw new Error("Attempted to remove numbers from group with an UPDATE");
|
|
||||||
decrypted.group.added = decrypted.group.members.filter(function(number) { return existingGroup.indexOf(number) < 0; });
|
|
||||||
|
|
||||||
var newGroup = textsecure.storage.groups.addNumbers(decrypted.group.id, decrypted.group.added);
|
|
||||||
if (newGroup.length != decrypted.group.members.length ||
|
|
||||||
newGroup.filter(function(number) { return decrypted.group.members.indexOf(number) < 0; }).length != 0) {
|
|
||||||
throw new Error("Error calculating group member difference");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Also follow this path if avatar + name haven't changed (ie we should start storing those)
|
switch(decrypted.group.type) {
|
||||||
if (decrypted.group.avatar === null && decrypted.group.added.length == 0 && decrypted.group.name === null) {
|
case textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE:
|
||||||
return;
|
if (decrypted.group.avatar !== null)
|
||||||
|
promises.push(handleAttachment(decrypted.group.avatar));
|
||||||
|
|
||||||
|
if (decrypted.group.members.filter(function(number) { return !textsecure.utils.isNumberSane(number); }).length != 0)
|
||||||
|
throw new Error("Invalid number in new group members");
|
||||||
|
|
||||||
|
if (existingGroup.filter(function(number) { decrypted.group.members.indexOf(number) < 0 }).length != 0)
|
||||||
|
throw new Error("Attempted to remove numbers from group with an UPDATE");
|
||||||
|
decrypted.group.added = decrypted.group.members.filter(function(number) { return existingGroup.indexOf(number) < 0; });
|
||||||
|
|
||||||
|
return textsecure.storage.groups.addNumbers(decrypted.group.id, decrypted.group.added).then(function(newGroup) {
|
||||||
|
if (newGroup.length != decrypted.group.members.length ||
|
||||||
|
newGroup.filter(function(number) { return decrypted.group.members.indexOf(number) < 0; }).length != 0) {
|
||||||
|
throw new Error("Error calculating group member difference");
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Also follow this path if avatar + name haven't changed (ie we should start storing those)
|
||||||
|
if (decrypted.group.avatar === null && decrypted.group.added.length == 0 && decrypted.group.name === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted.body = null;
|
||||||
|
decrypted.attachments = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
case textsecure.protobuf.PushMessageContent.GroupContext.Type.QUIT:
|
||||||
|
decrypted.body = null;
|
||||||
|
decrypted.attachments = [];
|
||||||
|
return textsecure.storage.groups.removeNumber(decrypted.group.id, source);
|
||||||
|
case textsecure.protobuf.PushMessageContent.GroupContext.Type.DELIVER:
|
||||||
|
decrypted.group.name = null;
|
||||||
|
decrypted.group.members = [];
|
||||||
|
decrypted.group.avatar = null;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Unknown group message type");
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypted.body = null;
|
|
||||||
decrypted.attachments = [];
|
|
||||||
|
|
||||||
break;
|
|
||||||
case textsecure.protobuf.PushMessageContent.GroupContext.Type.QUIT:
|
|
||||||
textsecure.storage.groups.removeNumber(decrypted.group.id, source);
|
|
||||||
|
|
||||||
decrypted.body = null;
|
|
||||||
decrypted.attachments = [];
|
|
||||||
case textsecure.protobuf.PushMessageContent.GroupContext.Type.DELIVER:
|
|
||||||
decrypted.group.name = null;
|
|
||||||
decrypted.group.members = [];
|
|
||||||
decrypted.group.avatar = null;
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error("Unknown group message type");
|
|
||||||
}
|
}
|
||||||
}
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i in decrypted.attachments) {
|
for (var i in decrypted.attachments) {
|
||||||
|
@ -39339,7 +39354,6 @@ TextSecureServer = function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function createAccount(number, verificationCode, identityKeyPair, single_device) {
|
function createAccount(number, verificationCode, identityKeyPair, single_device) {
|
||||||
textsecure.storage.put('identityKey', identityKeyPair);
|
textsecure.storage.put('identityKey', identityKeyPair);
|
||||||
|
|
||||||
|
@ -39589,34 +39603,37 @@ window.textsecure.messaging = function() {
|
||||||
var doUpdate = false;
|
var doUpdate = false;
|
||||||
Promise.all(devicesForNumber.map(function(device) {
|
Promise.all(devicesForNumber.map(function(device) {
|
||||||
return textsecure.protocol_wrapper.getRegistrationId(device.encodedNumber).then(function(registrationId) {
|
return textsecure.protocol_wrapper.getRegistrationId(device.encodedNumber).then(function(registrationId) {
|
||||||
if (textsecure.storage.groups.needUpdateByDeviceRegistrationId(groupId, number, devicesForNumber[i].encodedNumber, registrationId))
|
return textsecure.storage.groups.needUpdateByDeviceRegistrationId(
|
||||||
doUpdate = true;
|
groupId, number, devicesForNumber[i].encodedNumber, registrationId
|
||||||
|
).then(function(needUpdate) {
|
||||||
|
if (needUpdate) doUpdate = true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})).then(function() {
|
})).then(function() {
|
||||||
if (!doUpdate)
|
if (!doUpdate) return;
|
||||||
return Promise.resolve(true);
|
|
||||||
|
|
||||||
var group = textsecure.storage.groups.getGroup(groupId);
|
return textsecure.storage.groups.getGroup(groupId).then(function(group) {
|
||||||
var numberIndex = group.numbers.indexOf(number);
|
var numberIndex = group.numbers.indexOf(number);
|
||||||
if (numberIndex < 0) // This is potentially a multi-message rare racing-AJAX race
|
if (numberIndex < 0) // This is potentially a multi-message rare racing-AJAX race
|
||||||
return Promise.reject("Tried to refresh group to non-member");
|
return Promise.reject("Tried to refresh group to non-member");
|
||||||
|
|
||||||
var proto = new textsecure.protobuf.PushMessageContent();
|
var proto = new textsecure.protobuf.PushMessageContent();
|
||||||
proto.group = new textsecure.protobuf.PushMessageContent.GroupContext();
|
proto.group = new textsecure.protobuf.PushMessageContent.GroupContext();
|
||||||
|
|
||||||
proto.group.id = toArrayBuffer(group.id);
|
proto.group.id = toArrayBuffer(group.id);
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
proto.group.members = group.numbers;
|
proto.group.members = group.numbers;
|
||||||
proto.group.name = group.name === undefined ? null : group.name;
|
proto.group.name = group.name === undefined ? null : group.name;
|
||||||
|
|
||||||
if (group.avatar !== undefined) {
|
if (group.avatar !== undefined) {
|
||||||
return makeAttachmentPointer(group.avatar).then(function(attachment) {
|
return makeAttachmentPointer(group.avatar).then(function(attachment) {
|
||||||
proto.group.avatar = attachment;
|
proto.group.avatar = attachment;
|
||||||
|
return sendMessageToDevices(Date.now(), number, devicesForNumber, proto);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
return sendMessageToDevices(Date.now(), number, devicesForNumber, proto);
|
return sendMessageToDevices(Date.now(), number, devicesForNumber, proto);
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
return sendMessageToDevices(Date.now(), number, devicesForNumber, proto);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39821,16 +39838,17 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.id = toArrayBuffer(groupId);
|
proto.group.id = toArrayBuffer(groupId);
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.DELIVER;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.DELIVER;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.getNumbers(groupId);
|
return textsecure.storage.groups.getNumbers(groupId).then(function(numbers) {
|
||||||
if (numbers === undefined)
|
if (numbers === undefined)
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
|
|
||||||
var promises = [];
|
var promises = [];
|
||||||
for (var i in attachments)
|
for (var i in attachments)
|
||||||
promises.push(makeAttachmentPointer(attachments[i]));
|
promises.push(makeAttachmentPointer(attachments[i]));
|
||||||
return Promise.all(promises).then(function(attachmentsArray) {
|
return Promise.all(promises).then(function(attachmentsArray) {
|
||||||
proto.attachments = attachmentsArray;
|
proto.attachments = attachmentsArray;
|
||||||
return sendGroupProto(numbers, proto, timestamp);
|
return sendGroupProto(numbers, proto, timestamp);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39838,26 +39856,27 @@ window.textsecure.messaging = function() {
|
||||||
var proto = new textsecure.protobuf.PushMessageContent();
|
var proto = new textsecure.protobuf.PushMessageContent();
|
||||||
proto.group = new textsecure.protobuf.PushMessageContent.GroupContext();
|
proto.group = new textsecure.protobuf.PushMessageContent.GroupContext();
|
||||||
|
|
||||||
var group = textsecure.storage.groups.createNewGroup(numbers);
|
return textsecure.storage.groups.createNewGroup(numbers).then(function(group) {
|
||||||
proto.group.id = toArrayBuffer(group.id);
|
proto.group.id = toArrayBuffer(group.id);
|
||||||
var numbers = group.numbers;
|
var numbers = group.numbers;
|
||||||
|
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
proto.group.members = numbers;
|
proto.group.members = numbers;
|
||||||
proto.group.name = name;
|
proto.group.name = name;
|
||||||
|
|
||||||
if (avatar !== undefined) {
|
if (avatar !== undefined) {
|
||||||
return makeAttachmentPointer(avatar).then(function(attachment) {
|
return makeAttachmentPointer(avatar).then(function(attachment) {
|
||||||
proto.group.avatar = attachment;
|
proto.group.avatar = attachment;
|
||||||
|
return sendGroupProto(numbers, proto).then(function() {
|
||||||
|
return proto.group.id;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
return sendGroupProto(numbers, proto).then(function() {
|
return sendGroupProto(numbers, proto).then(function() {
|
||||||
return proto.group.id;
|
return proto.group.id;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
return sendGroupProto(numbers, proto).then(function() {
|
|
||||||
return proto.group.id;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.updateGroup = function(groupId, name, avatar, numbers) {
|
self.updateGroup = function(groupId, name, avatar, numbers) {
|
||||||
|
@ -39868,24 +39887,25 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
proto.group.name = name;
|
proto.group.name = name;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.addNumbers(groupId, numbers);
|
return textsecure.storage.groups.addNumbers(groupId, numbers).then(function(numbers) {
|
||||||
if (numbers === undefined) {
|
if (numbers === undefined) {
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
}
|
}
|
||||||
proto.group.members = numbers;
|
proto.group.members = numbers;
|
||||||
|
|
||||||
if (avatar !== undefined) {
|
if (avatar !== undefined) {
|
||||||
return makeAttachmentPointer(avatar).then(function(attachment) {
|
return makeAttachmentPointer(avatar).then(function(attachment) {
|
||||||
proto.group.avatar = attachment;
|
proto.group.avatar = attachment;
|
||||||
|
return sendGroupProto(numbers, proto).then(function() {
|
||||||
|
return proto.group.id;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
return sendGroupProto(numbers, proto).then(function() {
|
return sendGroupProto(numbers, proto).then(function() {
|
||||||
return proto.group.id;
|
return proto.group.id;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
return sendGroupProto(numbers, proto).then(function() {
|
|
||||||
return proto.group.id;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.addNumberToGroup = function(groupId, number) {
|
self.addNumberToGroup = function(groupId, number) {
|
||||||
|
@ -39894,12 +39914,13 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.id = toArrayBuffer(groupId);
|
proto.group.id = toArrayBuffer(groupId);
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.addNumbers(groupId, [number]);
|
return textsecure.storage.groups.addNumbers(groupId, [number]).then(function(numbers) {
|
||||||
if (numbers === undefined)
|
if (numbers === undefined)
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
proto.group.members = numbers;
|
proto.group.members = numbers;
|
||||||
|
|
||||||
return sendGroupProto(numbers, proto);
|
return sendGroupProto(numbers, proto);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.setGroupName = function(groupId, name) {
|
self.setGroupName = function(groupId, name) {
|
||||||
|
@ -39909,12 +39930,13 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
proto.group.name = name;
|
proto.group.name = name;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.getNumbers(groupId);
|
return textsecure.storage.groups.getNumbers(groupId).then(function(numbers) {
|
||||||
if (numbers === undefined)
|
if (numbers === undefined)
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
proto.group.members = numbers;
|
proto.group.members = numbers;
|
||||||
|
|
||||||
return sendGroupProto(numbers, proto);
|
return sendGroupProto(numbers, proto);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.setGroupAvatar = function(groupId, avatar) {
|
self.setGroupAvatar = function(groupId, avatar) {
|
||||||
|
@ -39923,14 +39945,15 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.id = toArrayBuffer(groupId);
|
proto.group.id = toArrayBuffer(groupId);
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.getNumbers(groupId);
|
return textsecure.storage.groups.getNumbers(groupId).then(function(numbers) {
|
||||||
if (numbers === undefined)
|
if (numbers === undefined)
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
proto.group.members = numbers;
|
proto.group.members = numbers;
|
||||||
|
|
||||||
return makeAttachmentPointer(avatar).then(function(attachment) {
|
return makeAttachmentPointer(avatar).then(function(attachment) {
|
||||||
proto.group.avatar = attachment;
|
proto.group.avatar = attachment;
|
||||||
return sendGroupProto(numbers, proto);
|
return sendGroupProto(numbers, proto);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39940,12 +39963,13 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.id = toArrayBuffer(groupId);
|
proto.group.id = toArrayBuffer(groupId);
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.QUIT;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.QUIT;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.getNumbers(groupId);
|
return textsecure.storage.groups.getNumbers(groupId).then(function(numbers) {
|
||||||
if (numbers === undefined)
|
if (numbers === undefined)
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
textsecure.storage.groups.deleteGroup(groupId);
|
return textsecure.storage.groups.deleteGroup(groupId).then(function() {
|
||||||
|
return sendGroupProto(numbers, proto);
|
||||||
return sendGroupProto(numbers, proto);
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
|
|
@ -114,40 +114,43 @@
|
||||||
|
|
||||||
return this.avatarInput.getFile().then(function(avatarFile) {
|
return this.avatarInput.getFile().then(function(avatarFile) {
|
||||||
var members = this.getRecipients().pluck('id');
|
var members = this.getRecipients().pluck('id');
|
||||||
var groupId = textsecure.storage.groups.createNewGroup(members).id;
|
textsecure.storage.groups.createNewGroup(members).then(function(group) {
|
||||||
var attributes = {
|
return group.id;
|
||||||
id: groupId,
|
}).then(function(groupId) {
|
||||||
groupId: groupId,
|
var attributes = {
|
||||||
type: 'group',
|
id: groupId,
|
||||||
name: name,
|
groupId: groupId,
|
||||||
avatar: avatarFile,
|
type: 'group',
|
||||||
members: members
|
name: name,
|
||||||
};
|
avatar: avatarFile,
|
||||||
var group = new Whisper.Conversation(attributes);
|
members: members
|
||||||
group.save().then(function() {
|
};
|
||||||
this.trigger('open', {modelId: groupId});
|
var group = new Whisper.Conversation(attributes);
|
||||||
|
group.save().then(function() {
|
||||||
|
this.trigger('open', {modelId: groupId});
|
||||||
|
}.bind(this));
|
||||||
|
var now = Date.now();
|
||||||
|
var message = group.messageCollection.add({
|
||||||
|
conversationId : group.id,
|
||||||
|
type : 'outgoing',
|
||||||
|
sent_at : now,
|
||||||
|
received_at : now,
|
||||||
|
group_update : {
|
||||||
|
name: group.get('name'),
|
||||||
|
avatar: group.get('avatar'),
|
||||||
|
joined: group.get('members')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
message.save();
|
||||||
|
textsecure.messaging.updateGroup(
|
||||||
|
group.id,
|
||||||
|
group.get('name'),
|
||||||
|
group.get('avatar'),
|
||||||
|
group.get('members')
|
||||||
|
).catch(function(errors) {
|
||||||
|
message.save({errors: errors.map(function(e){return e.error;})});
|
||||||
|
});
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
var now = Date.now();
|
|
||||||
var message = group.messageCollection.add({
|
|
||||||
conversationId : group.id,
|
|
||||||
type : 'outgoing',
|
|
||||||
sent_at : now,
|
|
||||||
received_at : now,
|
|
||||||
group_update : {
|
|
||||||
name: group.get('name'),
|
|
||||||
avatar: group.get('avatar'),
|
|
||||||
joined: group.get('members')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
message.save();
|
|
||||||
textsecure.messaging.updateGroup(
|
|
||||||
group.id,
|
|
||||||
group.get('name'),
|
|
||||||
group.get('avatar'),
|
|
||||||
group.get('members')
|
|
||||||
).catch(function(errors) {
|
|
||||||
message.save({errors: errors.map(function(e){return e.error;})});
|
|
||||||
});
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -179,65 +179,66 @@ textsecure.processDecrypted = function(decrypted, source) {
|
||||||
|
|
||||||
if (decrypted.group !== null) {
|
if (decrypted.group !== null) {
|
||||||
decrypted.group.id = getString(decrypted.group.id);
|
decrypted.group.id = getString(decrypted.group.id);
|
||||||
var existingGroup = textsecure.storage.groups.getNumbers(decrypted.group.id);
|
promises.push(textsecure.storage.groups.getNumbers(decrypted.group.id).then(function(existingGroup) {
|
||||||
if (existingGroup === undefined) {
|
if (existingGroup === undefined) {
|
||||||
if (decrypted.group.type != textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE) {
|
if (decrypted.group.type != textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE) {
|
||||||
throw new Error("Got message for unknown group");
|
throw new Error("Got message for unknown group");
|
||||||
}
|
}
|
||||||
textsecure.storage.groups.createNewGroup(decrypted.group.members, decrypted.group.id);
|
if (decrypted.group.avatar !== null) {
|
||||||
if (decrypted.group.avatar !== null) {
|
|
||||||
promises.push(handleAttachment(decrypted.group.avatar));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var fromIndex = existingGroup.indexOf(source);
|
|
||||||
|
|
||||||
if (fromIndex < 0) {
|
|
||||||
//TODO: This could be indication of a race...
|
|
||||||
throw new Error("Sender was not a member of the group they were sending from");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(decrypted.group.type) {
|
|
||||||
case textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE:
|
|
||||||
if (decrypted.group.avatar !== null)
|
|
||||||
promises.push(handleAttachment(decrypted.group.avatar));
|
promises.push(handleAttachment(decrypted.group.avatar));
|
||||||
|
}
|
||||||
|
return textsecure.storage.groups.createNewGroup(decrypted.group.members, decrypted.group.id);
|
||||||
|
} else {
|
||||||
|
var fromIndex = existingGroup.indexOf(source);
|
||||||
|
|
||||||
if (decrypted.group.members.filter(function(number) { return !textsecure.utils.isNumberSane(number); }).length != 0)
|
if (fromIndex < 0) {
|
||||||
throw new Error("Invalid number in new group members");
|
//TODO: This could be indication of a race...
|
||||||
|
throw new Error("Sender was not a member of the group they were sending from");
|
||||||
if (existingGroup.filter(function(number) { decrypted.group.members.indexOf(number) < 0 }).length != 0)
|
|
||||||
throw new Error("Attempted to remove numbers from group with an UPDATE");
|
|
||||||
decrypted.group.added = decrypted.group.members.filter(function(number) { return existingGroup.indexOf(number) < 0; });
|
|
||||||
|
|
||||||
var newGroup = textsecure.storage.groups.addNumbers(decrypted.group.id, decrypted.group.added);
|
|
||||||
if (newGroup.length != decrypted.group.members.length ||
|
|
||||||
newGroup.filter(function(number) { return decrypted.group.members.indexOf(number) < 0; }).length != 0) {
|
|
||||||
throw new Error("Error calculating group member difference");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Also follow this path if avatar + name haven't changed (ie we should start storing those)
|
switch(decrypted.group.type) {
|
||||||
if (decrypted.group.avatar === null && decrypted.group.added.length == 0 && decrypted.group.name === null) {
|
case textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE:
|
||||||
return;
|
if (decrypted.group.avatar !== null)
|
||||||
|
promises.push(handleAttachment(decrypted.group.avatar));
|
||||||
|
|
||||||
|
if (decrypted.group.members.filter(function(number) { return !textsecure.utils.isNumberSane(number); }).length != 0)
|
||||||
|
throw new Error("Invalid number in new group members");
|
||||||
|
|
||||||
|
if (existingGroup.filter(function(number) { decrypted.group.members.indexOf(number) < 0 }).length != 0)
|
||||||
|
throw new Error("Attempted to remove numbers from group with an UPDATE");
|
||||||
|
decrypted.group.added = decrypted.group.members.filter(function(number) { return existingGroup.indexOf(number) < 0; });
|
||||||
|
|
||||||
|
return textsecure.storage.groups.addNumbers(decrypted.group.id, decrypted.group.added).then(function(newGroup) {
|
||||||
|
if (newGroup.length != decrypted.group.members.length ||
|
||||||
|
newGroup.filter(function(number) { return decrypted.group.members.indexOf(number) < 0; }).length != 0) {
|
||||||
|
throw new Error("Error calculating group member difference");
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Also follow this path if avatar + name haven't changed (ie we should start storing those)
|
||||||
|
if (decrypted.group.avatar === null && decrypted.group.added.length == 0 && decrypted.group.name === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted.body = null;
|
||||||
|
decrypted.attachments = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
case textsecure.protobuf.PushMessageContent.GroupContext.Type.QUIT:
|
||||||
|
decrypted.body = null;
|
||||||
|
decrypted.attachments = [];
|
||||||
|
return textsecure.storage.groups.removeNumber(decrypted.group.id, source);
|
||||||
|
case textsecure.protobuf.PushMessageContent.GroupContext.Type.DELIVER:
|
||||||
|
decrypted.group.name = null;
|
||||||
|
decrypted.group.members = [];
|
||||||
|
decrypted.group.avatar = null;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Unknown group message type");
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypted.body = null;
|
|
||||||
decrypted.attachments = [];
|
|
||||||
|
|
||||||
break;
|
|
||||||
case textsecure.protobuf.PushMessageContent.GroupContext.Type.QUIT:
|
|
||||||
textsecure.storage.groups.removeNumber(decrypted.group.id, source);
|
|
||||||
|
|
||||||
decrypted.body = null;
|
|
||||||
decrypted.attachments = [];
|
|
||||||
case textsecure.protobuf.PushMessageContent.GroupContext.Type.DELIVER:
|
|
||||||
decrypted.group.name = null;
|
|
||||||
decrypted.group.members = [];
|
|
||||||
decrypted.group.avatar = null;
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error("Unknown group message type");
|
|
||||||
}
|
}
|
||||||
}
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i in decrypted.attachments) {
|
for (var i in decrypted.attachments) {
|
||||||
|
|
|
@ -99,34 +99,37 @@ window.textsecure.messaging = function() {
|
||||||
var doUpdate = false;
|
var doUpdate = false;
|
||||||
Promise.all(devicesForNumber.map(function(device) {
|
Promise.all(devicesForNumber.map(function(device) {
|
||||||
return textsecure.protocol_wrapper.getRegistrationId(device.encodedNumber).then(function(registrationId) {
|
return textsecure.protocol_wrapper.getRegistrationId(device.encodedNumber).then(function(registrationId) {
|
||||||
if (textsecure.storage.groups.needUpdateByDeviceRegistrationId(groupId, number, devicesForNumber[i].encodedNumber, registrationId))
|
return textsecure.storage.groups.needUpdateByDeviceRegistrationId(
|
||||||
doUpdate = true;
|
groupId, number, devicesForNumber[i].encodedNumber, registrationId
|
||||||
|
).then(function(needUpdate) {
|
||||||
|
if (needUpdate) doUpdate = true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})).then(function() {
|
})).then(function() {
|
||||||
if (!doUpdate)
|
if (!doUpdate) return;
|
||||||
return Promise.resolve(true);
|
|
||||||
|
|
||||||
var group = textsecure.storage.groups.getGroup(groupId);
|
return textsecure.storage.groups.getGroup(groupId).then(function(group) {
|
||||||
var numberIndex = group.numbers.indexOf(number);
|
var numberIndex = group.numbers.indexOf(number);
|
||||||
if (numberIndex < 0) // This is potentially a multi-message rare racing-AJAX race
|
if (numberIndex < 0) // This is potentially a multi-message rare racing-AJAX race
|
||||||
return Promise.reject("Tried to refresh group to non-member");
|
return Promise.reject("Tried to refresh group to non-member");
|
||||||
|
|
||||||
var proto = new textsecure.protobuf.PushMessageContent();
|
var proto = new textsecure.protobuf.PushMessageContent();
|
||||||
proto.group = new textsecure.protobuf.PushMessageContent.GroupContext();
|
proto.group = new textsecure.protobuf.PushMessageContent.GroupContext();
|
||||||
|
|
||||||
proto.group.id = toArrayBuffer(group.id);
|
proto.group.id = toArrayBuffer(group.id);
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
proto.group.members = group.numbers;
|
proto.group.members = group.numbers;
|
||||||
proto.group.name = group.name === undefined ? null : group.name;
|
proto.group.name = group.name === undefined ? null : group.name;
|
||||||
|
|
||||||
if (group.avatar !== undefined) {
|
if (group.avatar !== undefined) {
|
||||||
return makeAttachmentPointer(group.avatar).then(function(attachment) {
|
return makeAttachmentPointer(group.avatar).then(function(attachment) {
|
||||||
proto.group.avatar = attachment;
|
proto.group.avatar = attachment;
|
||||||
|
return sendMessageToDevices(Date.now(), number, devicesForNumber, proto);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
return sendMessageToDevices(Date.now(), number, devicesForNumber, proto);
|
return sendMessageToDevices(Date.now(), number, devicesForNumber, proto);
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
return sendMessageToDevices(Date.now(), number, devicesForNumber, proto);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,16 +334,17 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.id = toArrayBuffer(groupId);
|
proto.group.id = toArrayBuffer(groupId);
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.DELIVER;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.DELIVER;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.getNumbers(groupId);
|
return textsecure.storage.groups.getNumbers(groupId).then(function(numbers) {
|
||||||
if (numbers === undefined)
|
if (numbers === undefined)
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
|
|
||||||
var promises = [];
|
var promises = [];
|
||||||
for (var i in attachments)
|
for (var i in attachments)
|
||||||
promises.push(makeAttachmentPointer(attachments[i]));
|
promises.push(makeAttachmentPointer(attachments[i]));
|
||||||
return Promise.all(promises).then(function(attachmentsArray) {
|
return Promise.all(promises).then(function(attachmentsArray) {
|
||||||
proto.attachments = attachmentsArray;
|
proto.attachments = attachmentsArray;
|
||||||
return sendGroupProto(numbers, proto, timestamp);
|
return sendGroupProto(numbers, proto, timestamp);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,26 +352,27 @@ window.textsecure.messaging = function() {
|
||||||
var proto = new textsecure.protobuf.PushMessageContent();
|
var proto = new textsecure.protobuf.PushMessageContent();
|
||||||
proto.group = new textsecure.protobuf.PushMessageContent.GroupContext();
|
proto.group = new textsecure.protobuf.PushMessageContent.GroupContext();
|
||||||
|
|
||||||
var group = textsecure.storage.groups.createNewGroup(numbers);
|
return textsecure.storage.groups.createNewGroup(numbers).then(function(group) {
|
||||||
proto.group.id = toArrayBuffer(group.id);
|
proto.group.id = toArrayBuffer(group.id);
|
||||||
var numbers = group.numbers;
|
var numbers = group.numbers;
|
||||||
|
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
proto.group.members = numbers;
|
proto.group.members = numbers;
|
||||||
proto.group.name = name;
|
proto.group.name = name;
|
||||||
|
|
||||||
if (avatar !== undefined) {
|
if (avatar !== undefined) {
|
||||||
return makeAttachmentPointer(avatar).then(function(attachment) {
|
return makeAttachmentPointer(avatar).then(function(attachment) {
|
||||||
proto.group.avatar = attachment;
|
proto.group.avatar = attachment;
|
||||||
|
return sendGroupProto(numbers, proto).then(function() {
|
||||||
|
return proto.group.id;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
return sendGroupProto(numbers, proto).then(function() {
|
return sendGroupProto(numbers, proto).then(function() {
|
||||||
return proto.group.id;
|
return proto.group.id;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
return sendGroupProto(numbers, proto).then(function() {
|
|
||||||
return proto.group.id;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.updateGroup = function(groupId, name, avatar, numbers) {
|
self.updateGroup = function(groupId, name, avatar, numbers) {
|
||||||
|
@ -378,24 +383,25 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
proto.group.name = name;
|
proto.group.name = name;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.addNumbers(groupId, numbers);
|
return textsecure.storage.groups.addNumbers(groupId, numbers).then(function(numbers) {
|
||||||
if (numbers === undefined) {
|
if (numbers === undefined) {
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
}
|
}
|
||||||
proto.group.members = numbers;
|
proto.group.members = numbers;
|
||||||
|
|
||||||
if (avatar !== undefined) {
|
if (avatar !== undefined) {
|
||||||
return makeAttachmentPointer(avatar).then(function(attachment) {
|
return makeAttachmentPointer(avatar).then(function(attachment) {
|
||||||
proto.group.avatar = attachment;
|
proto.group.avatar = attachment;
|
||||||
|
return sendGroupProto(numbers, proto).then(function() {
|
||||||
|
return proto.group.id;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
return sendGroupProto(numbers, proto).then(function() {
|
return sendGroupProto(numbers, proto).then(function() {
|
||||||
return proto.group.id;
|
return proto.group.id;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
return sendGroupProto(numbers, proto).then(function() {
|
|
||||||
return proto.group.id;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.addNumberToGroup = function(groupId, number) {
|
self.addNumberToGroup = function(groupId, number) {
|
||||||
|
@ -404,12 +410,13 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.id = toArrayBuffer(groupId);
|
proto.group.id = toArrayBuffer(groupId);
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.addNumbers(groupId, [number]);
|
return textsecure.storage.groups.addNumbers(groupId, [number]).then(function(numbers) {
|
||||||
if (numbers === undefined)
|
if (numbers === undefined)
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
proto.group.members = numbers;
|
proto.group.members = numbers;
|
||||||
|
|
||||||
return sendGroupProto(numbers, proto);
|
return sendGroupProto(numbers, proto);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.setGroupName = function(groupId, name) {
|
self.setGroupName = function(groupId, name) {
|
||||||
|
@ -419,12 +426,13 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
proto.group.name = name;
|
proto.group.name = name;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.getNumbers(groupId);
|
return textsecure.storage.groups.getNumbers(groupId).then(function(numbers) {
|
||||||
if (numbers === undefined)
|
if (numbers === undefined)
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
proto.group.members = numbers;
|
proto.group.members = numbers;
|
||||||
|
|
||||||
return sendGroupProto(numbers, proto);
|
return sendGroupProto(numbers, proto);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.setGroupAvatar = function(groupId, avatar) {
|
self.setGroupAvatar = function(groupId, avatar) {
|
||||||
|
@ -433,14 +441,15 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.id = toArrayBuffer(groupId);
|
proto.group.id = toArrayBuffer(groupId);
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.UPDATE;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.getNumbers(groupId);
|
return textsecure.storage.groups.getNumbers(groupId).then(function(numbers) {
|
||||||
if (numbers === undefined)
|
if (numbers === undefined)
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
proto.group.members = numbers;
|
proto.group.members = numbers;
|
||||||
|
|
||||||
return makeAttachmentPointer(avatar).then(function(attachment) {
|
return makeAttachmentPointer(avatar).then(function(attachment) {
|
||||||
proto.group.avatar = attachment;
|
proto.group.avatar = attachment;
|
||||||
return sendGroupProto(numbers, proto);
|
return sendGroupProto(numbers, proto);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,12 +459,13 @@ window.textsecure.messaging = function() {
|
||||||
proto.group.id = toArrayBuffer(groupId);
|
proto.group.id = toArrayBuffer(groupId);
|
||||||
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.QUIT;
|
proto.group.type = textsecure.protobuf.PushMessageContent.GroupContext.Type.QUIT;
|
||||||
|
|
||||||
var numbers = textsecure.storage.groups.getNumbers(groupId);
|
return textsecure.storage.groups.getNumbers(groupId).then(function(numbers) {
|
||||||
if (numbers === undefined)
|
if (numbers === undefined)
|
||||||
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
return new Promise(function(resolve, reject) { reject(new Error("Unknown Group")); });
|
||||||
textsecure.storage.groups.deleteGroup(groupId);
|
return textsecure.storage.groups.deleteGroup(groupId).then(function() {
|
||||||
|
return sendGroupProto(numbers, proto);
|
||||||
return sendGroupProto(numbers, proto);
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
|
|
@ -25,110 +25,124 @@
|
||||||
|
|
||||||
window.textsecure.storage.groups = {
|
window.textsecure.storage.groups = {
|
||||||
createNewGroup: function(numbers, groupId) {
|
createNewGroup: function(numbers, groupId) {
|
||||||
if (groupId !== undefined && textsecure.storage.get("group" + groupId) !== undefined)
|
return Promise.resolve(function() {
|
||||||
throw new Error("Tried to recreate group");
|
if (groupId !== undefined && textsecure.storage.get("group" + groupId) !== undefined)
|
||||||
|
throw new Error("Tried to recreate group");
|
||||||
|
|
||||||
while (groupId === undefined || textsecure.storage.get("group" + groupId) !== undefined)
|
while (groupId === undefined || textsecure.storage.get("group" + groupId) !== undefined)
|
||||||
groupId = getString(textsecure.crypto.getRandomBytes(16));
|
groupId = getString(textsecure.crypto.getRandomBytes(16));
|
||||||
|
|
||||||
var me = textsecure.storage.user.getNumber();
|
var me = textsecure.storage.user.getNumber();
|
||||||
var haveMe = false;
|
var haveMe = false;
|
||||||
var finalNumbers = [];
|
var finalNumbers = [];
|
||||||
for (var i in numbers) {
|
for (var i in numbers) {
|
||||||
var number = numbers[i];
|
var number = numbers[i];
|
||||||
if (!textsecure.utils.isNumberSane(number))
|
if (!textsecure.utils.isNumberSane(number))
|
||||||
throw new Error("Invalid number in group");
|
throw new Error("Invalid number in group");
|
||||||
if (number == me)
|
if (number == me)
|
||||||
haveMe = true;
|
haveMe = true;
|
||||||
if (finalNumbers.indexOf(number) < 0)
|
if (finalNumbers.indexOf(number) < 0)
|
||||||
finalNumbers.push(number);
|
finalNumbers.push(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!haveMe)
|
if (!haveMe)
|
||||||
finalNumbers.push(me);
|
finalNumbers.push(me);
|
||||||
|
|
||||||
var groupObject = {numbers: finalNumbers, numberRegistrationIds: {}};
|
var groupObject = {numbers: finalNumbers, numberRegistrationIds: {}};
|
||||||
for (var i in finalNumbers)
|
for (var i in finalNumbers)
|
||||||
groupObject.numberRegistrationIds[finalNumbers[i]] = {};
|
groupObject.numberRegistrationIds[finalNumbers[i]] = {};
|
||||||
|
|
||||||
textsecure.storage.put("group" + groupId, groupObject);
|
textsecure.storage.put("group" + groupId, groupObject);
|
||||||
|
|
||||||
return {id: groupId, numbers: finalNumbers};
|
return {id: groupId, numbers: finalNumbers};
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
getNumbers: function(groupId) {
|
getNumbers: function(groupId) {
|
||||||
var group = textsecure.storage.get("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
if (group === undefined)
|
var group = textsecure.storage.get("group" + groupId);
|
||||||
return undefined;
|
if (group === undefined)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
return group.numbers;
|
return group.numbers;
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
removeNumber: function(groupId, number) {
|
removeNumber: function(groupId, number) {
|
||||||
var group = textsecure.storage.get("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
if (group === undefined)
|
var group = textsecure.storage.get("group" + groupId);
|
||||||
return undefined;
|
if (group === undefined)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
var me = textsecure.storage.user.getNumber();
|
var me = textsecure.storage.user.getNumber();
|
||||||
if (number == me)
|
if (number == me)
|
||||||
throw new Error("Cannot remove ourselves from a group, leave the group instead");
|
throw new Error("Cannot remove ourselves from a group, leave the group instead");
|
||||||
|
|
||||||
var i = group.numbers.indexOf(number);
|
var i = group.numbers.indexOf(number);
|
||||||
if (i > -1) {
|
if (i > -1) {
|
||||||
group.numbers.slice(i, 1);
|
group.numbers.slice(i, 1);
|
||||||
delete group.numberRegistrationIds[number];
|
delete group.numberRegistrationIds[number];
|
||||||
textsecure.storage.put("group" + groupId, group);
|
textsecure.storage.put("group" + groupId, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
return group.numbers;
|
return group.numbers;
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
addNumbers: function(groupId, numbers) {
|
addNumbers: function(groupId, numbers) {
|
||||||
var group = textsecure.storage.get("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
if (group === undefined)
|
var group = textsecure.storage.get("group" + groupId);
|
||||||
return undefined;
|
if (group === undefined)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
for (var i in numbers) {
|
for (var i in numbers) {
|
||||||
var number = numbers[i];
|
var number = numbers[i];
|
||||||
if (!textsecure.utils.isNumberSane(number))
|
if (!textsecure.utils.isNumberSane(number))
|
||||||
throw new Error("Invalid number in set to add to group");
|
throw new Error("Invalid number in set to add to group");
|
||||||
if (group.numbers.indexOf(number) < 0) {
|
if (group.numbers.indexOf(number) < 0) {
|
||||||
group.numbers.push(number);
|
group.numbers.push(number);
|
||||||
group.numberRegistrationIds[number] = {};
|
group.numberRegistrationIds[number] = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
textsecure.storage.put("group" + groupId, group);
|
textsecure.storage.put("group" + groupId, group);
|
||||||
return group.numbers;
|
return group.numbers;
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteGroup: function(groupId) {
|
deleteGroup: function(groupId) {
|
||||||
textsecure.storage.remove("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
|
textsecure.storage.remove("group" + groupId);
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
getGroup: function(groupId) {
|
getGroup: function(groupId) {
|
||||||
var group = textsecure.storage.get("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
if (group === undefined)
|
var group = textsecure.storage.get("group" + groupId);
|
||||||
return undefined;
|
if (group === undefined)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
return { id: groupId, numbers: group.numbers }; //TODO: avatar/name tracking
|
return { id: groupId, numbers: group.numbers }; //TODO: avatar/name tracking
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
|
|
||||||
needUpdateByDeviceRegistrationId: function(groupId, number, encodedNumber, registrationId) {
|
needUpdateByDeviceRegistrationId: function(groupId, number, encodedNumber, registrationId) {
|
||||||
var group = textsecure.storage.get("group" + groupId);
|
return Promise.resolve(function() {
|
||||||
if (group === undefined)
|
var group = textsecure.storage.get("group" + groupId);
|
||||||
throw new Error("Unknown group for device registration id");
|
if (group === undefined)
|
||||||
|
throw new Error("Unknown group for device registration id");
|
||||||
|
|
||||||
if (group.numberRegistrationIds[number] === undefined)
|
if (group.numberRegistrationIds[number] === undefined)
|
||||||
throw new Error("Unknown number in group for device registration id");
|
throw new Error("Unknown number in group for device registration id");
|
||||||
|
|
||||||
if (group.numberRegistrationIds[number][encodedNumber] == registrationId)
|
if (group.numberRegistrationIds[number][encodedNumber] == registrationId)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var needUpdate = group.numberRegistrationIds[number][encodedNumber] !== undefined;
|
var needUpdate = group.numberRegistrationIds[number][encodedNumber] !== undefined;
|
||||||
group.numberRegistrationIds[number][encodedNumber] = registrationId;
|
group.numberRegistrationIds[number][encodedNumber] = registrationId;
|
||||||
textsecure.storage.put("group" + groupId, group);
|
textsecure.storage.put("group" + groupId, group);
|
||||||
return needUpdate;
|
return needUpdate;
|
||||||
|
}());
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue