(function() { 'use strict'; /********************* *** Group Storage *** *********************/ window.textsecure = window.textsecure || {}; window.textsecure.storage = window.textsecure.storage || {}; // create a random group id that we haven't seen before. function generateNewGroupId() { var groupId = getString(libsignal.crypto.getRandomBytes(16)); return textsecure.storage.protocol.getGroup(groupId).then(function(group) { if (group === undefined) { return groupId; } else { console.warn('group id collision'); // probably a bad sign. return generateNewGroupId(); } }); } window.textsecure.storage.groups = { createNewGroup: function(numbers, groupId) { var groupId = groupId; return new Promise(function(resolve) { if (groupId !== undefined) { resolve( textsecure.storage.protocol.getGroup(groupId).then(function(group) { if (group !== undefined) { throw new Error('Tried to recreate group'); } }) ); } else { resolve( generateNewGroupId().then(function(newGroupId) { groupId = newGroupId; }) ); } }).then(function() { var me = textsecure.storage.user.getNumber(); var haveMe = false; var finalNumbers = []; for (var i in numbers) { var number = numbers[i]; if (!textsecure.utils.isNumberSane(number)) throw new Error('Invalid number in group'); if (number == me) haveMe = true; if (finalNumbers.indexOf(number) < 0) finalNumbers.push(number); } if (!haveMe) finalNumbers.push(me); var groupObject = { numbers: finalNumbers, numberRegistrationIds: {} }; for (var i in finalNumbers) groupObject.numberRegistrationIds[finalNumbers[i]] = {}; return textsecure.storage.protocol .putGroup(groupId, groupObject) .then(function() { return { id: groupId, numbers: finalNumbers }; }); }); }, getNumbers: function(groupId) { return textsecure.storage.protocol .getGroup(groupId) .then(function(group) { if (group === undefined) return undefined; return group.numbers; }); }, removeNumber: function(groupId, number) { return textsecure.storage.protocol .getGroup(groupId) .then(function(group) { if (group === undefined) return undefined; var me = textsecure.storage.user.getNumber(); if (number == me) throw new Error( 'Cannot remove ourselves from a group, leave the group instead' ); var i = group.numbers.indexOf(number); if (i > -1) { group.numbers.splice(i, 1); delete group.numberRegistrationIds[number]; return textsecure.storage.protocol .putGroup(groupId, group) .then(function() { return group.numbers; }); } return group.numbers; }); }, addNumbers: function(groupId, numbers) { return textsecure.storage.protocol .getGroup(groupId) .then(function(group) { if (group === undefined) return undefined; for (var i in numbers) { var number = numbers[i]; if (!textsecure.utils.isNumberSane(number)) throw new Error('Invalid number in set to add to group'); if (group.numbers.indexOf(number) < 0) { group.numbers.push(number); group.numberRegistrationIds[number] = {}; } } return textsecure.storage.protocol .putGroup(groupId, group) .then(function() { return group.numbers; }); }); }, deleteGroup: function(groupId) { return textsecure.storage.protocol.removeGroup(groupId); }, getGroup: function(groupId) { return textsecure.storage.protocol .getGroup(groupId) .then(function(group) { if (group === undefined) return undefined; return { id: groupId, numbers: group.numbers }; }); }, updateNumbers: function(groupId, numbers) { return textsecure.storage.protocol .getGroup(groupId) .then(function(group) { if (group === undefined) throw new Error('Tried to update numbers for unknown group'); if ( numbers.filter(textsecure.utils.isNumberSane).length < numbers.length ) throw new Error('Invalid number in new group members'); var added = numbers.filter(function(number) { return group.numbers.indexOf(number) < 0; }); return textsecure.storage.groups.addNumbers(groupId, added); }); }, }; })();