signal-desktop/libtextsecure/storage/groups.js

161 lines
5 KiB
JavaScript
Raw Normal View History

2018-07-21 21:51:20 +00:00
/* global window, getString, libsignal, textsecure */
/* eslint-disable more/no-then */
2018-05-02 16:51:22 +00:00
2018-07-21 21:51:20 +00:00
// eslint-disable-next-line func-names
(function() {
/** *******************
2018-05-02 16:51:22 +00:00
*** Group Storage ***
2018-07-21 21:51:20 +00:00
******************** */
2018-05-02 16:51:22 +00:00
window.textsecure = window.textsecure || {};
window.textsecure.storage = window.textsecure.storage || {};
// create a random group id that we haven't seen before.
function generateNewGroupId() {
2018-07-21 21:51:20 +00:00
const groupId = getString(libsignal.crypto.getRandomBytes(16));
return textsecure.storage.protocol.getGroup(groupId).then(group => {
2018-05-02 16:51:22 +00:00
if (group === undefined) {
return groupId;
}
2018-07-21 21:51:20 +00:00
window.log.warn('group id collision'); // probably a bad sign.
return generateNewGroupId();
2018-05-02 16:51:22 +00:00
});
}
window.textsecure.storage.groups = {
2018-07-21 21:51:20 +00:00
createNewGroup(numbers, groupId) {
return new Promise(resolve => {
2018-05-02 16:51:22 +00:00
if (groupId !== undefined) {
resolve(
2018-07-21 21:51:20 +00:00
textsecure.storage.protocol.getGroup(groupId).then(group => {
2018-05-02 16:51:22 +00:00
if (group !== undefined) {
throw new Error('Tried to recreate group');
}
})
);
} else {
resolve(
2018-07-21 21:51:20 +00:00
generateNewGroupId().then(newGroupId => {
// eslint-disable-next-line no-param-reassign
2018-05-02 16:51:22 +00:00
groupId = newGroupId;
})
);
}
2018-07-21 21:51:20 +00:00
}).then(() => {
const me = textsecure.storage.user.getNumber();
let haveMe = false;
const finalNumbers = [];
// eslint-disable-next-line no-restricted-syntax, guard-for-in
for (const i in numbers) {
const number = numbers[i];
2018-05-02 16:51:22 +00:00
if (!textsecure.utils.isNumberSane(number))
throw new Error('Invalid number in group');
2018-07-21 21:51:20 +00:00
if (number === me) haveMe = true;
2018-05-02 16:51:22 +00:00
if (finalNumbers.indexOf(number) < 0) finalNumbers.push(number);
}
2018-05-02 16:51:22 +00:00
if (!haveMe) finalNumbers.push(me);
2018-07-21 21:51:20 +00:00
const groupObject = {
numbers: finalNumbers,
numberRegistrationIds: {},
};
// eslint-disable-next-line no-restricted-syntax, guard-for-in
for (const i in finalNumbers) {
2018-05-02 16:51:22 +00:00
groupObject.numberRegistrationIds[finalNumbers[i]] = {};
2018-07-21 21:51:20 +00:00
}
2018-05-02 16:51:22 +00:00
return textsecure.storage.protocol
.putGroup(groupId, groupObject)
2018-07-21 21:51:20 +00:00
.then(() => ({ id: groupId, numbers: finalNumbers }));
2018-05-02 16:51:22 +00:00
});
},
2018-07-21 21:51:20 +00:00
getNumbers(groupId) {
return textsecure.storage.protocol.getGroup(groupId).then(group => {
2018-10-18 01:01:21 +00:00
if (!group) {
return undefined;
}
2018-07-21 21:51:20 +00:00
return group.numbers;
});
2018-05-02 16:51:22 +00:00
},
2018-07-21 21:51:20 +00:00
removeNumber(groupId, number) {
return textsecure.storage.protocol.getGroup(groupId).then(group => {
if (group === undefined) return undefined;
2018-07-21 21:51:20 +00:00
const me = textsecure.storage.user.getNumber();
if (number === me)
throw new Error(
'Cannot remove ourselves from a group, leave the group instead'
);
const i = group.numbers.indexOf(number);
if (i > -1) {
group.numbers.splice(i, 1);
// eslint-disable-next-line no-param-reassign
delete group.numberRegistrationIds[number];
return textsecure.storage.protocol
.putGroup(groupId, group)
.then(() => group.numbers);
}
return group.numbers;
});
2018-05-02 16:51:22 +00:00
},
2018-07-21 21:51:20 +00:00
addNumbers(groupId, numbers) {
return textsecure.storage.protocol.getGroup(groupId).then(group => {
if (group === undefined) return undefined;
// eslint-disable-next-line no-restricted-syntax, guard-for-in
for (const i in numbers) {
const 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);
// eslint-disable-next-line no-param-reassign
group.numberRegistrationIds[number] = {};
2018-05-02 16:51:22 +00:00
}
2018-07-21 21:51:20 +00:00
}
2018-07-21 21:51:20 +00:00
return textsecure.storage.protocol
.putGroup(groupId, group)
.then(() => group.numbers);
});
2018-05-02 16:51:22 +00:00
},
2018-07-21 21:51:20 +00:00
deleteGroup(groupId) {
2018-05-02 16:51:22 +00:00
return textsecure.storage.protocol.removeGroup(groupId);
},
2018-07-21 21:51:20 +00:00
getGroup(groupId) {
return textsecure.storage.protocol.getGroup(groupId).then(group => {
if (group === undefined) return undefined;
2018-07-21 21:51:20 +00:00
return { id: groupId, numbers: group.numbers };
});
2018-05-02 16:51:22 +00:00
},
2018-07-21 21:51:20 +00:00
updateNumbers(groupId, numbers) {
return textsecure.storage.protocol.getGroup(groupId).then(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');
const added = numbers.filter(
number => group.numbers.indexOf(number) < 0
);
return textsecure.storage.groups.addNumbers(groupId, added);
});
2018-05-02 16:51:22 +00:00
},
};
})();