Migrate schema to service ids

This commit is contained in:
Fedor Indutny 2023-08-16 22:54:39 +02:00 committed by Jamie Kyle
parent 71958f8a01
commit 8b0da36caa
258 changed files with 4795 additions and 2613 deletions

View file

@ -56,7 +56,7 @@
}; };
window.ConversationController = window.ConversationController || {}; window.ConversationController = window.ConversationController || {};
window.ConversationController.isSignalConversation = () => false; window.ConversationController.isSignalConversationId = () => false;
window.ConversationController.onConvoMessageMount = noop; window.ConversationController.onConvoMessageMount = noop;
window.getPreferredSystemLocales = () => ['en']; window.getPreferredSystemLocales = () => ['en'];
window.getResolvedMessagesLocaleDirection = () => 'ltr'; window.getResolvedMessagesLocaleDirection = () => 'ltr';

View file

@ -92,8 +92,9 @@
"@react-aria/utils": "3.16.0", "@react-aria/utils": "3.16.0",
"@react-spring/web": "9.5.5", "@react-spring/web": "9.5.5",
"@signalapp/better-sqlite3": "8.4.3", "@signalapp/better-sqlite3": "8.4.3",
"@signalapp/libsignal-client": "0.29.1", "@signalapp/libsignal-client": "0.30.2",
"@signalapp/ringrtc": "2.30.0", "@signalapp/ringrtc": "2.30.0",
"@signalapp/windows-dummy-keystroke": "1.0.0",
"@types/fabric": "4.5.3", "@types/fabric": "4.5.3",
"backbone": "1.4.0", "backbone": "1.4.0",
"blob-util": "2.0.2", "blob-util": "2.0.2",
@ -180,7 +181,6 @@
"uuid": "3.3.2", "uuid": "3.3.2",
"uuid-browser": "3.1.0", "uuid-browser": "3.1.0",
"websocket": "1.0.34", "websocket": "1.0.34",
"@signalapp/windows-dummy-keystroke": "1.0.0",
"zod": "3.21.4" "zod": "3.21.4"
}, },
"devDependencies": { "devDependencies": {
@ -195,7 +195,7 @@
"@electron/fuses": "1.5.0", "@electron/fuses": "1.5.0",
"@formatjs/intl": "2.6.7", "@formatjs/intl": "2.6.7",
"@mixer/parallel-prettier": "2.0.3", "@mixer/parallel-prettier": "2.0.3",
"@signalapp/mock-server": "3.2.3", "@signalapp/mock-server": "4.0.1",
"@storybook/addon-a11y": "6.5.6", "@storybook/addon-a11y": "6.5.6",
"@storybook/addon-actions": "6.5.6", "@storybook/addon-actions": "6.5.6",
"@storybook/addon-controls": "6.5.6", "@storybook/addon-controls": "6.5.6",

View file

@ -188,7 +188,7 @@ message GroupChange {
} }
bytes sourceUuid = 1; // Who made the change bytes sourceUserId = 1; // Who made the change
uint32 version = 2; // The change version number uint32 version = 2; // The change version number
repeated AddMemberAction addMembers = 3; // Members added repeated AddMemberAction addMembers = 3; // Members added
repeated DeleteMemberAction deleteMembers = 4; // Members deleted repeated DeleteMemberAction deleteMembers = 4; // Members deleted

View file

@ -136,7 +136,7 @@ message AccountRecord {
message PinnedConversation { message PinnedConversation {
message Contact { message Contact {
optional string uuid = 1; optional string serviceId = 1;
optional string e164 = 2; optional string e164 = 2;
} }

View file

@ -70,7 +70,9 @@ export async function populateConversationWithMessages({
schemaVersion: window.Signal.Types.Message.CURRENT_SCHEMA_VERSION, schemaVersion: window.Signal.Types.Message.CURRENT_SCHEMA_VERSION,
received_at: incrementMessageCounter(), received_at: incrementMessageCounter(),
readStatus: isUnread ? ReadStatus.Unread : ReadStatus.Read, readStatus: isUnread ? ReadStatus.Unread : ReadStatus.Read,
sourceUuid: isIncoming ? conversation.getCheckedServiceId('CI') : ourAci, sourceServiceId: isIncoming
? conversation.getCheckedServiceId('CI')
: ourAci,
...(isIncoming ...(isIncoming
? {} ? {}
: { : {

View file

@ -22,11 +22,12 @@ import { maybeDeriveGroupV2Id } from './groups';
import { assertDev, strictAssert } from './util/assert'; import { assertDev, strictAssert } from './util/assert';
import { drop } from './util/drop'; import { drop } from './util/drop';
import { isGroupV1, isGroupV2 } from './util/whatTypeOfConversation'; import { isGroupV1, isGroupV2 } from './util/whatTypeOfConversation';
import type { ServiceIdString } from './types/ServiceId'; import type { ServiceIdString, AciString, PniString } from './types/ServiceId';
import { import {
isServiceIdString, isServiceIdString,
normalizeAci, normalizeAci,
normalizePni, normalizePni,
normalizeServiceId,
} from './types/ServiceId'; } from './types/ServiceId';
import { sleep } from './util/sleep'; import { sleep } from './util/sleep';
import { isNotNil } from './util/isNotNil'; import { isNotNil } from './util/isNotNil';
@ -40,7 +41,7 @@ import { countAllConversationsUnreadStats } from './util/countUnreadStats';
type ConvoMatchType = type ConvoMatchType =
| { | {
key: 'uuid' | 'pni'; key: 'serviceId' | 'pni';
value: ServiceIdString | undefined; value: ServiceIdString | undefined;
match: ConversationModel | undefined; match: ConversationModel | undefined;
} }
@ -55,7 +56,7 @@ const { hasOwnProperty } = Object.prototype;
function applyChangeToConversation( function applyChangeToConversation(
conversation: ConversationModel, conversation: ConversationModel,
suggestedChange: Partial< suggestedChange: Partial<
Pick<ConversationAttributesType, 'uuid' | 'e164' | 'pni'> Pick<ConversationAttributesType, 'serviceId' | 'e164' | 'pni'>
> >
) { ) {
const change = { ...suggestedChange }; const change = { ...suggestedChange };
@ -65,29 +66,29 @@ function applyChangeToConversation(
change.pni = undefined; change.pni = undefined;
} }
// If we have a PNI but not an ACI, then the PNI will go in the UUID field // If we have a PNI but not an ACI, then the PNI will go in the serviceId field
// Tricky: We need a special check here, because the PNI can be in the uuid slot // Tricky: We need a special check here, because the PNI can be in the serviceId slot
if ( if (
change.pni && change.pni &&
!change.uuid && !change.serviceId &&
(!conversation.get('uuid') || (!conversation.getServiceId() ||
conversation.get('uuid') === conversation.get('pni')) conversation.getServiceId() === conversation.getPni())
) { ) {
change.uuid = change.pni; change.serviceId = change.pni;
} }
// If we're clearing a PNI, but we didn't have an ACI - we need to clear UUID field // If we're clearing a PNI, but we didn't have an ACI - we need to clear serviceId field
if ( if (
!change.uuid && !change.serviceId &&
hasOwnProperty.call(change, 'pni') && hasOwnProperty.call(change, 'pni') &&
!change.pni && !change.pni &&
conversation.get('uuid') === conversation.get('pni') conversation.getServiceId() === conversation.getPni()
) { ) {
change.uuid = undefined; change.serviceId = undefined;
} }
if (hasOwnProperty.call(change, 'uuid')) { if (hasOwnProperty.call(change, 'serviceId')) {
conversation.updateUuid(change.uuid); conversation.updateServiceId(change.serviceId);
} }
if (hasOwnProperty.call(change, 'e164')) { if (hasOwnProperty.call(change, 'e164')) {
conversation.updateE164(change.e164); conversation.updateE164(change.e164);
@ -289,7 +290,7 @@ export class ConversationController {
if (type === 'group') { if (type === 'group') {
conversation = this._conversations.add({ conversation = this._conversations.add({
id, id,
uuid: undefined, serviceId: undefined,
e164: undefined, e164: undefined,
groupId: identifier, groupId: identifier,
type, type,
@ -299,7 +300,7 @@ export class ConversationController {
} else if (isServiceIdString(identifier)) { } else if (isServiceIdString(identifier)) {
conversation = this._conversations.add({ conversation = this._conversations.add({
id, id,
uuid: identifier, serviceId: identifier,
e164: undefined, e164: undefined,
groupId: undefined, groupId: undefined,
type, type,
@ -309,7 +310,7 @@ export class ConversationController {
} else { } else {
conversation = this._conversations.add({ conversation = this._conversations.add({
id, id,
uuid: undefined, serviceId: undefined,
e164: identifier, e164: identifier,
groupId: undefined, groupId: undefined,
type, type,
@ -455,12 +456,8 @@ export class ConversationController {
return conversation; return conversation;
} }
isSignalConversation(uuidOrId: string): boolean { isSignalConversationId(conversationId: string): boolean {
if (uuidOrId === SIGNAL_ACI) { return this._signalConversationId === conversationId;
return true;
}
return this._signalConversationId === uuidOrId;
} }
areWePrimaryDevice(): boolean { areWePrimaryDevice(): boolean {
@ -469,7 +466,7 @@ export class ConversationController {
return ourDeviceId === 1; return ourDeviceId === 1;
} }
// Note: If you don't know what kind of UUID it is, put it in the 'aci' param. // Note: If you don't know what kind of serviceId it is, put it in the 'aci' param.
maybeMergeContacts({ maybeMergeContacts({
aci: providedAci, aci: providedAci,
e164, e164,
@ -478,9 +475,9 @@ export class ConversationController {
fromPniSignature, fromPniSignature,
mergeOldAndNew = safeCombineConversations, mergeOldAndNew = safeCombineConversations,
}: { }: {
aci?: string; aci?: AciString;
e164?: string; e164?: string;
pni?: string; pni?: PniString;
reason: string; reason: string;
fromPniSignature?: boolean; fromPniSignature?: boolean;
mergeOldAndNew?: (options: SafeCombineConversationsParams) => Promise<void>; mergeOldAndNew?: (options: SafeCombineConversationsParams) => Promise<void>;
@ -500,8 +497,7 @@ export class ConversationController {
} }
const logId = `maybeMergeContacts/${reason}/${dataProvided.join(',')}`; const logId = `maybeMergeContacts/${reason}/${dataProvided.join(',')}`;
const aci = const aci = providedAci
providedAci && providedAci !== providedPni
? normalizeAci(providedAci, 'maybeMergeContacts.aci') ? normalizeAci(providedAci, 'maybeMergeContacts.aci')
: undefined; : undefined;
const pni = providedPni const pni = providedPni
@ -517,7 +513,7 @@ export class ConversationController {
const matches: Array<ConvoMatchType> = [ const matches: Array<ConvoMatchType> = [
{ {
key: 'uuid', key: 'serviceId',
value: aci, value: aci,
match: window.ConversationController.get(aci), match: window.ConversationController.get(aci),
}, },
@ -568,26 +564,26 @@ export class ConversationController {
); );
targetConversation = match; targetConversation = match;
} }
// Tricky: PNI can end up in UUID slot, so we need to special-case it // Tricky: PNI can end up in serviceId slot, so we need to special-case it
if ( if (
!targetConversation && !targetConversation &&
unused.key === 'uuid' && unused.key === 'serviceId' &&
match.get(unused.key) === pni match.get(unused.key) === pni
) { ) {
log.info( log.info(
`${logId}: Match on ${key} has uuid matching incoming pni, ` + `${logId}: Match on ${key} has serviceId matching incoming pni, ` +
`so it will be our target conversation - ${match.idForLogging()}` `so it will be our target conversation - ${match.idForLogging()}`
); );
targetConversation = match; targetConversation = match;
} }
// Tricky: PNI can end up in UUID slot, so we need to special-case it // Tricky: PNI can end up in serviceId slot, so we need to special-case it
if ( if (
!targetConversation && !targetConversation &&
unused.key === 'uuid' && unused.key === 'serviceId' &&
match.get(unused.key) === match.get('pni') match.get(unused.key) === match.getPni()
) { ) {
log.info( log.info(
`${logId}: Match on ${key} has pni/uuid which are the same value, ` + `${logId}: Match on ${key} has pni/serviceId which are the same value, ` +
`so it will be our target conversation - ${match.idForLogging()}` `so it will be our target conversation - ${match.idForLogging()}`
); );
targetConversation = match; targetConversation = match;
@ -640,20 +636,21 @@ export class ConversationController {
); );
const change: Pick< const change: Pick<
Partial<ConversationAttributesType>, Partial<ConversationAttributesType>,
'uuid' | 'e164' | 'pni' 'serviceId' | 'e164' | 'pni'
> = { > = {
[key]: undefined, [key]: undefined,
}; };
// When the PNI is being used in the uuid field alone, we need to clear it // When the PNI is being used in the serviceId field alone, we need to clear it
if ((key === 'pni' || key === 'e164') && match.get('uuid') === pni) { if ((key === 'pni' || key === 'e164') && match.getServiceId() === pni) {
change.uuid = undefined; change.serviceId = undefined;
} }
applyChangeToConversation(match, change); applyChangeToConversation(match, change);
// Note: The PNI check here is just to be bulletproof; if we know a UUID is a PNI, // Note: The PNI check here is just to be bulletproof; if we know a
// then that should be put in the UUID field as well! // serviceId is a PNI, then that should be put in the serviceId field
// as well!
const willMerge = const willMerge =
!match.get('uuid') && !match.get('e164') && !match.get('pni'); !match.getServiceId() && !match.get('e164') && !match.getPni();
applyChangeToConversation(targetConversation, { applyChangeToConversation(targetConversation, {
[key]: value, [key]: value,
@ -705,7 +702,7 @@ export class ConversationController {
log.info(`${logId}: Creating a new conversation with all inputs`); log.info(`${logId}: Creating a new conversation with all inputs`);
// This is not our precedence for lookup, but it ensures that the PNI gets into the // This is not our precedence for lookup, but it ensures that the PNI gets into the
// uuid slot if we have no ACI. // serviceId slot if we have no ACI.
const identifier = aci || pni || e164; const identifier = aci || pni || e164;
strictAssert(identifier, `${logId}: identifier must be truthy!`); strictAssert(identifier, `${logId}: identifier must be truthy!`);
@ -716,73 +713,75 @@ export class ConversationController {
} }
/** /**
* Given a UUID and/or an E164, returns a string representing the local * Given a serviceId and/or an E164, returns a string representing the local
* database id of the given contact. Will create a new conversation if none exists; * database id of the given contact. Will create a new conversation if none exists;
* otherwise will return whatever is found. * otherwise will return whatever is found.
*/ */
lookupOrCreate({ lookupOrCreate({
e164, e164,
uuid, serviceId,
reason, reason,
}: { }: {
e164?: string | null; e164?: string | null;
uuid?: string | null; serviceId?: ServiceIdString | null;
reason: string; reason: string;
}): ConversationModel | undefined { }): ConversationModel | undefined {
const normalizedUuid = uuid ? uuid.toLowerCase() : undefined; const normalizedServiceId = serviceId
const identifier = normalizedUuid || e164; ? normalizeServiceId(serviceId, 'ConversationController.lookupOrCreate')
: undefined;
const identifier = normalizedServiceId || e164;
if ((!e164 && !uuid) || !identifier) { if ((!e164 && !serviceId) || !identifier) {
log.warn( log.warn(
`lookupOrCreate: Called with neither e164 nor uuid! reason: ${reason}` `lookupOrCreate: Called with neither e164 nor serviceId! reason: ${reason}`
); );
return undefined; return undefined;
} }
const convoE164 = this.get(e164); const convoE164 = this.get(e164);
const convoUuid = this.get(normalizedUuid); const convoServiceId = this.get(normalizedServiceId);
// 1. Handle no match at all // 1. Handle no match at all
if (!convoE164 && !convoUuid) { if (!convoE164 && !convoServiceId) {
log.info('lookupOrCreate: Creating new contact, no matches found'); log.info('lookupOrCreate: Creating new contact, no matches found');
const newConvo = this.getOrCreate(identifier, 'private'); const newConvo = this.getOrCreate(identifier, 'private');
// `identifier` would resolve to uuid if we had both, so fix up e164 // `identifier` would resolve to serviceId if we had both, so fix up e164
if (normalizedUuid && e164) { if (normalizedServiceId && e164) {
newConvo.updateE164(e164); newConvo.updateE164(e164);
} }
return newConvo; return newConvo;
} }
// 2. Handle match on only UUID // 2. Handle match on only service id
if (!convoE164 && convoUuid) { if (!convoE164 && convoServiceId) {
return convoUuid; return convoServiceId;
} }
// 3. Handle match on only E164 // 3. Handle match on only E164
if (convoE164 && !convoUuid) { if (convoE164 && !convoServiceId) {
return convoE164; return convoE164;
} }
// For some reason, TypeScript doesn't believe that we can trust that these two values // For some reason, TypeScript doesn't believe that we can trust that these two values
// are truthy by this point. So we'll throw if that isn't the case. // are truthy by this point. So we'll throw if that isn't the case.
if (!convoE164 || !convoUuid) { if (!convoE164 || !convoServiceId) {
throw new Error( throw new Error(
`lookupOrCreate: convoE164 or convoUuid are falsey but should both be true! reason: ${reason}` `lookupOrCreate: convoE164 or convoServiceId are falsey but should both be true! reason: ${reason}`
); );
} }
// 4. If the two lookups agree, return that conversation // 4. If the two lookups agree, return that conversation
if (convoE164 === convoUuid) { if (convoE164 === convoServiceId) {
return convoUuid; return convoServiceId;
} }
// 5. If the two lookups disagree, log and return the UUID match // 5. If the two lookups disagree, log and return the service id match
log.warn( log.warn(
`lookupOrCreate: Found a split contact - UUID ${normalizedUuid} and E164 ${e164}. Returning UUID match. reason: ${reason}` `lookupOrCreate: Found a split contact - service id ${normalizedServiceId} and E164 ${e164}. Returning service id match. reason: ${reason}`
); );
return convoUuid; return convoServiceId;
} }
checkForConflicts(): Promise<void> { checkForConflicts(): Promise<void> {
@ -795,7 +794,7 @@ export class ConversationController {
// run on `_combineConversationsQueue` queue and we don't want deadlocks. // run on `_combineConversationsQueue` queue and we don't want deadlocks.
private async doCheckForConflicts(): Promise<void> { private async doCheckForConflicts(): Promise<void> {
log.info('checkForConflicts: starting...'); log.info('checkForConflicts: starting...');
const byUuid = Object.create(null); const byServiceId = Object.create(null);
const byE164 = Object.create(null); const byE164 = Object.create(null);
const byGroupV2Id = Object.create(null); const byGroupV2Id = Object.create(null);
// We also want to find duplicate GV1 IDs. You might expect to see a "byGroupV1Id" map // We also want to find duplicate GV1 IDs. You might expect to see a "byGroupV1Id" map
@ -812,16 +811,18 @@ export class ConversationController {
'Expected conversation to be found in array during iteration' 'Expected conversation to be found in array during iteration'
); );
const uuid = conversation.get('uuid'); const serviceId = conversation.getServiceId();
const pni = conversation.get('pni'); const pni = conversation.getPni();
const e164 = conversation.get('e164'); const e164 = conversation.get('e164');
if (uuid) { if (serviceId) {
const existing = byUuid[uuid]; const existing = byServiceId[serviceId];
if (!existing) { if (!existing) {
byUuid[uuid] = conversation; byServiceId[serviceId] = conversation;
} else { } else {
log.warn(`checkForConflicts: Found conflict with uuid ${uuid}`); log.warn(
`checkForConflicts: Found conflict with serviceId ${serviceId}`
);
// Keep the newer one if it has an e164, otherwise keep existing // Keep the newer one if it has an e164, otherwise keep existing
if (conversation.get('e164')) { if (conversation.get('e164')) {
@ -831,7 +832,7 @@ export class ConversationController {
current: conversation, current: conversation,
obsolete: existing, obsolete: existing,
}); });
byUuid[uuid] = conversation; byServiceId[serviceId] = conversation;
} else { } else {
// Keep existing - note that this applies if neither had an e164 // Keep existing - note that this applies if neither had an e164
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
@ -844,28 +845,28 @@ export class ConversationController {
} }
if (pni) { if (pni) {
const existing = byUuid[pni]; const existing = byServiceId[pni];
if (!existing) { if (!existing) {
byUuid[pni] = conversation; byServiceId[pni] = conversation;
} else if (existing === conversation) { } else if (existing === conversation) {
// Conversation has both uuid and pni set to the same value. This // Conversation has both service id and pni set to the same value. This
// happens when starting a conversation by E164. // happens when starting a conversation by E164.
assertDev( assertDev(
pni === uuid, pni === serviceId,
'checkForConflicts: expected PNI to be equal to UUID' 'checkForConflicts: expected PNI to be equal to serviceId'
); );
} else { } else {
log.warn(`checkForConflicts: Found conflict with pni ${pni}`); log.warn(`checkForConflicts: Found conflict with pni ${pni}`);
// Keep the newer one if it has additional data, otherwise keep existing // Keep the newer one if it has additional data, otherwise keep existing
if (conversation.get('e164') || conversation.get('pni')) { if (conversation.get('e164') || conversation.getPni()) {
// Keep new one // Keep new one
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await this.doCombineConversations({ await this.doCombineConversations({
current: conversation, current: conversation,
obsolete: existing, obsolete: existing,
}); });
byUuid[pni] = conversation; byServiceId[pni] = conversation;
} else { } else {
// Keep existing - note that this applies if neither had an e164 // Keep existing - note that this applies if neither had an e164
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
@ -882,15 +883,15 @@ export class ConversationController {
if (!existing) { if (!existing) {
byE164[e164] = conversation; byE164[e164] = conversation;
} else { } else {
// If we have two contacts with the same e164 but different truthy UUIDs, then // If we have two contacts with the same e164 but different truthy
// we'll delete the e164 on the older one // service ids, then we'll delete the e164 on the older one
if ( if (
conversation.get('uuid') && conversation.getServiceId() &&
existing.get('uuid') && existing.getServiceId() &&
conversation.get('uuid') !== existing.get('uuid') conversation.getServiceId() !== existing.getServiceId()
) { ) {
log.warn( log.warn(
`checkForConflicts: Found two matches on e164 ${e164} with different truthy UUIDs. Dropping e164 on older.` `checkForConflicts: Found two matches on e164 ${e164} with different truthy service ids. Dropping e164 on older.`
); );
existing.set({ e164: undefined }); existing.set({ e164: undefined });
@ -903,8 +904,8 @@ export class ConversationController {
log.warn(`checkForConflicts: Found conflict with e164 ${e164}`); log.warn(`checkForConflicts: Found conflict with e164 ${e164}`);
// Keep the newer one if it has a UUID, otherwise keep existing // Keep the newer one if it has a service id, otherwise keep existing
if (conversation.get('uuid')) { if (conversation.getServiceId()) {
// Keep new one // Keep new one
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await this.doCombineConversations({ await this.doCombineConversations({
@ -913,7 +914,7 @@ export class ConversationController {
}); });
byE164[e164] = conversation; byE164[e164] = conversation;
} else { } else {
// Keep existing - note that this applies if neither had a UUID // Keep existing - note that this applies if neither had a service id
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await this.doCombineConversations({ await this.doCombineConversations({
current: existing, current: existing,
@ -1073,7 +1074,7 @@ export class ConversationController {
} }
log.warn(`${logId}: Delete all sessions tied to old conversationId`); log.warn(`${logId}: Delete all sessions tied to old conversationId`);
// Note: we use the conversationId here in case we've already lost our uuid. // Note: we use the conversationId here in case we've already lost our service id.
await window.textsecure.storage.protocol.removeSessionsByConversation( await window.textsecure.storage.protocol.removeSessionsByConversation(
obsoleteId obsoleteId
); );
@ -1301,9 +1302,9 @@ export class ConversationController {
async _forgetE164(e164: string): Promise<void> { async _forgetE164(e164: string): Promise<void> {
const { server } = window.textsecure; const { server } = window.textsecure;
strictAssert(server, 'Server must be initialized'); strictAssert(server, 'Server must be initialized');
const uuidMap = await getServiceIdsForE164s(server, [e164]); const serviceIdMap = await getServiceIdsForE164s(server, [e164]);
const pni = uuidMap.get(e164)?.pni; const pni = serviceIdMap.get(e164)?.pni;
log.info(`ConversationController: forgetting e164=${e164} pni=${pni}`); log.info(`ConversationController: forgetting e164=${e164} pni=${pni}`);
@ -1382,14 +1383,16 @@ export class ConversationController {
updateConversation(conversation.attributes); updateConversation(conversation.attributes);
} }
// Clean up the conversations that have UUID as their e164. // Clean up the conversations that have service id as their e164.
const e164 = conversation.get('e164'); const e164 = conversation.get('e164');
const uuid = conversation.get('uuid'); const serviceId = conversation.getServiceId();
if (e164 && isServiceIdString(e164) && uuid) { if (e164 && isServiceIdString(e164) && serviceId) {
conversation.set({ e164: undefined }); conversation.set({ e164: undefined });
updateConversation(conversation.attributes); updateConversation(conversation.attributes);
log.info(`Cleaning up conversation(${uuid}) with invalid e164`); log.info(
`Cleaning up conversation(${serviceId}) with invalid e164`
);
} }
} catch (error) { } catch (error) {
log.error( log.error(

View file

@ -423,7 +423,8 @@ export class SignalProtocolStore extends EventEmitter {
.map(item => item.fromDB) .map(item => item.fromDB)
.filter( .filter(
item => item =>
item.ourUuid === ourServiceId && item.isLastResort === isLastResort item.ourServiceId === ourServiceId &&
item.isLastResort === isLastResort
); );
} }
@ -479,7 +480,7 @@ export class SignalProtocolStore extends EventEmitter {
isConfirmed: key.isConfirmed, isConfirmed: key.isConfirmed,
isLastResort: key.isLastResort, isLastResort: key.isLastResort,
keyId: key.keyId, keyId: key.keyId,
ourUuid: ourServiceId, ourServiceId,
}; };
toSave.push(kyberPreKey); toSave.push(kyberPreKey);
@ -589,7 +590,7 @@ export class SignalProtocolStore extends EventEmitter {
const entries = Array.from(this.preKeys.values()); const entries = Array.from(this.preKeys.values());
return entries return entries
.map(item => item.fromDB) .map(item => item.fromDB)
.filter(item => item.ourUuid === ourServiceId); .filter(item => item.ourServiceId === ourServiceId);
} }
async storePreKeys( async storePreKeys(
@ -613,7 +614,7 @@ export class SignalProtocolStore extends EventEmitter {
const preKey = { const preKey = {
id, id,
keyId: key.keyId, keyId: key.keyId,
ourUuid: ourServiceId, ourServiceId,
publicKey: key.keyPair.pubKey, publicKey: key.keyPair.pubKey,
privateKey: key.keyPair.privKey, privateKey: key.keyPair.privKey,
createdAt: now, createdAt: now,
@ -705,7 +706,7 @@ export class SignalProtocolStore extends EventEmitter {
const entries = Array.from(this.signedPreKeys.values()); const entries = Array.from(this.signedPreKeys.values());
return entries return entries
.filter(({ fromDB }) => fromDB.ourUuid === ourServiceId) .filter(({ fromDB }) => fromDB.ourServiceId === ourServiceId)
.map(entry => { .map(entry => {
const preKey = entry.fromDB; const preKey = entry.fromDB;
return { return {
@ -760,7 +761,7 @@ export class SignalProtocolStore extends EventEmitter {
const fromDB = { const fromDB = {
id, id,
ourUuid: ourServiceId, ourServiceId,
keyId, keyId,
publicKey: keyPair.pubKey, publicKey: keyPair.pubKey,
privateKey: keyPair.privKey, privateKey: keyPair.privKey,
@ -1335,7 +1336,7 @@ export class SignalProtocolStore extends EventEmitter {
throw new Error('_maybeMigrateSession: Unknown session version type!'); throw new Error('_maybeMigrateSession: Unknown session version type!');
} }
const ourServiceId = session.ourUuid; const { ourServiceId } = session;
const keyPair = this.getIdentityKeyPair(ourServiceId); const keyPair = this.getIdentityKeyPair(ourServiceId);
if (!keyPair) { if (!keyPair) {
@ -1384,7 +1385,7 @@ export class SignalProtocolStore extends EventEmitter {
const { serviceId, deviceId } = qualifiedAddress; const { serviceId, deviceId } = qualifiedAddress;
const conversation = window.ConversationController.lookupOrCreate({ const conversation = window.ConversationController.lookupOrCreate({
uuid: serviceId, serviceId,
reason: 'SignalProtocolStore.storeSession', reason: 'SignalProtocolStore.storeSession',
}); });
strictAssert( strictAssert(
@ -1397,9 +1398,9 @@ export class SignalProtocolStore extends EventEmitter {
const fromDB = { const fromDB = {
id, id,
version: 2, version: 2,
ourUuid: qualifiedAddress.ourServiceId, ourServiceId: qualifiedAddress.ourServiceId,
conversationId: conversation.id, conversationId: conversation.id,
uuid: serviceId, serviceId,
deviceId, deviceId,
record: record.serialize().toString('base64'), record: record.serialize().toString('base64'),
}; };
@ -1448,7 +1449,8 @@ export class SignalProtocolStore extends EventEmitter {
const allSessions = this._getAllSessions(); const allSessions = this._getAllSessions();
const entries = allSessions.filter( const entries = allSessions.filter(
({ fromDB }) => ({ fromDB }) =>
fromDB.ourUuid === ourServiceId && serviceIdSet.has(fromDB.uuid) fromDB.ourServiceId === ourServiceId &&
serviceIdSet.has(fromDB.serviceId)
); );
const openEntries: Array< const openEntries: Array<
| undefined | undefined
@ -1485,15 +1487,15 @@ export class SignalProtocolStore extends EventEmitter {
} }
const { entry, record } = item; const { entry, record } = item;
const { uuid } = entry.fromDB; const { serviceId } = entry.fromDB;
serviceIdSet.delete(uuid); serviceIdSet.delete(serviceId);
const id = entry.fromDB.deviceId; const id = entry.fromDB.deviceId;
const registrationId = record.remoteRegistrationId(); const registrationId = record.remoteRegistrationId();
return { return {
serviceId: uuid, serviceId,
id, id,
registrationId, registrationId,
}; };
@ -1601,7 +1603,7 @@ export class SignalProtocolStore extends EventEmitter {
for (let i = 0, max = entries.length; i < max; i += 1) { for (let i = 0, max = entries.length; i < max; i += 1) {
const entry = entries[i]; const entry = entries[i];
if (entry.fromDB.uuid === serviceId) { if (entry.fromDB.serviceId === serviceId) {
this.sessions.delete(entry.fromDB.id); this.sessions.delete(entry.fromDB.id);
this.pendingSessions.delete(entry.fromDB.id); this.pendingSessions.delete(entry.fromDB.id);
} }
@ -1675,7 +1677,8 @@ export class SignalProtocolStore extends EventEmitter {
const allEntries = this._getAllSessions(); const allEntries = this._getAllSessions();
const entries = allEntries.filter( const entries = allEntries.filter(
entry => entry =>
entry.fromDB.uuid === serviceId && entry.fromDB.deviceId !== deviceId entry.fromDB.serviceId === serviceId &&
entry.fromDB.deviceId !== deviceId
); );
await Promise.all( await Promise.all(
@ -1696,7 +1699,7 @@ export class SignalProtocolStore extends EventEmitter {
const allEntries = this._getAllSessions(); const allEntries = this._getAllSessions();
const entries = allEntries.filter( const entries = allEntries.filter(
entry => entry.fromDB.uuid === serviceId entry => entry.fromDB.serviceId === serviceId
); );
await Promise.all( await Promise.all(
@ -1743,7 +1746,7 @@ export class SignalProtocolStore extends EventEmitter {
// First, fetch this conversation // First, fetch this conversation
const conversation = window.ConversationController.lookupOrCreate({ const conversation = window.ConversationController.lookupOrCreate({
uuid: serviceId, serviceId,
reason: 'SignalProtocolStore.lightSessionReset', reason: 'SignalProtocolStore.lightSessionReset',
}); });
assertDev(conversation, `lightSessionReset/${id}: missing conversation`); assertDev(conversation, `lightSessionReset/${id}: missing conversation`);
@ -2584,7 +2587,7 @@ export class SignalProtocolStore extends EventEmitter {
isConfirmed: true, isConfirmed: true,
isLastResort: true, isLastResort: true,
keyId: lastResortKyberPreKey.id(), keyId: lastResortKyberPreKey.id(),
ourUuid: pni, ourServiceId: pni,
}, },
]) ])
: undefined, : undefined,

View file

@ -1081,7 +1081,7 @@ export async function startApp(): Promise<void> {
`retryPlaceholders/interval: Found ${expired.length} expired items` `retryPlaceholders/interval: Found ${expired.length} expired items`
); );
expired.forEach(item => { expired.forEach(item => {
const { conversationId, senderUuid, sentAt } = item; const { conversationId, senderAci, sentAt } = item;
const conversation = const conversation =
window.ConversationController.get(conversationId); window.ConversationController.get(conversationId);
if (conversation) { if (conversation) {
@ -1092,7 +1092,7 @@ export async function startApp(): Promise<void> {
conversation.addDeliveryIssue({ conversation.addDeliveryIssue({
receivedAt, receivedAt,
receivedAtCounter, receivedAtCounter,
senderUuid, senderAci,
sentAt, sentAt,
}) })
) )
@ -2469,7 +2469,7 @@ export async function startApp(): Promise<void> {
remove: reaction.remove, remove: reaction.remove,
source: ReactionSource.FromSomeoneElse, source: ReactionSource.FromSomeoneElse,
storyReactionMessage: message, storyReactionMessage: message,
targetAuthorUuid: targetAuthorAci, targetAuthorAci,
targetTimestamp: reaction.targetTimestamp, targetTimestamp: reaction.targetTimestamp,
timestamp, timestamp,
}; };
@ -2679,7 +2679,7 @@ export async function startApp(): Promise<void> {
serverTimestamp: data.serverTimestamp, serverTimestamp: data.serverTimestamp,
source: window.textsecure.storage.user.getNumber(), source: window.textsecure.storage.user.getNumber(),
sourceDevice: data.device, sourceDevice: data.device,
sourceUuid: window.textsecure.storage.user.getAci(), sourceServiceId: window.textsecure.storage.user.getAci(),
timestamp, timestamp,
type: data.message.isStory ? 'story' : 'outgoing', type: data.message.isStory ? 'story' : 'outgoing',
storyDistributionListId: data.storyDistributionListId, storyDistributionListId: data.storyDistributionListId,
@ -2755,8 +2755,8 @@ export async function startApp(): Promise<void> {
const { data, confirm } = event; const { data, confirm } = event;
const source = window.textsecure.storage.user.getNumber(); const source = window.textsecure.storage.user.getNumber();
const sourceUuid = window.textsecure.storage.user.getAci(); const sourceServiceId = window.textsecure.storage.user.getAci();
strictAssert(source && sourceUuid, 'Missing user number and uuid'); strictAssert(source && sourceServiceId, 'Missing user number and uuid');
const messageDescriptor = getMessageDescriptor({ const messageDescriptor = getMessageDescriptor({
...data, ...data,
@ -2804,7 +2804,7 @@ export async function startApp(): Promise<void> {
remove: reaction.remove, remove: reaction.remove,
source: ReactionSource.FromSync, source: ReactionSource.FromSync,
storyReactionMessage: message, storyReactionMessage: message,
targetAuthorUuid: targetAuthorAci, targetAuthorAci,
targetTimestamp: reaction.targetTimestamp, targetTimestamp: reaction.targetTimestamp,
timestamp, timestamp,
}; };
@ -2900,7 +2900,7 @@ export async function startApp(): Promise<void> {
serverTimestamp: data.serverTimestamp, serverTimestamp: data.serverTimestamp,
source: data.source, source: data.source,
sourceDevice: data.sourceDevice, sourceDevice: data.sourceDevice,
sourceUuid: data.sourceAci, sourceServiceId: data.sourceAci,
timestamp: data.timestamp, timestamp: data.timestamp,
type: data.message.isStory ? 'story' : 'incoming', type: data.message.isStory ? 'story' : 'incoming',
unidentifiedDeliveryReceived: data.unidentifiedDeliveryReceived, unidentifiedDeliveryReceived: data.unidentifiedDeliveryReceived,
@ -3174,7 +3174,7 @@ export async function startApp(): Promise<void> {
wasSentEncrypted, wasSentEncrypted,
} = event.receipt; } = event.receipt;
const sourceConversation = window.ConversationController.lookupOrCreate({ const sourceConversation = window.ConversationController.lookupOrCreate({
uuid: sourceServiceId, serviceId: sourceServiceId,
e164: source, e164: source,
reason: `onReadOrViewReceipt(${envelopeTimestamp})`, reason: `onReadOrViewReceipt(${envelopeTimestamp})`,
}); });
@ -3305,7 +3305,7 @@ export async function startApp(): Promise<void> {
ev.confirm(); ev.confirm();
const sourceConversation = window.ConversationController.lookupOrCreate({ const sourceConversation = window.ConversationController.lookupOrCreate({
uuid: sourceServiceId, serviceId: sourceServiceId,
e164: source, e164: source,
reason: `onDeliveryReceipt(${envelopeTimestamp})`, reason: `onDeliveryReceipt(${envelopeTimestamp})`,
}); });

View file

@ -26,7 +26,7 @@ import { SizeObserver } from '../hooks/useSizeObserver';
type OwnProps = { type OwnProps = {
i18n: LocalizerType; i18n: LocalizerType;
theme: ThemeType; theme: ThemeType;
contact: Pick<ConversationType, 'id' | 'title' | 'uuid'>; contact: Pick<ConversationType, 'id' | 'title' | 'serviceId' | 'pni'>;
candidateConversations: ReadonlyArray<ConversationType>; candidateConversations: ReadonlyArray<ConversationType>;
regionCode: string | undefined; regionCode: string | undefined;
}; };
@ -119,11 +119,12 @@ export function AddUserToAnotherGroupModal({
let disabledReason; let disabledReason;
if (memberships.some(c => c.uuid === contact.uuid)) { if (memberships.some(c => c.aci === contact.serviceId)) {
disabledReason = DisabledReason.AlreadyMember; disabledReason = DisabledReason.AlreadyMember;
} else if ( } else if (
pendingApprovalMemberships.some(c => c.uuid === contact.uuid) || pendingApprovalMemberships.some(c => c.aci === contact.serviceId) ||
pendingMemberships.some(c => c.uuid === contact.uuid) pendingMemberships.some(c => c.serviceId === contact.serviceId) ||
pendingMemberships.some(c => c.serviceId === contact.pni)
) { ) {
disabledReason = DisabledReason.Pending; disabledReason = DisabledReason.Pending;
} }

View file

@ -90,7 +90,7 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
), ),
title: text('Caller Title', 'Morty Smith'), title: text('Caller Title', 'Morty Smith'),
}), }),
uuid: generateAci(), serviceId: generateAci(),
}, },
notifyForCall: action('notify-for-call'), notifyForCall: action('notify-for-call'),
openSystemPreferencesAction: action('open-system-preferences-action'), openSystemPreferencesAction: action('open-system-preferences-action'),

View file

@ -274,7 +274,7 @@ function ActiveCallManager({
<CallingParticipantsList <CallingParticipantsList
i18n={i18n} i18n={i18n}
onClose={toggleParticipants} onClose={toggleParticipants}
ourUuid={me.uuid} ourServiceId={me.serviceId}
participants={peekedParticipants} participants={peekedParticipants}
/> />
) : null} ) : null}
@ -359,7 +359,7 @@ function ActiveCallManager({
<CallingParticipantsList <CallingParticipantsList
i18n={i18n} i18n={i18n}
onClose={toggleParticipants} onClose={toggleParticipants}
ourUuid={me.uuid} ourServiceId={me.serviceId}
participants={groupCallParticipantsForParticipantsList} participants={groupCallParticipantsForParticipantsList}
/> />
) : null} ) : null}

View file

@ -23,7 +23,7 @@ import { setupI18n } from '../util/setupI18n';
import { missingCaseError } from '../util/missingCaseError'; import { missingCaseError } from '../util/missingCaseError';
import { import {
getDefaultConversation, getDefaultConversation,
getDefaultConversationWithUuid, getDefaultConversationWithServiceId,
} from '../test-both/helpers/getDefaultConversation'; } from '../test-both/helpers/getDefaultConversation';
import { fakeGetGroupCallVideoFrameSource } from '../test-both/helpers/fakeGetGroupCallVideoFrameSource'; import { fakeGetGroupCallVideoFrameSource } from '../test-both/helpers/fakeGetGroupCallVideoFrameSource';
import enMessages from '../../_locales/en/messages.json'; import enMessages from '../../_locales/en/messages.json';
@ -175,7 +175,7 @@ const createProps = (
name: 'Morty Smith', name: 'Morty Smith',
profileName: 'Morty Smith', profileName: 'Morty Smith',
title: 'Morty Smith', title: 'Morty Smith',
uuid: generateAci(), serviceId: generateAci(),
}), }),
openSystemPreferencesAction: action('open-system-preferences-action'), openSystemPreferencesAction: action('open-system-preferences-action'),
setGroupCallVideoRequest: action('set-group-call-video-request'), setGroupCallVideoRequest: action('set-group-call-video-request'),
@ -312,7 +312,7 @@ export function GroupCall1(): JSX.Element {
videoAspectRatio: 1.3, videoAspectRatio: 1.3,
...getDefaultConversation({ ...getDefaultConversation({
isBlocked: false, isBlocked: false,
uuid: generateAci(), serviceId: generateAci(),
title: 'Tyler', title: 'Tyler',
}), }),
}, },
@ -334,7 +334,7 @@ const allRemoteParticipants = times(MAX_PARTICIPANTS).map(index => ({
presenting: false, presenting: false,
sharingScreen: false, sharingScreen: false,
videoAspectRatio: 1.3, videoAspectRatio: 1.3,
...getDefaultConversationWithUuid({ ...getDefaultConversationWithServiceId({
isBlocked: index === 10 || index === MAX_PARTICIPANTS - 1, isBlocked: index === 10 || index === MAX_PARTICIPANTS - 1,
title: `Participant ${index + 1}`, title: `Participant ${index + 1}`,
}), }),
@ -380,7 +380,7 @@ export function GroupCallReconnecting(): JSX.Element {
...getDefaultConversation({ ...getDefaultConversation({
isBlocked: false, isBlocked: false,
title: 'Tyler', title: 'Tyler',
uuid: generateAci(), serviceId: generateAci(),
}), }),
}, },
], ],

View file

@ -16,7 +16,7 @@ import { generateAci } from '../types/ServiceId';
import enMessages from '../../_locales/en/messages.json'; import enMessages from '../../_locales/en/messages.json';
import { import {
getDefaultConversation, getDefaultConversation,
getDefaultConversationWithUuid, getDefaultConversationWithServiceId,
} from '../test-both/helpers/getDefaultConversation'; } from '../test-both/helpers/getDefaultConversation';
const i18n = setupI18n('en', enMessages); const i18n = setupI18n('en', enMessages);
@ -67,7 +67,7 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => {
getDefaultConversation({ getDefaultConversation({
color: AvatarColors[0], color: AvatarColors[0],
id: generateUuid(), id: generateUuid(),
uuid: generateAci(), serviceId: generateAci(),
}), }),
onCallCanceled: action('on-call-canceled'), onCallCanceled: action('on-call-canceled'),
onJoinCall: action('on-join-call'), onJoinCall: action('on-join-call'),
@ -87,7 +87,7 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => {
}; };
const fakePeekedParticipant = (conversationProps: Partial<ConversationType>) => const fakePeekedParticipant = (conversationProps: Partial<ConversationType>) =>
getDefaultConversationWithUuid({ getDefaultConversationWithServiceId({
...conversationProps, ...conversationProps,
}); });
@ -118,7 +118,7 @@ export function NoCameraLocalAvatar(): JSX.Element {
avatarPath: '/fixtures/kitten-4-112-112.jpg', avatarPath: '/fixtures/kitten-4-112-112.jpg',
color: AvatarColors[0], color: AvatarColors[0],
id: generateUuid(), id: generateUuid(),
uuid: generateAci(), serviceId: generateAci(),
}), }),
}); });
return <CallingLobby {...props} />; return <CallingLobby {...props} />;
@ -168,14 +168,14 @@ GroupCall1PeekedParticipant.story = {
}; };
export function GroupCall1PeekedParticipantSelf(): JSX.Element { export function GroupCall1PeekedParticipantSelf(): JSX.Element {
const uuid = generateAci(); const serviceId = generateAci();
const props = createProps({ const props = createProps({
isGroupCall: true, isGroupCall: true,
me: getDefaultConversation({ me: getDefaultConversation({
id: generateUuid(), id: generateUuid(),
uuid, serviceId,
}), }),
peekedParticipants: [fakePeekedParticipant({ title: 'Ash', uuid })], peekedParticipants: [fakePeekedParticipant({ title: 'Ash', serviceId })],
}); });
return <CallingLobby {...props} />; return <CallingLobby {...props} />;
} }

View file

@ -49,7 +49,9 @@ export type PropsType = {
isGroupCall: boolean; isGroupCall: boolean;
isGroupCallOutboundRingEnabled: boolean; isGroupCallOutboundRingEnabled: boolean;
isCallFull?: boolean; isCallFull?: boolean;
me: Readonly<Pick<ConversationType, 'avatarPath' | 'color' | 'id' | 'uuid'>>; me: Readonly<
Pick<ConversationType, 'avatarPath' | 'color' | 'id' | 'serviceId'>
>;
onCallCanceled: () => void; onCallCanceled: () => void;
onJoinCall: () => void; onJoinCall: () => void;
outgoingRing: boolean; outgoingRing: boolean;

View file

@ -9,7 +9,8 @@ import type { PropsType } from './CallingParticipantsList';
import { CallingParticipantsList } from './CallingParticipantsList'; import { CallingParticipantsList } from './CallingParticipantsList';
import { AvatarColors } from '../types/Colors'; import { AvatarColors } from '../types/Colors';
import type { GroupCallRemoteParticipantType } from '../types/Calling'; import type { GroupCallRemoteParticipantType } from '../types/Calling';
import { getDefaultConversationWithUuid } from '../test-both/helpers/getDefaultConversation'; import { generateAci } from '../types/ServiceId';
import { getDefaultConversationWithServiceId } from '../test-both/helpers/getDefaultConversation';
import { setupI18n } from '../util/setupI18n'; import { setupI18n } from '../util/setupI18n';
import enMessages from '../../_locales/en/messages.json'; import enMessages from '../../_locales/en/messages.json';
@ -25,7 +26,7 @@ function createParticipant(
presenting: Boolean(participantProps.presenting), presenting: Boolean(participantProps.presenting),
sharingScreen: Boolean(participantProps.sharingScreen), sharingScreen: Boolean(participantProps.sharingScreen),
videoAspectRatio: 1.3, videoAspectRatio: 1.3,
...getDefaultConversationWithUuid({ ...getDefaultConversationWithServiceId({
avatarPath: participantProps.avatarPath, avatarPath: participantProps.avatarPath,
color: sample(AvatarColors), color: sample(AvatarColors),
isBlocked: Boolean(participantProps.isBlocked), isBlocked: Boolean(participantProps.isBlocked),
@ -39,7 +40,7 @@ function createParticipant(
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
i18n, i18n,
onClose: action('on-close'), onClose: action('on-close'),
ourUuid: 'cf085e6a-e70b-41ec-a310-c198248af13f', ourServiceId: generateAci(),
participants: overrideProps.participants || [], participants: overrideProps.participants || [],
}); });

View file

@ -11,6 +11,7 @@ import { Avatar, AvatarSize } from './Avatar';
import { ContactName } from './conversation/ContactName'; import { ContactName } from './conversation/ContactName';
import { InContactsIcon } from './InContactsIcon'; import { InContactsIcon } from './InContactsIcon';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
import type { ServiceIdString } from '../types/ServiceId';
import { sortByTitle } from '../util/sortByTitle'; import { sortByTitle } from '../util/sortByTitle';
import type { ConversationType } from '../state/ducks/conversations'; import type { ConversationType } from '../state/ducks/conversations';
import { isInSystemContacts } from '../util/isInSystemContacts'; import { isInSystemContacts } from '../util/isInSystemContacts';
@ -25,7 +26,7 @@ type ParticipantType = ConversationType & {
export type PropsType = { export type PropsType = {
readonly i18n: LocalizerType; readonly i18n: LocalizerType;
readonly onClose: () => void; readonly onClose: () => void;
readonly ourUuid: string | undefined; readonly ourServiceId: ServiceIdString | undefined;
readonly participants: Array<ParticipantType>; readonly participants: Array<ParticipantType>;
}; };
@ -33,7 +34,7 @@ export const CallingParticipantsList = React.memo(
function CallingParticipantsListInner({ function CallingParticipantsListInner({
i18n, i18n,
onClose, onClose,
ourUuid, ourServiceId,
participants, participants,
}: PropsType) { }: PropsType) {
const [root, setRoot] = React.useState<HTMLElement | null>(null); const [root, setRoot] = React.useState<HTMLElement | null>(null);
@ -101,9 +102,9 @@ export const CallingParticipantsList = React.memo(
(participant: ParticipantType, index: number) => ( (participant: ParticipantType, index: number) => (
<li <li
className="module-calling-participants-list__contact" className="module-calling-participants-list__contact"
// It's tempting to use `participant.uuid` as the `key` here, but that // It's tempting to use `participant.serviceId` as the `key`
// can result in duplicate keys for participants who have joined on // here, but that can result in duplicate keys for
// multiple devices. // participants who have joined on multiple devices.
key={index} key={index}
> >
<div> <div>
@ -122,7 +123,8 @@ export const CallingParticipantsList = React.memo(
sharedGroupNames={participant.sharedGroupNames} sharedGroupNames={participant.sharedGroupNames}
size={AvatarSize.THIRTY_TWO} size={AvatarSize.THIRTY_TWO}
/> />
{ourUuid && participant.uuid === ourUuid ? ( {ourServiceId &&
participant.serviceId === ourServiceId ? (
<span className="module-calling-participants-list__name"> <span className="module-calling-participants-list__name">
{i18n('icu:you')} {i18n('icu:you')}
</span> </span>

View file

@ -30,14 +30,14 @@ type PropsType = {
| 'unblurredAvatarPath' | 'unblurredAvatarPath'
>; >;
i18n: LocalizerType; i18n: LocalizerType;
me: Pick<ConversationType, 'id' | 'uuid'>; me: Pick<ConversationType, 'id' | 'serviceId'>;
ringMode: RingMode; ringMode: RingMode;
// The following should only be set for group conversations. // The following should only be set for group conversations.
groupMembers?: Array<Pick<ConversationType, 'id' | 'firstName' | 'title'>>; groupMembers?: Array<Pick<ConversationType, 'id' | 'firstName' | 'title'>>;
isCallFull?: boolean; isCallFull?: boolean;
peekedParticipants?: Array< peekedParticipants?: Array<
Pick<ConversationType, 'firstName' | 'title' | 'uuid'> Pick<ConversationType, 'firstName' | 'title' | 'serviceId'>
>; >;
}; };
@ -61,7 +61,7 @@ export function CallingPreCallInfo({
// device. // device.
let hasYou = false; let hasYou = false;
const participantNames = peekedParticipants.map(participant => { const participantNames = peekedParticipants.map(participant => {
if (participant.uuid === me.uuid) { if (participant.serviceId === me.serviceId) {
hasYou = true; hasYou = true;
return i18n('icu:you'); return i18n('icu:you');
} }

View file

@ -36,6 +36,7 @@ import type {
InMemoryAttachmentDraftType, InMemoryAttachmentDraftType,
} from '../types/Attachment'; } from '../types/Attachment';
import { isImageAttachment, isVoiceMessage } from '../types/Attachment'; import { isImageAttachment, isVoiceMessage } from '../types/Attachment';
import type { AciString } from '../types/ServiceId';
import { AudioCapture } from './conversation/AudioCapture'; import { AudioCapture } from './conversation/AudioCapture';
import { CompositionUpload } from './CompositionUpload'; import { CompositionUpload } from './CompositionUpload';
import type { import type {
@ -87,7 +88,6 @@ export type OwnProps = Readonly<{
conversationId: string; conversationId: string;
discardEditMessage: (id: string) => unknown; discardEditMessage: (id: string) => unknown;
draftEditMessage?: DraftEditMessageType; draftEditMessage?: DraftEditMessageType;
uuid?: string;
draftAttachments: ReadonlyArray<AttachmentDraftType>; draftAttachments: ReadonlyArray<AttachmentDraftType>;
errorDialogAudioRecorderType?: ErrorDialogAudioRecorderType; errorDialogAudioRecorderType?: ErrorDialogAudioRecorderType;
errorRecording: (e: ErrorDialogAudioRecorderType) => unknown; errorRecording: (e: ErrorDialogAudioRecorderType) => unknown;
@ -131,7 +131,7 @@ export type OwnProps = Readonly<{
options: { options: {
bodyRanges?: DraftBodyRanges; bodyRanges?: DraftBodyRanges;
message?: string; message?: string;
quoteAuthorUuid?: string; quoteAuthorAci?: AciString;
quoteSentAt?: number; quoteSentAt?: number;
targetMessageId: string; targetMessageId: string;
} }
@ -153,7 +153,7 @@ export type OwnProps = Readonly<{
'i18n' | 'onClick' | 'onClose' | 'withContentAbove' | 'isCompose' 'i18n' | 'onClick' | 'onClose' | 'withContentAbove' | 'isCompose'
> >
>; >;
quotedMessageAuthorUuid?: string; quotedMessageAuthorAci?: AciString;
quotedMessageSentAt?: number; quotedMessageSentAt?: number;
removeAttachment: (conversationId: string, filePath: string) => unknown; removeAttachment: (conversationId: string, filePath: string) => unknown;
@ -256,7 +256,7 @@ export function CompositionArea({
// Quote // Quote
quotedMessageId, quotedMessageId,
quotedMessageProps, quotedMessageProps,
quotedMessageAuthorUuid, quotedMessageAuthorAci,
quotedMessageSentAt, quotedMessageSentAt,
scrollToMessage, scrollToMessage,
// MediaQualitySelector // MediaQualitySelector
@ -356,7 +356,7 @@ export function CompositionArea({
message, message,
// sent timestamp for the quote // sent timestamp for the quote
quoteSentAt: quotedMessageSentAt, quoteSentAt: quotedMessageSentAt,
quoteAuthorUuid: quotedMessageAuthorUuid, quoteAuthorAci: quotedMessageAuthorAci,
targetMessageId: editedMessageId, targetMessageId: editedMessageId,
}); });
} else { } else {
@ -374,7 +374,7 @@ export function CompositionArea({
draftAttachments, draftAttachments,
editedMessageId, editedMessageId,
quotedMessageSentAt, quotedMessageSentAt,
quotedMessageAuthorUuid, quotedMessageAuthorAci,
sendEditedMessage, sendEditedMessage,
sendMultiMediaMessage, sendMultiMediaMessage,
setLarge, setLarge,

View file

@ -138,7 +138,7 @@ export function Mentions(): JSX.Element {
{ {
start: 5, start: 5,
length: 1, length: 1,
mentionUuid: generateAci(), mentionAci: generateAci(),
conversationID: 'k', conversationID: 'k',
replacementText: 'Kate Beaton', replacementText: 'Kate Beaton',
}, },

View file

@ -26,7 +26,7 @@ import { BodyRange, collapseRangeTree, insertRange } from '../types/BodyRange';
import type { LocalizerType, ThemeType } from '../types/Util'; import type { LocalizerType, ThemeType } from '../types/Util';
import type { ConversationType } from '../state/ducks/conversations'; import type { ConversationType } from '../state/ducks/conversations';
import type { PreferredBadgeSelectorType } from '../state/selectors/badges'; import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
import { isServiceIdString } from '../types/ServiceId'; import { isAciString } from '../types/ServiceId';
import { MentionBlot } from '../quill/mentions/blot'; import { MentionBlot } from '../quill/mentions/blot';
import { import {
matchEmojiImage, matchEmojiImage,
@ -678,15 +678,12 @@ export function CompositionInput(props: Props): React.ReactElement {
return; return;
} }
const currentMemberServiceIds = currentMembers const currentMemberAcis = currentMembers
.map(m => m.uuid) .map(m => m.serviceId)
.filter(isNotNil) .filter(isNotNil)
.filter(isServiceIdString); .filter(isAciString);
const newDelta = getDeltaToRemoveStaleMentions( const newDelta = getDeltaToRemoveStaleMentions(ops, currentMemberAcis);
ops,
currentMemberServiceIds
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
quill.updateContents(newDelta as any); quill.updateContents(newDelta as any);

View file

@ -374,7 +374,7 @@ export function ConversationList({
'unblurredAvatarPath', 'unblurredAvatarPath',
'unreadCount', 'unreadCount',
'unreadMentionsCount', 'unreadMentionsCount',
'uuid', 'serviceId',
]); ]);
const { badges, title, unreadCount, lastMessage } = itemProps; const { badges, title, unreadCount, lastMessage } = itemProps;
result = ( result = (

View file

@ -8,7 +8,7 @@ import { action } from '@storybook/addon-actions';
import { GroupCallOverflowArea } from './GroupCallOverflowArea'; import { GroupCallOverflowArea } from './GroupCallOverflowArea';
import { setupI18n } from '../util/setupI18n'; import { setupI18n } from '../util/setupI18n';
import { getDefaultConversationWithUuid } from '../test-both/helpers/getDefaultConversation'; import { getDefaultConversationWithServiceId } from '../test-both/helpers/getDefaultConversation';
import { fakeGetGroupCallVideoFrameSource } from '../test-both/helpers/fakeGetGroupCallVideoFrameSource'; import { fakeGetGroupCallVideoFrameSource } from '../test-both/helpers/fakeGetGroupCallVideoFrameSource';
import { FRAME_BUFFER_SIZE } from '../calling/constants'; import { FRAME_BUFFER_SIZE } from '../calling/constants';
import enMessages from '../../_locales/en/messages.json'; import enMessages from '../../_locales/en/messages.json';
@ -24,7 +24,7 @@ const allRemoteParticipants = times(MAX_PARTICIPANTS).map(index => ({
presenting: false, presenting: false,
sharingScreen: false, sharingScreen: false,
videoAspectRatio: 1.3, videoAspectRatio: 1.3,
...getDefaultConversationWithUuid({ ...getDefaultConversationWithServiceId({
isBlocked: index === 10 || index === MAX_PARTICIPANTS - 1, isBlocked: index === 10 || index === MAX_PARTICIPANTS - 1,
title: `Participant ${index + 1}`, title: `Participant ${index + 1}`,
}), }),

View file

@ -61,7 +61,7 @@ const createProps = (
isBlocked: Boolean(isBlocked), isBlocked: Boolean(isBlocked),
title: title:
'Pablo Diego José Francisco de Paula Juan Nepomuceno María de los Remedios Cipriano de la Santísima Trinidad Ruiz y Picasso', 'Pablo Diego José Francisco de Paula Juan Nepomuceno María de los Remedios Cipriano de la Santísima Trinidad Ruiz y Picasso',
uuid: generateAci(), serviceId: generateAci(),
}), }),
}, },
remoteParticipantsCount: 1, remoteParticipantsCount: 1,

View file

@ -310,7 +310,9 @@ function ContactSection({
} }
const { distributionId } = section.story; const { distributionId } = section.story;
const uuids = section.contacts.map(contact => contact.uuid).filter(isNotNil); const serviceIds = section.contacts
.map(contact => contact.serviceId)
.filter(isNotNil);
const sectionName = const sectionName =
distributionId === MY_STORY_ID distributionId === MY_STORY_ID
? i18n('icu:Stories__mine') ? i18n('icu:Stories__mine')
@ -322,17 +324,17 @@ function ContactSection({
<div className="module-SafetyNumberChangeDialog__row__story-name"> <div className="module-SafetyNumberChangeDialog__row__story-name">
{sectionName} {sectionName}
</div> </div>
{distributionId && removeFromStory && uuids.length > 1 && ( {distributionId && removeFromStory && serviceIds.length > 1 && (
<SectionButtonWithMenu <SectionButtonWithMenu
ariaLabel={i18n('icu:safetyNumberChangeDialog__actions-story', { ariaLabel={i18n('icu:safetyNumberChangeDialog__actions-story', {
story: sectionName, story: sectionName,
})} })}
i18n={i18n} i18n={i18n}
memberCount={uuids.length} memberCount={serviceIds.length}
storyName={sectionName} storyName={sectionName}
theme={theme} theme={theme}
removeFromStory={() => { removeFromStory={() => {
removeFromStory(distributionId, uuids); removeFromStory(distributionId, serviceIds);
}} }}
/> />
)} )}
@ -443,7 +445,7 @@ function ContactRow({
shouldShowNumber: boolean; shouldShowNumber: boolean;
theme: ThemeType; theme: ThemeType;
}>) { }>) {
const { uuid } = contact; const { serviceId } = contact;
return ( return (
<li className="module-SafetyNumberChangeDialog__row" key={contact.id}> <li className="module-SafetyNumberChangeDialog__row" key={contact.id}>
@ -493,14 +495,14 @@ function ContactRow({
</div> </div>
) : null} ) : null}
</div> </div>
{distributionId && removeFromStory && uuid ? ( {distributionId && removeFromStory && serviceId ? (
<RowButtonWithMenu <RowButtonWithMenu
ariaLabel={i18n('icu:safetyNumberChangeDialog__actions-contact', { ariaLabel={i18n('icu:safetyNumberChangeDialog__actions-contact', {
contact: contact.title, contact: contact.title,
})} })}
i18n={i18n} i18n={i18n}
theme={theme} theme={theme}
removeFromStory={() => removeFromStory(distributionId, [uuid])} removeFromStory={() => removeFromStory(distributionId, [serviceId])}
verifyContact={() => setSelectedContact(contact)} verifyContact={() => setSelectedContact(contact)}
/> />
) : ( ) : (

View file

@ -59,7 +59,7 @@ export type PropsType = {
onDeleteList: (listId: StoryDistributionIdString) => unknown; onDeleteList: (listId: StoryDistributionIdString) => unknown;
onDistributionListCreated: ( onDistributionListCreated: (
name: string, name: string,
viewerUuids: Array<ServiceIdString> viewerServiceIds: Array<ServiceIdString>
) => Promise<StoryDistributionIdString>; ) => Promise<StoryDistributionIdString>;
onSelectedStoryList: (options: { onSelectedStoryList: (options: {
conversationId: string; conversationId: string;
@ -107,15 +107,15 @@ function getListMemberServiceIds(
signalConnections: Array<ConversationType> signalConnections: Array<ConversationType>
): Array<ServiceIdString> { ): Array<ServiceIdString> {
const memberServiceIds = list.members const memberServiceIds = list.members
.map(({ uuid }) => uuid) .map(({ serviceId }) => serviceId)
.filter(isNotNil); .filter(isNotNil);
if (list.id === MY_STORY_ID && list.isBlockList) { if (list.id === MY_STORY_ID && list.isBlockList) {
const excludeUuids = new Set<string>(memberServiceIds); const excludeServiceIds = new Set<ServiceIdString>(memberServiceIds);
return signalConnections return signalConnections
.map(conversation => conversation.uuid) .map(conversation => conversation.serviceId)
.filter(isNotNil) .filter(isNotNil)
.filter(uuid => !excludeUuids.has(uuid)); .filter(serviceId => !excludeServiceIds.has(serviceId));
} }
return memberServiceIds; return memberServiceIds;
@ -242,7 +242,7 @@ export function SendStoryModal({
return distributionLists.find(list => list.id === listIdToEdit); return distributionLists.find(list => list.id === listIdToEdit);
}, [distributionLists, listIdToEdit]); }, [distributionLists, listIdToEdit]);
// myStoriesPrivacy, myStoriesPrivacyUuids, and myStories are only used // myStoriesPrivacy, myStoriesPrivacyServiceIds, and myStories are only used
// during the first time posting to My Stories experience where we have // during the first time posting to My Stories experience where we have
// to select the privacy settings. // to select the privacy settings.
const ogMyStories = useMemo( const ogMyStories = useMemo(
@ -310,18 +310,18 @@ export function SendStoryModal({
</Button> </Button>
<Button <Button
onClick={() => { onClick={() => {
const uuids = stagedMyStories.members const serviceIds = stagedMyStories.members
.map(convo => convo.uuid) .map(convo => convo.serviceId)
.filter(isNotNil); .filter(isNotNil);
if (stagedMyStories.isBlockList) { if (stagedMyStories.isBlockList) {
if (stagedMyStories.members.length) { if (stagedMyStories.members.length) {
onHideMyStoriesFrom(uuids); onHideMyStoriesFrom(serviceIds);
} else { } else {
setMyStoriesToAllSignalConnections(); setMyStoriesToAllSignalConnections();
} }
} else { } else {
onViewersUpdated(MY_STORY_ID, uuids); onViewersUpdated(MY_STORY_ID, serviceIds);
} }
setSelectedContacts([]); setSelectedContacts([]);
@ -425,10 +425,10 @@ export function SendStoryModal({
candidateConversations={candidateConversations} candidateConversations={candidateConversations}
getPreferredBadge={getPreferredBadge} getPreferredBadge={getPreferredBadge}
i18n={i18n} i18n={i18n}
onCreateList={async (name, uuids) => { onCreateList={async (name, serviceIds) => {
const newDistributionListId = await onDistributionListCreated( const newDistributionListId = await onDistributionListCreated(
name, name,
uuids serviceIds
); );
setSelectedContacts([]); setSelectedContacts([]);
@ -438,19 +438,19 @@ export function SendStoryModal({
setPage(Page.SendStory); setPage(Page.SendStory);
}} }}
onViewersUpdated={uuids => { onViewersUpdated={serviceIds => {
if (listIdToEdit && page === Page.AddViewer) { if (listIdToEdit && page === Page.AddViewer) {
onViewersUpdated(listIdToEdit, uuids); onViewersUpdated(listIdToEdit, serviceIds);
setPage(Page.EditingDistributionList); setPage(Page.EditingDistributionList);
} else if (page === Page.ChooseViewers) { } else if (page === Page.ChooseViewers) {
setPage(Page.NameStory); setPage(Page.NameStory);
} else if (listIdToEdit && page === Page.HideStoryFrom) { } else if (listIdToEdit && page === Page.HideStoryFrom) {
onHideMyStoriesFrom(uuids); onHideMyStoriesFrom(serviceIds);
setPage(Page.SendStory); setPage(Page.SendStory);
} else if (page === Page.HideStoryFrom || page === Page.AddViewer) { } else if (page === Page.HideStoryFrom || page === Page.AddViewer) {
const uuidsSet = new Set(uuids); const serviceIdSet = new Set(serviceIds);
const members = candidateConversations.filter(convo => const members = candidateConversations.filter(convo =>
convo.uuid ? uuidsSet.has(convo.uuid) : false convo.serviceId ? serviceIdSet.has(convo.serviceId) : false
); );
setStagedMyStories(myStories => ({ setStagedMyStories(myStories => ({
...myStories, ...myStories,
@ -800,7 +800,7 @@ export function SendStoryModal({
onSelectedStoryList({ onSelectedStoryList({
conversationId: group.id, conversationId: group.id,
distributionId: undefined, distributionId: undefined,
serviceIds: group.memberships.map(({ uuid }) => uuid), serviceIds: group.memberships.map(({ aci }) => aci),
}); });
} }
}} }}

View file

@ -54,7 +54,7 @@ export default {
setMyStoriesToAllSignalConnections: { action: true }, setMyStoriesToAllSignalConnections: { action: true },
toggleSignalConnectionsModal: { action: true }, toggleSignalConnectionsModal: { action: true },
setStoriesDisabled: { action: true }, setStoriesDisabled: { action: true },
getConversationByUuid: { getConversationByServiceId: {
defaultValue: () => getDefaultGroup(), defaultValue: () => getDefaultGroup(),
}, },
}, },

View file

@ -52,25 +52,28 @@ export type PropsType = {
toggleGroupsForStorySend: (groupIds: Array<string>) => unknown; toggleGroupsForStorySend: (groupIds: Array<string>) => unknown;
onDistributionListCreated: ( onDistributionListCreated: (
name: string, name: string,
viewerUuids: Array<ServiceIdString> viewerServiceIds: Array<ServiceIdString>
) => Promise<string>; ) => Promise<string>;
onHideMyStoriesFrom: (viewerUuids: Array<ServiceIdString>) => unknown; onHideMyStoriesFrom: (viewerServiceIds: Array<ServiceIdString>) => unknown;
onRemoveMembers: (listId: string, uuids: Array<ServiceIdString>) => unknown; onRemoveMembers: (
listId: string,
serviceIds: Array<ServiceIdString>
) => unknown;
onRepliesNReactionsChanged: ( onRepliesNReactionsChanged: (
listId: string, listId: string,
allowsReplies: boolean allowsReplies: boolean
) => unknown; ) => unknown;
onViewersUpdated: ( onViewersUpdated: (
listId: string, listId: string,
viewerUuids: Array<ServiceIdString> viewerServiceIds: Array<ServiceIdString>
) => unknown; ) => unknown;
setMyStoriesToAllSignalConnections: () => unknown; setMyStoriesToAllSignalConnections: () => unknown;
storyViewReceiptsEnabled: boolean; storyViewReceiptsEnabled: boolean;
theme: ThemeType; theme: ThemeType;
toggleSignalConnectionsModal: () => unknown; toggleSignalConnectionsModal: () => unknown;
setStoriesDisabled: (value: boolean) => void; setStoriesDisabled: (value: boolean) => void;
getConversationByUuid: ( getConversationByServiceId: (
uuid: ServiceIdString serviceId: ServiceIdString
) => ConversationType | undefined; ) => ConversationType | undefined;
}; };
@ -90,7 +93,7 @@ function filterConversations(
conversations, conversations,
searchTerm, searchTerm,
undefined undefined
).filter(conversation => conversation.uuid); ).filter(conversation => conversation.serviceId);
} }
const modalCommonProps: Pick<ModalPropsType, 'hasXButton' | 'moduleClassName'> = const modalCommonProps: Pick<ModalPropsType, 'hasXButton' | 'moduleClassName'> =
@ -258,7 +261,7 @@ export function StoriesSettingsModal({
toggleSignalConnectionsModal, toggleSignalConnectionsModal,
theme, theme,
setStoriesDisabled, setStoriesDisabled,
getConversationByUuid, getConversationByServiceId,
}: PropsType): JSX.Element { }: PropsType): JSX.Element {
const [confirmDiscardModal, confirmDiscardIf] = useConfirmDiscard(i18n); const [confirmDiscardModal, confirmDiscardIf] = useConfirmDiscard(i18n);
@ -311,8 +314,8 @@ export function StoriesSettingsModal({
i18n={i18n} i18n={i18n}
page={page} page={page}
onClose={onClose} onClose={onClose}
onCreateList={(name, uuids) => { onCreateList={(name, serviceIds) => {
void onDistributionListCreated(name, uuids); void onDistributionListCreated(name, serviceIds);
resetChooseViewersScreen(); resetChooseViewersScreen();
}} }}
onBackButtonClick={() => onBackButtonClick={() =>
@ -330,9 +333,9 @@ export function StoriesSettingsModal({
} }
}) })
} }
onViewersUpdated={uuids => { onViewersUpdated={serviceIds => {
if (listToEditId && page === Page.AddViewer) { if (listToEditId && page === Page.AddViewer) {
onViewersUpdated(listToEditId, uuids); onViewersUpdated(listToEditId, serviceIds);
resetChooseViewersScreen(); resetChooseViewersScreen();
} }
@ -341,7 +344,7 @@ export function StoriesSettingsModal({
} }
if (page === Page.HideStoryFrom) { if (page === Page.HideStoryFrom) {
onHideMyStoriesFrom(uuids); onHideMyStoriesFrom(serviceIds);
resetChooseViewersScreen(); resetChooseViewersScreen();
} }
}} }}
@ -377,7 +380,7 @@ export function StoriesSettingsModal({
group={groupToView} group={groupToView}
onClose={onClose} onClose={onClose}
onBackButtonClick={() => setGroupToViewId(null)} onBackButtonClick={() => setGroupToViewId(null)}
getConversationByUuid={getConversationByUuid} getConversationByServiceId={getConversationByServiceId}
onRemoveGroup={group => { onRemoveGroup={group => {
setConfirmRemoveGroup({ setConfirmRemoveGroup({
id: group.id, id: group.id,
@ -583,7 +586,7 @@ export function DistributionListSettingsModal({
| { | {
listId: string; listId: string;
title: string; title: string;
uuid: ServiceIdString; serviceId: ServiceIdString;
} }
>(); >();
@ -695,11 +698,14 @@ export function DistributionListSettingsModal({
})} })}
className="StoriesSettingsModal__list__delete" className="StoriesSettingsModal__list__delete"
onClick={() => { onClick={() => {
strictAssert(member.uuid, 'Story member was missing uuid'); strictAssert(
member.serviceId,
'Story member was missing service id'
);
setConfirmRemoveMember({ setConfirmRemoveMember({
listId: listToEdit.id, listId: listToEdit.id,
title: member.title, title: member.title,
uuid: member.uuid, serviceId: member.serviceId,
}); });
}} }}
type="button" type="button"
@ -747,7 +753,7 @@ export function DistributionListSettingsModal({
{ {
action: () => action: () =>
onRemoveMembers(confirmRemoveMember.listId, [ onRemoveMembers(confirmRemoveMember.listId, [
confirmRemoveMember.uuid, confirmRemoveMember.serviceId,
]), ]),
style: 'negative', style: 'negative',
text: i18n('icu:StoriesSettings__remove--action'), text: i18n('icu:StoriesSettings__remove--action'),
@ -950,8 +956,11 @@ export function EditMyStoryPrivacy({
} }
type EditDistributionListModalPropsType = { type EditDistributionListModalPropsType = {
onCreateList: (name: string, viewerUuids: Array<ServiceIdString>) => unknown; onCreateList: (
onViewersUpdated: (viewerUuids: Array<ServiceIdString>) => unknown; name: string,
viewerServiceIds: Array<ServiceIdString>
) => unknown;
onViewersUpdated: (viewerServiceIds: Array<ServiceIdString>) => unknown;
page: page:
| Page.AddViewer | Page.AddViewer
| Page.ChooseViewers | Page.ChooseViewers
@ -1007,7 +1016,9 @@ export function EditDistributionListModal({
const selectConversationServiceIds: Set<ServiceIdString> = useMemo( const selectConversationServiceIds: Set<ServiceIdString> = useMemo(
() => () =>
new Set(selectedContacts.map(contact => contact.uuid).filter(isNotNil)), new Set(
selectedContacts.map(contact => contact.serviceId).filter(isNotNil)
),
[selectedContacts] [selectedContacts]
); );
@ -1108,11 +1119,11 @@ export function EditDistributionListModal({
const rowCount = filteredConversations.length; const rowCount = filteredConversations.length;
const getRow = (index: number): undefined | Row => { const getRow = (index: number): undefined | Row => {
const contact = filteredConversations[index]; const contact = filteredConversations[index];
if (!contact || !contact.uuid) { if (!contact || !contact.serviceId) {
return undefined; return undefined;
} }
const isSelected = selectConversationServiceIds.has(contact.uuid); const isSelected = selectConversationServiceIds.has(contact.serviceId);
return { return {
type: RowType.ContactCheckbox, type: RowType.ContactCheckbox,
@ -1243,7 +1254,9 @@ type GroupStorySettingsModalProps = {
group: ConversationType; group: ConversationType;
onClose(): void; onClose(): void;
onBackButtonClick(): void; onBackButtonClick(): void;
getConversationByUuid(uuid: ServiceIdString): ConversationType | undefined; getConversationByServiceId(
serviceId: ServiceIdString
): ConversationType | undefined;
onRemoveGroup(group: ConversationType): void; onRemoveGroup(group: ConversationType): void;
}; };
@ -1252,10 +1265,13 @@ export function GroupStorySettingsModal({
group, group,
onClose, onClose,
onBackButtonClick, onBackButtonClick,
getConversationByUuid, getConversationByServiceId,
onRemoveGroup, onRemoveGroup,
}: GroupStorySettingsModalProps): JSX.Element { }: GroupStorySettingsModalProps): JSX.Element {
const groupMemberships = getGroupMemberships(group, getConversationByUuid); const groupMemberships = getGroupMemberships(
group,
getConversationByServiceId
);
return ( return (
<ModalPage <ModalPage
modalName="GroupStorySettingsModal" modalName="GroupStorySettingsModal"

View file

@ -103,7 +103,7 @@ export function StoryListItem({
const { firstName, title } = sender; const { firstName, title } = sender;
const isSignalOfficial = sender.uuid === SIGNAL_ACI; const isSignalOfficial = sender.serviceId === SIGNAL_ACI;
let avatarStoryRing: HasStories | undefined; let avatarStoryRing: HasStories | undefined;
if (attachment) { if (attachment) {

View file

@ -40,21 +40,21 @@ export function MultipleMentions(): JSX.Element {
{ {
start: 4, start: 4,
length: 1, length: 1,
mentionUuid: SERVICE_ID_1, mentionAci: SERVICE_ID_1,
replacementText: 'Professor Farnsworth', replacementText: 'Professor Farnsworth',
conversationID: 'x', conversationID: 'x',
}, },
{ {
start: 2, start: 2,
length: 1, length: 1,
mentionUuid: SERVICE_ID_2, mentionAci: SERVICE_ID_2,
replacementText: 'Philip J Fry', replacementText: 'Philip J Fry',
conversationID: 'x', conversationID: 'x',
}, },
{ {
start: 0, start: 0,
length: 1, length: 1,
mentionUuid: SERVICE_ID_3, mentionAci: SERVICE_ID_3,
replacementText: 'Yancy Fry', replacementText: 'Yancy Fry',
conversationID: 'x', conversationID: 'x',
}, },
@ -73,21 +73,21 @@ export function ComplexMentions(): JSX.Element {
{ {
start: 80, start: 80,
length: 1, length: 1,
mentionUuid: SERVICE_ID_4, mentionAci: SERVICE_ID_4,
replacementText: 'Cereal Killer', replacementText: 'Cereal Killer',
conversationID: 'x', conversationID: 'x',
}, },
{ {
start: 78, start: 78,
length: 1, length: 1,
mentionUuid: SERVICE_ID_5, mentionAci: SERVICE_ID_5,
replacementText: 'Acid Burn', replacementText: 'Acid Burn',
conversationID: 'x', conversationID: 'x',
}, },
{ {
start: 4, start: 4,
length: 1, length: 1,
mentionUuid: SERVICE_ID_6, mentionAci: SERVICE_ID_6,
replacementText: 'Zero Cool', replacementText: 'Zero Cool',
conversationID: 'x', conversationID: 'x',
}, },
@ -109,7 +109,7 @@ export function WithOddCharacter(): JSX.Element {
{ {
start: 4, start: 4,
length: 1, length: 1,
mentionUuid: SERVICE_ID_6, mentionAci: SERVICE_ID_6,
replacementText: 'Zero Cool', replacementText: 'Zero Cool',
conversationID: 'x', conversationID: 'x',
}, },

View file

@ -45,7 +45,7 @@ const getCommonProps = (options: {
? GroupCallStatus.GenericGroupCall ? GroupCallStatus.GenericGroupCall
: DirectCallStatus.Pending, : DirectCallStatus.Pending,
callCreator = getDefaultConversation({ callCreator = getDefaultConversation({
uuid: generateAci(), serviceId: generateAci(),
isMe: direction === CallDirection.Outgoing, isMe: direction === CallDirection.Outgoing,
}), }),
callExternalState = CallExternalState.Active, callExternalState = CallExternalState.Active,
@ -63,7 +63,7 @@ const getCommonProps = (options: {
callHistory: { callHistory: {
callId: '123', callId: '123',
peerId: conversation.id, peerId: conversation.id,
ringerId: callCreator?.uuid ?? null, ringerId: callCreator?.serviceId ?? null,
mode, mode,
type, type,
direction, direction,

View file

@ -44,7 +44,7 @@ const renderChange = (
areWeAdmin = true, areWeAdmin = true,
}: { }: {
groupMemberships?: ReadonlyArray<{ groupMemberships?: ReadonlyArray<{
uuid: AciString; aci: AciString;
isAdmin: boolean; isAdmin: boolean;
}>; }>;
groupBannedMemberships?: ReadonlyArray<ServiceIdString>; groupBannedMemberships?: ReadonlyArray<ServiceIdString>;
@ -92,7 +92,7 @@ export function Multiple(): JSX.Element {
}, },
{ {
type: 'member-add', type: 'member-add',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
{ {
type: 'description', type: 'description',
@ -100,7 +100,7 @@ export function Multiple(): JSX.Element {
}, },
{ {
type: 'member-privilege', type: 'member-privilege',
uuid: OUR_ACI, aci: OUR_ACI,
newPrivilege: RoleEnum.ADMINISTRATOR, newPrivilege: RoleEnum.ADMINISTRATOR,
}, },
], ],
@ -451,7 +451,7 @@ export function MemberAdd(): JSX.Element {
details: [ details: [
{ {
type: 'member-add', type: 'member-add',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -460,7 +460,7 @@ export function MemberAdd(): JSX.Element {
details: [ details: [
{ {
type: 'member-add', type: 'member-add',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -468,7 +468,7 @@ export function MemberAdd(): JSX.Element {
details: [ details: [
{ {
type: 'member-add', type: 'member-add',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -477,7 +477,7 @@ export function MemberAdd(): JSX.Element {
details: [ details: [
{ {
type: 'member-add', type: 'member-add',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -486,7 +486,7 @@ export function MemberAdd(): JSX.Element {
details: [ details: [
{ {
type: 'member-add', type: 'member-add',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -494,7 +494,7 @@ export function MemberAdd(): JSX.Element {
details: [ details: [
{ {
type: 'member-add', type: 'member-add',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -511,7 +511,7 @@ export function MemberAddFromInvited(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-invite', type: 'member-add-from-invite',
uuid: OUR_ACI, aci: OUR_ACI,
inviter: CONTACT_B, inviter: CONTACT_B,
}, },
], ],
@ -520,7 +520,7 @@ export function MemberAddFromInvited(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-invite', type: 'member-add-from-invite',
uuid: OUR_ACI, aci: OUR_ACI,
inviter: CONTACT_A, inviter: CONTACT_A,
}, },
], ],
@ -531,7 +531,7 @@ export function MemberAddFromInvited(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-invite', type: 'member-add-from-invite',
uuid: CONTACT_A, aci: CONTACT_A,
inviter: CONTACT_B, inviter: CONTACT_B,
}, },
], ],
@ -541,7 +541,7 @@ export function MemberAddFromInvited(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-invite', type: 'member-add-from-invite',
uuid: CONTACT_B, aci: CONTACT_B,
inviter: CONTACT_C, inviter: CONTACT_C,
}, },
], ],
@ -550,7 +550,7 @@ export function MemberAddFromInvited(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-invite', type: 'member-add-from-invite',
uuid: CONTACT_A, aci: CONTACT_A,
inviter: CONTACT_B, inviter: CONTACT_B,
}, },
], ],
@ -561,7 +561,7 @@ export function MemberAddFromInvited(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-invite', type: 'member-add-from-invite',
uuid: OUR_ACI, aci: OUR_ACI,
inviter: CONTACT_A, inviter: CONTACT_A,
}, },
], ],
@ -571,7 +571,7 @@ export function MemberAddFromInvited(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-invite', type: 'member-add-from-invite',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -580,7 +580,7 @@ export function MemberAddFromInvited(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-invite', type: 'member-add-from-invite',
uuid: CONTACT_A, aci: CONTACT_A,
inviter: OUR_ACI, inviter: OUR_ACI,
}, },
], ],
@ -590,7 +590,7 @@ export function MemberAddFromInvited(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-invite', type: 'member-add-from-invite',
uuid: CONTACT_A, aci: CONTACT_A,
inviter: CONTACT_B, inviter: CONTACT_B,
}, },
], ],
@ -600,7 +600,7 @@ export function MemberAddFromInvited(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-invite', type: 'member-add-from-invite',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -610,7 +610,7 @@ export function MemberAddFromInvited(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-invite', type: 'member-add-from-invite',
uuid: OUR_ACI, aci: OUR_ACI,
inviter: CONTACT_B, inviter: CONTACT_B,
}, },
], ],
@ -631,7 +631,7 @@ export function MemberAddFromLink(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-link', type: 'member-add-from-link',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -640,7 +640,7 @@ export function MemberAddFromLink(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-link', type: 'member-add-from-link',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -648,7 +648,7 @@ export function MemberAddFromLink(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-link', type: 'member-add-from-link',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -668,7 +668,7 @@ export function MemberAddFromAdminApproval(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-admin-approval', type: 'member-add-from-admin-approval',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -676,7 +676,7 @@ export function MemberAddFromAdminApproval(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-admin-approval', type: 'member-add-from-admin-approval',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -685,7 +685,7 @@ export function MemberAddFromAdminApproval(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-admin-approval', type: 'member-add-from-admin-approval',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -694,7 +694,7 @@ export function MemberAddFromAdminApproval(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-admin-approval', type: 'member-add-from-admin-approval',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -702,7 +702,7 @@ export function MemberAddFromAdminApproval(): JSX.Element {
details: [ details: [
{ {
type: 'member-add-from-admin-approval', type: 'member-add-from-admin-approval',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -722,7 +722,7 @@ export function MemberRemove(): JSX.Element {
details: [ details: [
{ {
type: 'member-remove', type: 'member-remove',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -731,7 +731,7 @@ export function MemberRemove(): JSX.Element {
details: [ details: [
{ {
type: 'member-remove', type: 'member-remove',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -739,7 +739,7 @@ export function MemberRemove(): JSX.Element {
details: [ details: [
{ {
type: 'member-remove', type: 'member-remove',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -748,7 +748,7 @@ export function MemberRemove(): JSX.Element {
details: [ details: [
{ {
type: 'member-remove', type: 'member-remove',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -757,7 +757,7 @@ export function MemberRemove(): JSX.Element {
details: [ details: [
{ {
type: 'member-remove', type: 'member-remove',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -766,7 +766,7 @@ export function MemberRemove(): JSX.Element {
details: [ details: [
{ {
type: 'member-remove', type: 'member-remove',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -774,7 +774,7 @@ export function MemberRemove(): JSX.Element {
details: [ details: [
{ {
type: 'member-remove', type: 'member-remove',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -790,7 +790,7 @@ export function MemberPrivilege(): JSX.Element {
details: [ details: [
{ {
type: 'member-privilege', type: 'member-privilege',
uuid: OUR_ACI, aci: OUR_ACI,
newPrivilege: RoleEnum.ADMINISTRATOR, newPrivilege: RoleEnum.ADMINISTRATOR,
}, },
], ],
@ -799,7 +799,7 @@ export function MemberPrivilege(): JSX.Element {
details: [ details: [
{ {
type: 'member-privilege', type: 'member-privilege',
uuid: OUR_ACI, aci: OUR_ACI,
newPrivilege: RoleEnum.ADMINISTRATOR, newPrivilege: RoleEnum.ADMINISTRATOR,
}, },
], ],
@ -809,7 +809,7 @@ export function MemberPrivilege(): JSX.Element {
details: [ details: [
{ {
type: 'member-privilege', type: 'member-privilege',
uuid: CONTACT_A, aci: CONTACT_A,
newPrivilege: RoleEnum.ADMINISTRATOR, newPrivilege: RoleEnum.ADMINISTRATOR,
}, },
], ],
@ -819,7 +819,7 @@ export function MemberPrivilege(): JSX.Element {
details: [ details: [
{ {
type: 'member-privilege', type: 'member-privilege',
uuid: CONTACT_A, aci: CONTACT_A,
newPrivilege: RoleEnum.ADMINISTRATOR, newPrivilege: RoleEnum.ADMINISTRATOR,
}, },
], ],
@ -828,7 +828,7 @@ export function MemberPrivilege(): JSX.Element {
details: [ details: [
{ {
type: 'member-privilege', type: 'member-privilege',
uuid: CONTACT_A, aci: CONTACT_A,
newPrivilege: RoleEnum.ADMINISTRATOR, newPrivilege: RoleEnum.ADMINISTRATOR,
}, },
], ],
@ -838,7 +838,7 @@ export function MemberPrivilege(): JSX.Element {
details: [ details: [
{ {
type: 'member-privilege', type: 'member-privilege',
uuid: OUR_ACI, aci: OUR_ACI,
newPrivilege: RoleEnum.DEFAULT, newPrivilege: RoleEnum.DEFAULT,
}, },
], ],
@ -847,7 +847,7 @@ export function MemberPrivilege(): JSX.Element {
details: [ details: [
{ {
type: 'member-privilege', type: 'member-privilege',
uuid: OUR_ACI, aci: OUR_ACI,
newPrivilege: RoleEnum.DEFAULT, newPrivilege: RoleEnum.DEFAULT,
}, },
], ],
@ -857,7 +857,7 @@ export function MemberPrivilege(): JSX.Element {
details: [ details: [
{ {
type: 'member-privilege', type: 'member-privilege',
uuid: CONTACT_A, aci: CONTACT_A,
newPrivilege: RoleEnum.DEFAULT, newPrivilege: RoleEnum.DEFAULT,
}, },
], ],
@ -867,7 +867,7 @@ export function MemberPrivilege(): JSX.Element {
details: [ details: [
{ {
type: 'member-privilege', type: 'member-privilege',
uuid: CONTACT_A, aci: CONTACT_A,
newPrivilege: RoleEnum.DEFAULT, newPrivilege: RoleEnum.DEFAULT,
}, },
], ],
@ -876,7 +876,7 @@ export function MemberPrivilege(): JSX.Element {
details: [ details: [
{ {
type: 'member-privilege', type: 'member-privilege',
uuid: CONTACT_A, aci: CONTACT_A,
newPrivilege: RoleEnum.DEFAULT, newPrivilege: RoleEnum.DEFAULT,
}, },
], ],
@ -893,7 +893,7 @@ export function PendingAddOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-add-one', type: 'pending-add-one',
uuid: OUR_ACI, serviceId: OUR_ACI,
}, },
], ],
})} })}
@ -901,7 +901,7 @@ export function PendingAddOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-add-one', type: 'pending-add-one',
uuid: OUR_ACI, serviceId: OUR_ACI,
}, },
], ],
})} })}
@ -910,7 +910,7 @@ export function PendingAddOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-add-one', type: 'pending-add-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
}, },
], ],
})} })}
@ -919,7 +919,7 @@ export function PendingAddOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-add-one', type: 'pending-add-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
}, },
], ],
})} })}
@ -927,7 +927,7 @@ export function PendingAddOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-add-one', type: 'pending-add-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
}, },
], ],
})} })}
@ -984,7 +984,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
inviter: OUR_ACI, inviter: OUR_ACI,
}, },
], ],
@ -994,7 +994,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
inviter: OUR_ACI, inviter: OUR_ACI,
}, },
], ],
@ -1004,7 +1004,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
inviter: OUR_ACI, inviter: OUR_ACI,
}, },
], ],
@ -1013,7 +1013,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
inviter: OUR_ACI, inviter: OUR_ACI,
}, },
], ],
@ -1023,7 +1023,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
}, },
], ],
})} })}
@ -1032,7 +1032,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
inviter: CONTACT_B, inviter: CONTACT_B,
}, },
], ],
@ -1043,7 +1043,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: OUR_ACI, serviceId: OUR_ACI,
inviter: CONTACT_B, inviter: CONTACT_B,
}, },
], ],
@ -1053,7 +1053,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: CONTACT_B, serviceId: CONTACT_B,
inviter: CONTACT_A, inviter: CONTACT_A,
}, },
], ],
@ -1064,7 +1064,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
inviter: CONTACT_B, inviter: CONTACT_B,
}, },
], ],
@ -1074,7 +1074,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
inviter: CONTACT_B, inviter: CONTACT_B,
}, },
], ],
@ -1083,7 +1083,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
inviter: CONTACT_B, inviter: CONTACT_B,
}, },
], ],
@ -1094,7 +1094,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
}, },
], ],
})} })}
@ -1103,7 +1103,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
}, },
], ],
})} })}
@ -1111,7 +1111,7 @@ export function PendingRemoveOne(): JSX.Element {
details: [ details: [
{ {
type: 'pending-remove-one', type: 'pending-remove-one',
uuid: INVITEE_A, serviceId: INVITEE_A,
}, },
], ],
})} })}
@ -1226,7 +1226,7 @@ export function AdminApprovalAdd(): JSX.Element {
details: [ details: [
{ {
type: 'admin-approval-add-one', type: 'admin-approval-add-one',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -1234,7 +1234,7 @@ export function AdminApprovalAdd(): JSX.Element {
details: [ details: [
{ {
type: 'admin-approval-add-one', type: 'admin-approval-add-one',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -1254,7 +1254,7 @@ export function AdminApprovalRemove(): JSX.Element {
details: [ details: [
{ {
type: 'admin-approval-remove-one', type: 'admin-approval-remove-one',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -1262,7 +1262,7 @@ export function AdminApprovalRemove(): JSX.Element {
details: [ details: [
{ {
type: 'admin-approval-remove-one', type: 'admin-approval-remove-one',
uuid: OUR_ACI, aci: OUR_ACI,
}, },
], ],
})} })}
@ -1271,7 +1271,7 @@ export function AdminApprovalRemove(): JSX.Element {
details: [ details: [
{ {
type: 'admin-approval-remove-one', type: 'admin-approval-remove-one',
uuid: CONTACT_A, aci: CONTACT_A,
}, },
], ],
})} })}
@ -1294,14 +1294,14 @@ export function AdminApprovalBounce(): JSX.Element {
details: [ details: [
{ {
type: 'admin-approval-bounce', type: 'admin-approval-bounce',
uuid: CONTACT_A, aci: CONTACT_A,
times: 1, times: 1,
isApprovalPending: false, isApprovalPending: false,
}, },
], ],
}, },
{ {
groupMemberships: [{ uuid: CONTACT_C, isAdmin: false }], groupMemberships: [{ aci: CONTACT_C, isAdmin: false }],
groupBannedMemberships: [CONTACT_B], groupBannedMemberships: [CONTACT_B],
} }
)} )}
@ -1311,14 +1311,14 @@ export function AdminApprovalBounce(): JSX.Element {
details: [ details: [
{ {
type: 'admin-approval-bounce', type: 'admin-approval-bounce',
uuid: CONTACT_A, aci: CONTACT_A,
times: 1, times: 1,
isApprovalPending: false, isApprovalPending: false,
}, },
], ],
}, },
{ {
groupMemberships: [{ uuid: CONTACT_C, isAdmin: false }], groupMemberships: [{ aci: CONTACT_C, isAdmin: false }],
groupBannedMemberships: [CONTACT_B], groupBannedMemberships: [CONTACT_B],
} }
)} )}
@ -1326,7 +1326,7 @@ export function AdminApprovalBounce(): JSX.Element {
details: [ details: [
{ {
type: 'admin-approval-bounce', type: 'admin-approval-bounce',
uuid: CONTACT_A, aci: CONTACT_A,
times: 1, times: 1,
isApprovalPending: false, isApprovalPending: false,
}, },
@ -1340,7 +1340,7 @@ export function AdminApprovalBounce(): JSX.Element {
details: [ details: [
{ {
type: 'admin-approval-bounce', type: 'admin-approval-bounce',
uuid: CONTACT_A, aci: CONTACT_A,
times: 1, times: 1,
isApprovalPending: false, isApprovalPending: false,
}, },
@ -1356,13 +1356,13 @@ export function AdminApprovalBounce(): JSX.Element {
details: [ details: [
{ {
type: 'admin-approval-bounce', type: 'admin-approval-bounce',
uuid: CONTACT_A, aci: CONTACT_A,
times: 1, times: 1,
isApprovalPending: false, isApprovalPending: false,
}, },
], ],
}, },
{ groupMemberships: [{ uuid: CONTACT_A, isAdmin: false }] } { groupMemberships: [{ aci: CONTACT_A, isAdmin: false }] }
)} )}
Would show button, but user is already banned: Would show button, but user is already banned:
{renderChange( {renderChange(
@ -1371,7 +1371,7 @@ export function AdminApprovalBounce(): JSX.Element {
details: [ details: [
{ {
type: 'admin-approval-bounce', type: 'admin-approval-bounce',
uuid: CONTACT_A, aci: CONTACT_A,
times: 1, times: 1,
isApprovalPending: false, isApprovalPending: false,
}, },

View file

@ -30,7 +30,7 @@ export type PropsDataType = {
areWeAdmin: boolean; areWeAdmin: boolean;
conversationId: string; conversationId: string;
groupMemberships?: ReadonlyArray<{ groupMemberships?: ReadonlyArray<{
uuid: AciString; aci: AciString;
isAdmin: boolean; isAdmin: boolean;
}>; }>;
groupBannedMemberships?: ReadonlyArray<ServiceIdString>; groupBannedMemberships?: ReadonlyArray<ServiceIdString>;
@ -116,7 +116,7 @@ function getIcon(
): GroupIconType { ): GroupIconType {
const changeType = detail.type; const changeType = detail.type;
let possibleIcon = changeToIconMap.get(changeType); let possibleIcon = changeToIconMap.get(changeType);
const isSameId = fromId === get(detail, 'uuid', null); const isSameId = fromId === get(detail, 'aci', null);
if (isSameId) { if (isSameId) {
if (changeType === 'member-remove') { if (changeType === 'member-remove') {
possibleIcon = 'group-leave'; possibleIcon = 'group-leave';
@ -154,13 +154,13 @@ function GroupV2Detail({
areWeAdmin: boolean; areWeAdmin: boolean;
blockGroupLinkRequests: ( blockGroupLinkRequests: (
conversationId: string, conversationId: string,
uuid: ServiceIdString serviceId: ServiceIdString
) => unknown; ) => unknown;
conversationId: string; conversationId: string;
detail: GroupV2ChangeDetailType; detail: GroupV2ChangeDetailType;
isLastText: boolean; isLastText: boolean;
groupMemberships?: ReadonlyArray<{ groupMemberships?: ReadonlyArray<{
uuid: AciString; aci: AciString;
isAdmin: boolean; isAdmin: boolean;
}>; }>;
groupBannedMemberships?: ReadonlyArray<ServiceIdString>; groupBannedMemberships?: ReadonlyArray<ServiceIdString>;
@ -206,10 +206,10 @@ function GroupV2Detail({
if ( if (
!isLastText || !isLastText ||
detail.type !== 'admin-approval-bounce' || detail.type !== 'admin-approval-bounce' ||
!detail.uuid !detail.aci
) { ) {
log.warn( log.warn(
'GroupV2Detail: ConfirmingblockGroupLinkRequests but missing uuid or wrong change type' 'GroupV2Detail: ConfirmingblockGroupLinkRequests but missing aci or wrong change type'
); );
modalNode = undefined; modalNode = undefined;
break; break;
@ -221,7 +221,7 @@ function GroupV2Detail({
title={i18n('icu:PendingRequests--block--title')} title={i18n('icu:PendingRequests--block--title')}
actions={[ actions={[
{ {
action: () => blockGroupLinkRequests(conversationId, detail.uuid), action: () => blockGroupLinkRequests(conversationId, detail.aci),
text: i18n('icu:PendingRequests--block--confirm'), text: i18n('icu:PendingRequests--block--confirm'),
style: 'affirmative', style: 'affirmative',
}, },
@ -233,7 +233,7 @@ function GroupV2Detail({
id="icu:PendingRequests--block--contents" id="icu:PendingRequests--block--contents"
i18n={i18n} i18n={i18n}
components={{ components={{
name: renderContact(detail.uuid), name: renderContact(detail.aci),
}} }}
/> />
</ConfirmationDialog> </ConfirmationDialog>
@ -261,11 +261,11 @@ function GroupV2Detail({
isLastText && isLastText &&
detail.type === 'admin-approval-bounce' && detail.type === 'admin-approval-bounce' &&
areWeAdmin && areWeAdmin &&
detail.uuid && detail.aci &&
detail.uuid !== ourAci && detail.aci !== ourAci &&
(!fromId || fromId === detail.uuid) && (!fromId || fromId === detail.aci) &&
!groupMemberships?.some(item => item.uuid === detail.uuid) && !groupMemberships?.some(item => item.aci === detail.aci) &&
!groupBannedMemberships?.some(uuid => uuid === detail.uuid) !groupBannedMemberships?.some(serviceId => serviceId === detail.aci)
) { ) {
buttonNode = ( buttonNode = (
<Button <Button

View file

@ -319,7 +319,7 @@ export type PropsActions = {
messageExpanded: (id: string, displayLimit: number) => unknown; messageExpanded: (id: string, displayLimit: number) => unknown;
checkForAccount: (phoneNumber: string) => unknown; checkForAccount: (phoneNumber: string) => unknown;
startConversation: (e164: string, uuid: ServiceIdString) => void; startConversation: (e164: string, serviceId: ServiceIdString) => void;
showConversation: ShowConversationType; showConversation: ShowConversationType;
openGiftBadge: (messageId: string) => void; openGiftBadge: (messageId: string) => void;
pushPanelForConversation: PushPanelForConversationActionType; pushPanelForConversation: PushPanelForConversationActionType;
@ -516,7 +516,7 @@ export class Message extends React.PureComponent<Props, State> {
} }
const { contact, checkForAccount } = this.props; const { contact, checkForAccount } = this.props;
if (contact && contact.firstNumber && !contact.uuid) { if (contact && contact.firstNumber && !contact.serviceId) {
checkForAccount(contact.firstNumber); checkForAccount(contact.firstNumber);
} }
@ -1637,7 +1637,7 @@ export class Message extends React.PureComponent<Props, State> {
this.getMetadataPlacement() !== MetadataPlacement.NotRendered; this.getMetadataPlacement() !== MetadataPlacement.NotRendered;
const otherContent = const otherContent =
(contact && contact.firstNumber && contact.uuid) || withCaption; (contact && contact.firstNumber && contact.serviceId) || withCaption;
const tabIndex = otherContent ? 0 : -1; const tabIndex = otherContent ? 0 : -1;
return ( return (
@ -1647,10 +1647,10 @@ export class Message extends React.PureComponent<Props, State> {
i18n={i18n} i18n={i18n}
onClick={() => { onClick={() => {
const signalAccount = const signalAccount =
contact.firstNumber && contact.uuid contact.firstNumber && contact.serviceId
? { ? {
phoneNumber: contact.firstNumber, phoneNumber: contact.firstNumber,
uuid: contact.uuid, serviceId: contact.serviceId,
} }
: undefined; : undefined;
@ -1678,8 +1678,8 @@ export class Message extends React.PureComponent<Props, State> {
if (!contact) { if (!contact) {
return null; return null;
} }
const { firstNumber, uuid } = contact; const { firstNumber, serviceId } = contact;
if (!firstNumber || !uuid) { if (!firstNumber || !serviceId) {
return null; return null;
} }
@ -1689,7 +1689,7 @@ export class Message extends React.PureComponent<Props, State> {
onClick={e => { onClick={e => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
startConversation(firstNumber, uuid); startConversation(firstNumber, serviceId);
}} }}
className={classNames( className={classNames(
'module-message__send-message-button', 'module-message__send-message-button',
@ -2456,8 +2456,8 @@ export class Message extends React.PureComponent<Props, State> {
return; return;
} }
if (contact && contact.firstNumber && contact.uuid) { if (contact && contact.firstNumber && contact.serviceId) {
startConversation(contact.firstNumber, contact.uuid); startConversation(contact.firstNumber, contact.serviceId);
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@ -2466,10 +2466,10 @@ export class Message extends React.PureComponent<Props, State> {
if (contact) { if (contact) {
const signalAccount = const signalAccount =
contact.firstNumber && contact.uuid contact.firstNumber && contact.serviceId
? { ? {
phoneNumber: contact.firstNumber, phoneNumber: contact.firstNumber,
uuid: contact.uuid, serviceId: contact.serviceId,
} }
: undefined; : undefined;
pushPanelForConversation({ pushPanelForConversation({

View file

@ -128,7 +128,7 @@ export function Mention(): JSX.Element {
{ {
start: 5, start: 5,
length: 1, length: 1,
mentionUuid: SERVICE_ID_1, mentionAci: SERVICE_ID_1,
replacementText: 'Bender B Rodriguez 🤖', replacementText: 'Bender B Rodriguez 🤖',
conversationID: 'x', conversationID: 'x',
}, },
@ -150,21 +150,21 @@ export function MultipleMentions(): JSX.Element {
{ {
start: 2, start: 2,
length: 1, length: 1,
mentionUuid: SERVICE_ID_2, mentionAci: SERVICE_ID_2,
replacementText: 'Philip J Fry', replacementText: 'Philip J Fry',
conversationID: 'x', conversationID: 'x',
}, },
{ {
start: 4, start: 4,
length: 1, length: 1,
mentionUuid: SERVICE_ID_3, mentionAci: SERVICE_ID_3,
replacementText: 'Professor Farnsworth', replacementText: 'Professor Farnsworth',
conversationID: 'x', conversationID: 'x',
}, },
{ {
start: 0, start: 0,
length: 1, length: 1,
mentionUuid: SERVICE_ID_4, mentionAci: SERVICE_ID_4,
replacementText: 'Yancy Fry', replacementText: 'Yancy Fry',
conversationID: 'x', conversationID: 'x',
}, },
@ -192,21 +192,21 @@ export function ComplexMessageBody(): JSX.Element {
{ {
start: 78, start: 78,
length: 1, length: 1,
mentionUuid: SERVICE_ID_5, mentionAci: SERVICE_ID_5,
replacementText: 'Acid Burn', replacementText: 'Acid Burn',
conversationID: 'x', conversationID: 'x',
}, },
{ {
start: 80, start: 80,
length: 1, length: 1,
mentionUuid: SERVICE_ID_6, mentionAci: SERVICE_ID_6,
replacementText: 'Cereal Killer', replacementText: 'Cereal Killer',
conversationID: 'x', conversationID: 'x',
}, },
{ {
start: 4, start: 4,
length: 1, length: 1,
mentionUuid: SERVICE_ID_6, mentionAci: SERVICE_ID_6,
replacementText: 'Zero Cool', replacementText: 'Zero Cool',
conversationID: 'x', conversationID: 'x',
}, },
@ -324,14 +324,14 @@ export function FormattingSpoiler(): JSX.Element {
{ {
start: 54, start: 54,
length: 1, length: 1,
mentionUuid: SERVICE_ID_7, mentionAci: SERVICE_ID_7,
conversationID: 'a', conversationID: 'a',
replacementText: '🅰️ Alice', replacementText: '🅰️ Alice',
}, },
{ {
start: 60, start: 60,
length: 1, length: 1,
mentionUuid: SERVICE_ID_8, mentionAci: SERVICE_ID_8,
conversationID: 'b', conversationID: 'b',
replacementText: '🅱️ Bob', replacementText: '🅱️ Bob',
}, },
@ -384,35 +384,35 @@ export function FormattingNesting(): JSX.Element {
{ {
start: 29, start: 29,
length: 1, length: 1,
mentionUuid: SERVICE_ID_7, mentionAci: SERVICE_ID_7,
conversationID: 'a', conversationID: 'a',
replacementText: '🅰️ Alice', replacementText: '🅰️ Alice',
}, },
{ {
start: 61, start: 61,
length: 1, length: 1,
mentionUuid: SERVICE_ID_8, mentionAci: SERVICE_ID_8,
conversationID: 'b', conversationID: 'b',
replacementText: '🅱️ Bob', replacementText: '🅱️ Bob',
}, },
{ {
start: 68, start: 68,
length: 1, length: 1,
mentionUuid: SERVICE_ID_9, mentionAci: SERVICE_ID_9,
conversationID: 'c', conversationID: 'c',
replacementText: 'Charlie', replacementText: 'Charlie',
}, },
{ {
start: 80, start: 80,
length: 1, length: 1,
mentionUuid: SERVICE_ID_10, mentionAci: SERVICE_ID_10,
conversationID: 'd', conversationID: 'd',
replacementText: 'Dan', replacementText: 'Dan',
}, },
{ {
start: 105, start: 105,
length: 1, length: 1,
mentionUuid: SERVICE_ID_11, mentionAci: SERVICE_ID_11,
conversationID: 'e', conversationID: 'e',
replacementText: 'Eve', replacementText: 'Eve',
}, },
@ -452,7 +452,7 @@ export function FormattingComplex(): JSX.Element {
{ {
start: 24, start: 24,
length: 1, length: 1,
mentionUuid: SERVICE_ID_3, mentionAci: SERVICE_ID_3,
conversationID: 'x', conversationID: 'x',
replacementText: '🤖 Hello', replacementText: '🤖 Hello',
}, },
@ -484,7 +484,7 @@ export function FormattingComplex(): JSX.Element {
{ {
start: 491, start: 491,
length: 1, length: 1,
mentionUuid: SERVICE_ID_3, mentionAci: SERVICE_ID_3,
conversationID: 'x', conversationID: 'x',
replacementText: '🤖 Hello', replacementText: '🤖 Hello',
}, },

View file

@ -92,7 +92,7 @@ export function LongTextWithMention(): JSX.Element {
{ {
start: 800, start: 800,
length: 1, length: 1,
mentionUuid: generateAci(), mentionAci: generateAci(),
conversationID: 'x', conversationID: 'x',
replacementText: 'Alice', replacementText: 'Alice',
}, },

View file

@ -267,8 +267,8 @@ const actions = () => ({
), ),
blockGroupLinkRequests: action('blockGroupLinkRequests'), blockGroupLinkRequests: action('blockGroupLinkRequests'),
checkForAccount: action('checkForAccount'), checkForAccount: action('checkForAccount'),
clearInvitedUuidsForNewlyCreatedGroup: action( clearInvitedServiceIdsForNewlyCreatedGroup: action(
'clearInvitedUuidsForNewlyCreatedGroup' 'clearInvitedServiceIdsForNewlyCreatedGroup'
), ),
setIsNearBottom: action('setIsNearBottom'), setIsNearBottom: action('setIsNearBottom'),
loadOlderMessages: action('loadOlderMessages'), loadOlderMessages: action('loadOlderMessages'),

View file

@ -148,7 +148,7 @@ export type PropsActionsType = {
conversationId: string, conversationId: string,
groupNameCollisions: ReadonlyDeep<GroupNameCollisionsWithIdsByTitle> groupNameCollisions: ReadonlyDeep<GroupNameCollisionsWithIdsByTitle>
) => void; ) => void;
clearInvitedUuidsForNewlyCreatedGroup: () => void; clearInvitedServiceIdsForNewlyCreatedGroup: () => void;
clearTargetedMessage: () => unknown; clearTargetedMessage: () => unknown;
closeContactSpoofingReview: () => void; closeContactSpoofingReview: () => void;
loadOlderMessages: (conversationId: string, messageId: string) => unknown; loadOlderMessages: (conversationId: string, messageId: string) => unknown;
@ -743,7 +743,7 @@ export class Timeline extends React.Component<
public override render(): JSX.Element | null { public override render(): JSX.Element | null {
const { const {
acknowledgeGroupMemberNameCollisions, acknowledgeGroupMemberNameCollisions,
clearInvitedUuidsForNewlyCreatedGroup, clearInvitedServiceIdsForNewlyCreatedGroup,
closeContactSpoofingReview, closeContactSpoofingReview,
contactSpoofingReview, contactSpoofingReview,
getPreferredBadge, getPreferredBadge,
@ -1139,7 +1139,7 @@ export class Timeline extends React.Component<
contacts={invitedContactsForNewlyCreatedGroup} contacts={invitedContactsForNewlyCreatedGroup}
getPreferredBadge={getPreferredBadge} getPreferredBadge={getPreferredBadge}
i18n={i18n} i18n={i18n}
onClose={clearInvitedUuidsForNewlyCreatedGroup} onClose={clearInvitedServiceIdsForNewlyCreatedGroup}
theme={theme} theme={theme}
/> />
)} )}

View file

@ -1676,7 +1676,7 @@ Mentions.args = {
{ {
start: 0, start: 0,
length: 1, length: 1,
mentionUuid: generateAci(), mentionAci: generateAci(),
replacementText: 'Zapp Brannigan', replacementText: 'Zapp Brannigan',
conversationID: 'x', conversationID: 'x',
}, },
@ -1944,7 +1944,7 @@ EmbeddedContactWithSendMessage.args = {
contact: { contact: {
...fullContact, ...fullContact,
firstNumber: fullContact.number[0].value, firstNumber: fullContact.number[0].value,
uuid: generateAci(), serviceId: generateAci(),
}, },
direction: 'incoming', direction: 'incoming',
}; };

View file

@ -234,7 +234,7 @@ export function WithCallHistoryGroup(): JSX.Element {
<ConversationDetails <ConversationDetails
{...props} {...props}
callHistoryGroup={{ callHistoryGroup={{
peerId: props.conversation?.uuid ?? '', peerId: props.conversation?.serviceId ?? '',
mode: CallMode.Direct, mode: CallMode.Direct,
type: CallType.Video, type: CallType.Video,
direction: CallDirection.Incoming, direction: CallDirection.Incoming,

View file

@ -292,7 +292,8 @@ function getConfirmationMessage({
} }
const inviter = members.find( const inviter = members.find(
({ uuid }) => uuid === firstPendingMembership.metadata.addedByUserId ({ serviceId }) =>
serviceId === firstPendingMembership.metadata.addedByUserId
); );
if (inviter === undefined) { if (inviter === undefined) {
@ -412,13 +413,16 @@ function MembersPendingProfileKey({
groupedPendingMemberships; groupedPendingMemberships;
const otherPendingMemberships = Object.keys(otherPendingMembershipGroups) const otherPendingMemberships = Object.keys(otherPendingMembershipGroups)
.map(id => members.find(member => member.uuid === id)) .map(id => members.find(member => member.serviceId === id))
.filter((member): member is ConversationType => member !== undefined) .filter((member): member is ConversationType => member !== undefined)
.map(member => { .map(member => {
assertDev(member.uuid, 'We just verified that member has uuid above'); assertDev(
member.serviceId,
'We just verified that member has serviceId above'
);
return { return {
member, member,
pendingMemberships: otherPendingMembershipGroups[member.uuid], pendingMemberships: otherPendingMembershipGroups[member.serviceId],
}; };
}); });

View file

@ -68,7 +68,7 @@ type PropsType = {
| 'sharedGroupNames' | 'sharedGroupNames'
| 'title' | 'title'
| 'unblurredAvatarPath' | 'unblurredAvatarPath'
| 'uuid' | 'serviceId'
> & > &
( (
| { badge?: undefined; theme?: ThemeType } | { badge?: undefined; theme?: ThemeType }
@ -109,12 +109,12 @@ export const BaseConversationListItem: FunctionComponent<PropsType> =
unblurredAvatarPath, unblurredAvatarPath,
unreadCount, unreadCount,
unreadMentionsCount, unreadMentionsCount,
uuid, serviceId,
} = props; } = props;
const identifier = id ? cleanId(id) : undefined; const identifier = id ? cleanId(id) : undefined;
const htmlId = useMemo(() => generateUuid(), []); const htmlId = useMemo(() => generateUuid(), []);
const testId = overrideTestId || groupId || uuid; const testId = overrideTestId || groupId || serviceId;
const isUnread = isConversationUnread({ markedUnread, unreadCount }); const isUnread = isConversationUnread({ markedUnread, unreadCount });
const isAvatarNoteToSelf = isBoolean(isNoteToSelf) const isAvatarNoteToSelf = isBoolean(isNoteToSelf)

View file

@ -38,7 +38,7 @@ export type PropsDataType = {
| 'title' | 'title'
| 'type' | 'type'
| 'unblurredAvatarPath' | 'unblurredAvatarPath'
| 'uuid' | 'serviceId'
>; >;
type PropsHousekeepingType = { type PropsHousekeepingType = {

View file

@ -39,7 +39,7 @@ export type ContactListItemConversationType = Pick<
| 'unblurredAvatarPath' | 'unblurredAvatarPath'
| 'username' | 'username'
| 'e164' | 'e164'
| 'uuid' | 'serviceId'
>; >;
type PropsDataType = ContactListItemConversationType & { type PropsDataType = ContactListItemConversationType & {
@ -85,7 +85,7 @@ export const ContactListItem: FunctionComponent<PropsType> = React.memo(
title, title,
type, type,
unblurredAvatarPath, unblurredAvatarPath,
uuid, serviceId,
}) { }) {
const [isConfirmingBlocking, setConfirmingBlocking] = useState(false); const [isConfirmingBlocking, setConfirmingBlocking] = useState(false);
const [isConfirmingRemoving, setConfirmingRemoving] = useState(false); const [isConfirmingRemoving, setConfirmingRemoving] = useState(false);
@ -149,7 +149,7 @@ export const ContactListItem: FunctionComponent<PropsType> = React.memo(
/> />
) : ( ) : (
<ContactName <ContactName
isSignalConversation={isSignalConversation({ id, uuid })} isSignalConversation={isSignalConversation({ id, serviceId })}
module={HEADER_CONTACT_NAME_CLASS_NAME} module={HEADER_CONTACT_NAME_CLASS_NAME}
title={title} title={title}
/> />

View file

@ -64,7 +64,7 @@ export type PropsData = Pick<
| 'unblurredAvatarPath' | 'unblurredAvatarPath'
| 'unreadCount' | 'unreadCount'
| 'unreadMentionsCount' | 'unreadMentionsCount'
| 'uuid' | 'serviceId'
> & { > & {
badge?: BadgeType; badge?: BadgeType;
}; };
@ -108,7 +108,7 @@ export const ConversationListItem: FunctionComponent<Props> = React.memo(
unblurredAvatarPath, unblurredAvatarPath,
unreadCount, unreadCount,
unreadMentionsCount, unreadMentionsCount,
uuid, serviceId,
}) { }) {
const isMuted = Boolean(muteExpiresAt && Date.now() < muteExpiresAt); const isMuted = Boolean(muteExpiresAt && Date.now() < muteExpiresAt);
const headerName = ( const headerName = (
@ -122,7 +122,7 @@ export const ConversationListItem: FunctionComponent<Props> = React.memo(
) : ( ) : (
<ContactName <ContactName
module={HEADER_CONTACT_NAME_CLASS_NAME} module={HEADER_CONTACT_NAME_CLASS_NAME}
isSignalConversation={isSignalConversation({ id, uuid })} isSignalConversation={isSignalConversation({ id, serviceId })}
title={title} title={title}
/> />
)} )}
@ -221,7 +221,7 @@ export const ConversationListItem: FunctionComponent<Props> = React.memo(
unreadCount={unreadCount} unreadCount={unreadCount}
unreadMentionsCount={unreadMentionsCount} unreadMentionsCount={unreadMentionsCount}
unblurredAvatarPath={unblurredAvatarPath} unblurredAvatarPath={unblurredAvatarPath}
uuid={uuid} serviceId={serviceId}
/> />
); );
} }

View file

@ -21,7 +21,7 @@ export type GroupListItemConversationType = Pick<
disabledReason: DisabledReason | undefined; disabledReason: DisabledReason | undefined;
membersCount: number; membersCount: number;
memberships: ReadonlyArray<{ memberships: ReadonlyArray<{
uuid: AciString; aci: AciString;
isAdmin: boolean; isAdmin: boolean;
}>; }>;
}; };

View file

@ -203,14 +203,14 @@ export function Mention(): JSX.Element {
bodyRanges: [ bodyRanges: [
{ {
length: 1, length: 1,
mentionUuid: SERVICE_ID_3, mentionAci: SERVICE_ID_3,
replacementText: 'Shoe', replacementText: 'Shoe',
conversationID: 'x', conversationID: 'x',
start: 113, start: 113,
}, },
{ {
length: 1, length: 1,
mentionUuid: SERVICE_ID_3, mentionAci: SERVICE_ID_3,
replacementText: 'Shoe', replacementText: 'Shoe',
conversationID: 'x', conversationID: 'x',
start: 237, start: 237,
@ -235,7 +235,7 @@ export function MentionRegexp(): JSX.Element {
bodyRanges: [ bodyRanges: [
{ {
length: 1, length: 1,
mentionUuid: SERVICE_ID_3, mentionAci: SERVICE_ID_3,
replacementText: 'RegExp', replacementText: 'RegExp',
conversationID: 'x', conversationID: 'x',
start: 0, start: 0,
@ -260,7 +260,7 @@ export function MentionNoMatches(): JSX.Element {
bodyRanges: [ bodyRanges: [
{ {
length: 1, length: 1,
mentionUuid: SERVICE_ID_3, mentionAci: SERVICE_ID_3,
replacementText: 'Neo', replacementText: 'Neo',
conversationID: 'x', conversationID: 'x',
start: 0, start: 0,
@ -284,14 +284,14 @@ export const _MentionNoMatches = (): JSX.Element => {
bodyRanges: [ bodyRanges: [
{ {
length: 1, length: 1,
mentionUuid: SERVICE_ID_3, mentionAci: SERVICE_ID_3,
replacementText: 'Shoe', replacementText: 'Shoe',
conversationID: 'x', conversationID: 'x',
start: 113, start: 113,
}, },
{ {
length: 1, length: 1,
mentionUuid: SERVICE_ID_3, mentionAci: SERVICE_ID_3,
replacementText: 'Shoe', replacementText: 'Shoe',
conversationID: 'x', conversationID: 'x',
start: 237, start: 237,
@ -316,14 +316,14 @@ export function DoubleMention(): JSX.Element {
bodyRanges: [ bodyRanges: [
{ {
length: 1, length: 1,
mentionUuid: SERVICE_ID_2, mentionAci: SERVICE_ID_2,
replacementText: 'Alice', replacementText: 'Alice',
conversationID: 'x', conversationID: 'x',
start: 4, start: 4,
}, },
{ {
length: 1, length: 1,
mentionUuid: SERVICE_ID_1, mentionAci: SERVICE_ID_1,
replacementText: 'Bob', replacementText: 'Bob',
conversationID: 'x', conversationID: 'x',
start: 6, start: 6,

View file

@ -86,13 +86,15 @@ export function renderChangeDetail<T>(
return renderString(id, localizer, components); return renderString(id, localizer, components);
} }
const isOurUuid = (uuid?: ServiceIdString): boolean => { const isOurServiceId = (serviceId?: ServiceIdString): boolean => {
if (!uuid) { if (!serviceId) {
return false; return false;
} }
return Boolean((ourAci && uuid === ourAci) || (ourPni && uuid === ourPni)); return Boolean(
(ourAci && serviceId === ourAci) || (ourPni && serviceId === ourPni)
);
}; };
const fromYou = isOurUuid(from); const fromYou = isOurServiceId(from);
if (detail.type === 'create') { if (detail.type === 'create') {
if (fromYou) { if (fromYou) {
@ -249,8 +251,8 @@ export function renderChangeDetail<T>(
return ''; return '';
} }
if (detail.type === 'member-add') { if (detail.type === 'member-add') {
const { uuid } = detail; const { aci } = detail;
const weAreJoiner = isOurUuid(uuid); const weAreJoiner = isOurServiceId(aci);
if (weAreJoiner) { if (weAreJoiner) {
if (fromYou) { if (fromYou) {
@ -265,25 +267,25 @@ export function renderChangeDetail<T>(
} }
if (fromYou) { if (fromYou) {
return i18n('icu:GroupV2--member-add--other--you', { return i18n('icu:GroupV2--member-add--other--you', {
memberName: renderContact(uuid), memberName: renderContact(aci),
}); });
} }
if (from) { if (from) {
return i18n('icu:GroupV2--member-add--other--other', { return i18n('icu:GroupV2--member-add--other--other', {
adderName: renderContact(from), adderName: renderContact(from),
addeeName: renderContact(uuid), addeeName: renderContact(aci),
}); });
} }
return i18n('icu:GroupV2--member-add--other--unknown', { return i18n('icu:GroupV2--member-add--other--unknown', {
memberName: renderContact(uuid), memberName: renderContact(aci),
}); });
} }
if (detail.type === 'member-add-from-invite') { if (detail.type === 'member-add-from-invite') {
const { uuid, inviter } = detail; const { aci, inviter } = detail;
const weAreJoiner = isOurUuid(uuid); const weAreJoiner = isOurServiceId(aci);
const weAreInviter = isOurUuid(inviter); const weAreInviter = isOurServiceId(inviter);
if (!from || from !== uuid) { if (!from || from !== aci) {
if (weAreJoiner) { if (weAreJoiner) {
// They can't be the same, no fromYou check here // They can't be the same, no fromYou check here
if (from) { if (from) {
@ -296,17 +298,17 @@ export function renderChangeDetail<T>(
if (fromYou) { if (fromYou) {
return i18n('icu:GroupV2--member-add--invited--you', { return i18n('icu:GroupV2--member-add--invited--you', {
inviteeName: renderContact(uuid), inviteeName: renderContact(aci),
}); });
} }
if (from) { if (from) {
return i18n('icu:GroupV2--member-add--invited--other', { return i18n('icu:GroupV2--member-add--invited--other', {
memberName: renderContact(from), memberName: renderContact(from),
inviteeName: renderContact(uuid), inviteeName: renderContact(aci),
}); });
} }
return i18n('icu:GroupV2--member-add--invited--unknown', { return i18n('icu:GroupV2--member-add--invited--unknown', {
inviteeName: renderContact(uuid), inviteeName: renderContact(aci),
}); });
} }
@ -320,12 +322,12 @@ export function renderChangeDetail<T>(
} }
if (weAreInviter) { if (weAreInviter) {
return i18n('icu:GroupV2--member-add--from-invite--from-you', { return i18n('icu:GroupV2--member-add--from-invite--from-you', {
inviteeName: renderContact(uuid), inviteeName: renderContact(aci),
}); });
} }
if (inviter) { if (inviter) {
return i18n('icu:GroupV2--member-add--from-invite--other', { return i18n('icu:GroupV2--member-add--from-invite--other', {
inviteeName: renderContact(uuid), inviteeName: renderContact(aci),
inviterName: renderContact(inviter), inviterName: renderContact(inviter),
}); });
} }
@ -333,17 +335,17 @@ export function renderChangeDetail<T>(
'icu:GroupV2--member-add--from-invite--other-no-from', 'icu:GroupV2--member-add--from-invite--other-no-from',
{ {
inviteeName: renderContact(uuid), inviteeName: renderContact(aci),
} }
); );
} }
if (detail.type === 'member-add-from-link') { if (detail.type === 'member-add-from-link') {
const { uuid } = detail; const { aci } = detail;
if (fromYou && isOurUuid(uuid)) { if (fromYou && isOurServiceId(aci)) {
return i18n('icu:GroupV2--member-add-from-link--you--you'); return i18n('icu:GroupV2--member-add-from-link--you--you');
} }
if (from && uuid === from) { if (from && aci === from) {
return i18n('icu:GroupV2--member-add-from-link--other', { return i18n('icu:GroupV2--member-add-from-link--other', {
memberName: renderContact(from), memberName: renderContact(from),
}); });
@ -353,12 +355,12 @@ export function renderChangeDetail<T>(
// from group change events, which always have a sender. // from group change events, which always have a sender.
log.warn('member-add-from-link change type; we have no from!'); log.warn('member-add-from-link change type; we have no from!');
return i18n('icu:GroupV2--member-add--other--unknown', { return i18n('icu:GroupV2--member-add--other--unknown', {
memberName: renderContact(uuid), memberName: renderContact(aci),
}); });
} }
if (detail.type === 'member-add-from-admin-approval') { if (detail.type === 'member-add-from-admin-approval') {
const { uuid } = detail; const { aci } = detail;
const weAreJoiner = isOurUuid(uuid); const weAreJoiner = isOurServiceId(aci);
if (weAreJoiner) { if (weAreJoiner) {
if (from) { if (from) {
@ -381,7 +383,7 @@ export function renderChangeDetail<T>(
return i18n( return i18n(
'icu:GroupV2--member-add-from-admin-approval--other--you', 'icu:GroupV2--member-add-from-admin-approval--other--you',
{ joinerName: renderContact(uuid) } { joinerName: renderContact(aci) }
); );
} }
if (from) { if (from) {
@ -390,7 +392,7 @@ export function renderChangeDetail<T>(
{ {
adminName: renderContact(from), adminName: renderContact(from),
joinerName: renderContact(uuid), joinerName: renderContact(aci),
} }
); );
} }
@ -401,12 +403,12 @@ export function renderChangeDetail<T>(
return i18n( return i18n(
'icu:GroupV2--member-add-from-admin-approval--other--unknown', 'icu:GroupV2--member-add-from-admin-approval--other--unknown',
{ joinerName: renderContact(uuid) } { joinerName: renderContact(aci) }
); );
} }
if (detail.type === 'member-remove') { if (detail.type === 'member-remove') {
const { uuid } = detail; const { aci } = detail;
const weAreLeaver = isOurUuid(uuid); const weAreLeaver = isOurServiceId(aci);
if (weAreLeaver) { if (weAreLeaver) {
if (fromYou) { if (fromYou) {
@ -422,10 +424,10 @@ export function renderChangeDetail<T>(
if (fromYou) { if (fromYou) {
return i18n('icu:GroupV2--member-remove--other--you', { return i18n('icu:GroupV2--member-remove--other--you', {
memberName: renderContact(uuid), memberName: renderContact(aci),
}); });
} }
if (from && from === uuid) { if (from && from === aci) {
return i18n('icu:GroupV2--member-remove--other--self', { return i18n('icu:GroupV2--member-remove--other--self', {
memberName: renderContact(from), memberName: renderContact(from),
}); });
@ -433,16 +435,16 @@ export function renderChangeDetail<T>(
if (from) { if (from) {
return i18n('icu:GroupV2--member-remove--other--other', { return i18n('icu:GroupV2--member-remove--other--other', {
adminName: renderContact(from), adminName: renderContact(from),
memberName: renderContact(uuid), memberName: renderContact(aci),
}); });
} }
return i18n('icu:GroupV2--member-remove--other--unknown', { return i18n('icu:GroupV2--member-remove--other--unknown', {
memberName: renderContact(uuid), memberName: renderContact(aci),
}); });
} }
if (detail.type === 'member-privilege') { if (detail.type === 'member-privilege') {
const { uuid, newPrivilege } = detail; const { aci, newPrivilege } = detail;
const weAreMember = isOurUuid(uuid); const weAreMember = isOurServiceId(aci);
if (newPrivilege === RoleEnum.ADMINISTRATOR) { if (newPrivilege === RoleEnum.ADMINISTRATOR) {
if (weAreMember) { if (weAreMember) {
@ -459,17 +461,17 @@ export function renderChangeDetail<T>(
if (fromYou) { if (fromYou) {
return i18n('icu:GroupV2--member-privilege--promote--other--you', { return i18n('icu:GroupV2--member-privilege--promote--other--you', {
memberName: renderContact(uuid), memberName: renderContact(aci),
}); });
} }
if (from) { if (from) {
return i18n('icu:GroupV2--member-privilege--promote--other--other', { return i18n('icu:GroupV2--member-privilege--promote--other--other', {
adminName: renderContact(from), adminName: renderContact(from),
memberName: renderContact(uuid), memberName: renderContact(aci),
}); });
} }
return i18n('icu:GroupV2--member-privilege--promote--other--unknown', { return i18n('icu:GroupV2--member-privilege--promote--other--unknown', {
memberName: renderContact(uuid), memberName: renderContact(aci),
}); });
} }
if (newPrivilege === RoleEnum.DEFAULT) { if (newPrivilege === RoleEnum.DEFAULT) {
@ -484,7 +486,7 @@ export function renderChangeDetail<T>(
if (fromYou) { if (fromYou) {
return i18n('icu:GroupV2--member-privilege--demote--other--you', { return i18n('icu:GroupV2--member-privilege--demote--other--you', {
memberName: renderContact(uuid), memberName: renderContact(aci),
}); });
} }
if (from) { if (from) {
@ -493,14 +495,14 @@ export function renderChangeDetail<T>(
{ {
adminName: renderContact(from), adminName: renderContact(from),
memberName: renderContact(uuid), memberName: renderContact(aci),
} }
); );
} }
return i18n( return i18n(
'icu:GroupV2--member-privilege--demote--other--unknown', 'icu:GroupV2--member-privilege--demote--other--unknown',
{ memberName: renderContact(uuid) } { memberName: renderContact(aci) }
); );
} }
log.warn( log.warn(
@ -509,8 +511,8 @@ export function renderChangeDetail<T>(
return ''; return '';
} }
if (detail.type === 'pending-add-one') { if (detail.type === 'pending-add-one') {
const { uuid } = detail; const { serviceId } = detail;
const weAreInvited = isOurUuid(uuid); const weAreInvited = isOurServiceId(serviceId);
if (weAreInvited) { if (weAreInvited) {
if (from) { if (from) {
return i18n('icu:GroupV2--pending-add--one--you--other', { return i18n('icu:GroupV2--pending-add--one--you--other', {
@ -521,7 +523,7 @@ export function renderChangeDetail<T>(
} }
if (fromYou) { if (fromYou) {
return i18n('icu:GroupV2--pending-add--one--other--you', { return i18n('icu:GroupV2--pending-add--one--other--you', {
inviteeName: renderContact(uuid), inviteeName: renderContact(serviceId),
}); });
} }
if (from) { if (from) {
@ -550,23 +552,23 @@ export function renderChangeDetail<T>(
}); });
} }
if (detail.type === 'pending-remove-one') { if (detail.type === 'pending-remove-one') {
const { inviter, uuid } = detail; const { inviter, serviceId } = detail;
const weAreInviter = isOurUuid(inviter); const weAreInviter = isOurServiceId(inviter);
const weAreInvited = isOurUuid(uuid); const weAreInvited = isOurServiceId(serviceId);
const sentByInvited = Boolean(from && from === uuid); const sentByInvited = Boolean(from && from === serviceId);
const sentByInviter = Boolean(from && inviter && from === inviter); const sentByInviter = Boolean(from && inviter && from === inviter);
if (weAreInviter) { if (weAreInviter) {
if (sentByInvited) { if (sentByInvited) {
return i18n('icu:GroupV2--pending-remove--decline--you', { return i18n('icu:GroupV2--pending-remove--decline--you', {
inviteeName: renderContact(uuid), inviteeName: renderContact(serviceId),
}); });
} }
if (fromYou) { if (fromYou) {
return i18n( return i18n(
'icu:GroupV2--pending-remove--revoke-invite-from-you--one--you', 'icu:GroupV2--pending-remove--revoke-invite-from-you--one--you',
{ inviteeName: renderContact(uuid) } { inviteeName: renderContact(serviceId) }
); );
} }
if (from) { if (from) {
@ -575,14 +577,14 @@ export function renderChangeDetail<T>(
{ {
adminName: renderContact(from), adminName: renderContact(from),
inviteeName: renderContact(uuid), inviteeName: renderContact(serviceId),
} }
); );
} }
return i18n( return i18n(
'icu:GroupV2--pending-remove--revoke-invite-from-you--one--unknown', 'icu:GroupV2--pending-remove--revoke-invite-from-you--one--unknown',
{ inviteeName: renderContact(uuid) } { inviteeName: renderContact(serviceId) }
); );
} }
if (sentByInvited) { if (sentByInvited) {
@ -646,7 +648,7 @@ export function renderChangeDetail<T>(
} }
if (detail.type === 'pending-remove-many') { if (detail.type === 'pending-remove-many') {
const { count, inviter } = detail; const { count, inviter } = detail;
const weAreInviter = isOurUuid(inviter); const weAreInviter = isOurServiceId(inviter);
if (weAreInviter) { if (weAreInviter) {
if (fromYou) { if (fromYou) {
@ -725,19 +727,19 @@ export function renderChangeDetail<T>(
); );
} }
if (detail.type === 'admin-approval-add-one') { if (detail.type === 'admin-approval-add-one') {
const { uuid } = detail; const { aci } = detail;
const weAreJoiner = isOurUuid(uuid); const weAreJoiner = isOurServiceId(aci);
if (weAreJoiner) { if (weAreJoiner) {
return i18n('icu:GroupV2--admin-approval-add-one--you'); return i18n('icu:GroupV2--admin-approval-add-one--you');
} }
return i18n('icu:GroupV2--admin-approval-add-one--other', { return i18n('icu:GroupV2--admin-approval-add-one--other', {
joinerName: renderContact(uuid), joinerName: renderContact(aci),
}); });
} }
if (detail.type === 'admin-approval-remove-one') { if (detail.type === 'admin-approval-remove-one') {
const { uuid } = detail; const { aci } = detail;
const weAreJoiner = isOurUuid(uuid); const weAreJoiner = isOurServiceId(aci);
if (weAreJoiner) { if (weAreJoiner) {
if (fromYou) { if (fromYou) {
@ -750,14 +752,14 @@ export function renderChangeDetail<T>(
return i18n( return i18n(
'icu:GroupV2--admin-approval-remove-one--other--you', 'icu:GroupV2--admin-approval-remove-one--other--you',
{ joinerName: renderContact(uuid) } { joinerName: renderContact(aci) }
); );
} }
if (from && from === uuid) { if (from && from === aci) {
return i18n( return i18n(
'icu:GroupV2--admin-approval-remove-one--other--own', 'icu:GroupV2--admin-approval-remove-one--other--own',
{ joinerName: renderContact(uuid) } { joinerName: renderContact(aci) }
); );
} }
if (from) { if (from) {
@ -766,7 +768,7 @@ export function renderChangeDetail<T>(
{ {
adminName: renderContact(from), adminName: renderContact(from),
joinerName: renderContact(uuid), joinerName: renderContact(aci),
} }
); );
} }
@ -776,20 +778,20 @@ export function renderChangeDetail<T>(
return i18n( return i18n(
'icu:GroupV2--admin-approval-remove-one--other--own', 'icu:GroupV2--admin-approval-remove-one--other--own',
{ joinerName: renderContact(uuid) } { joinerName: renderContact(aci) }
); );
} }
if (detail.type === 'admin-approval-bounce') { if (detail.type === 'admin-approval-bounce') {
const { uuid, times, isApprovalPending } = detail; const { aci, times, isApprovalPending } = detail;
let firstMessage: T | string; let firstMessage: T | string;
if (times === 1) { if (times === 1) {
firstMessage = i18n('icu:GroupV2--admin-approval-bounce--one', { firstMessage = i18n('icu:GroupV2--admin-approval-bounce--one', {
joinerName: renderContact(uuid), joinerName: renderContact(aci),
}); });
} else { } else {
firstMessage = i18n('icu:GroupV2--admin-approval-bounce', { firstMessage = i18n('icu:GroupV2--admin-approval-bounce', {
joinerName: renderContact(uuid), joinerName: renderContact(aci),
numberOfRequests: times, numberOfRequests: times,
}); });
} }
@ -801,7 +803,7 @@ export function renderChangeDetail<T>(
const secondMessage = renderChangeDetail( const secondMessage = renderChangeDetail(
{ {
type: 'admin-approval-add-one', type: 'admin-approval-add-one',
uuid, aci,
}, },
options options
); );

File diff suppressed because it is too large Load diff

View file

@ -2,13 +2,14 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { useEffect } from 'react'; import { useEffect } from 'react';
import type { AciString } from '../types/ServiceId';
import { usePrevious } from './usePrevious'; import { usePrevious } from './usePrevious';
type RemoteParticipant = { type RemoteParticipant = {
hasRemoteVideo: boolean; hasRemoteVideo: boolean;
presenting: boolean; presenting: boolean;
title: string; title: string;
uuid?: string; aci?: AciString;
}; };
export function useActivateSpeakerViewOnPresenting({ export function useActivateSpeakerViewOnPresenting({
@ -20,20 +21,20 @@ export function useActivateSpeakerViewOnPresenting({
switchToPresentationView: () => void; switchToPresentationView: () => void;
switchFromPresentationView: () => void; switchFromPresentationView: () => void;
}): void { }): void {
const presenterUuid = remoteParticipants.find( const presenterAci = remoteParticipants.find(
participant => participant.presenting participant => participant.presenting
)?.uuid; )?.aci;
const prevPresenterUuid = usePrevious(presenterUuid, presenterUuid); const prevPresenterAci = usePrevious(presenterAci, presenterAci);
useEffect(() => { useEffect(() => {
if (prevPresenterUuid !== presenterUuid && presenterUuid) { if (prevPresenterAci !== presenterAci && presenterAci) {
switchToPresentationView(); switchToPresentationView();
} else if (prevPresenterUuid && !presenterUuid) { } else if (prevPresenterAci && !presenterAci) {
switchFromPresentationView(); switchFromPresentationView();
} }
}, [ }, [
presenterUuid, presenterAci,
prevPresenterUuid, prevPresenterAci,
switchToPresentationView, switchToPresentationView,
switchFromPresentationView, switchFromPresentationView,
]); ]);

View file

@ -39,6 +39,7 @@ import type { ServiceIdString } from '../types/ServiceId';
import { commonShouldJobContinue } from './helpers/commonShouldJobContinue'; import { commonShouldJobContinue } from './helpers/commonShouldJobContinue';
import { sleeper } from '../util/sleeper'; import { sleeper } from '../util/sleeper';
import { receiptSchema, ReceiptType } from '../types/Receipt'; import { receiptSchema, ReceiptType } from '../types/Receipt';
import { serviceIdSchema, aciSchema } from '../types/ServiceId';
import { sendResendRequest } from './helpers/sendResendRequest'; import { sendResendRequest } from './helpers/sendResendRequest';
import { sendNullMessage } from './helpers/sendNullMessage'; import { sendNullMessage } from './helpers/sendNullMessage';
import { sendSenderKeyDistribution } from './helpers/sendSenderKeyDistribution'; import { sendSenderKeyDistribution } from './helpers/sendSenderKeyDistribution';
@ -82,12 +83,7 @@ const deleteStoryForEveryoneJobDataSchema = z.object({
updatedStoryRecipients: z updatedStoryRecipients: z
.array( .array(
z.object({ z.object({
// TODO: DESKTOP-5630 destinationServiceId: serviceIdSchema.optional(),
destinationUuid: z.string().optional(),
legacyDestinationUuid: z.string().optional(),
destinationAci: z.string().optional(),
destinationPni: z.string().optional(),
distributionListIds: z.array(z.string()), distributionListIds: z.array(z.string()),
isAllowedToReply: z.boolean(), isAllowedToReply: z.boolean(),
}) })
@ -162,7 +158,7 @@ const resendRequestJobDataSchema = z.object({
plaintext: z.string(), plaintext: z.string(),
receivedAtCounter: z.number(), receivedAtCounter: z.number(),
receivedAtDate: z.number(), receivedAtDate: z.number(),
senderUuid: z.string(), senderAci: aciSchema,
senderDevice: z.number(), senderDevice: z.number(),
timestamp: z.number(), timestamp: z.number(),
}); });

View file

@ -5,6 +5,7 @@ import { assertDev } from '../../util/assert';
import { isDirectConversation } from '../../util/whatTypeOfConversation'; import { isDirectConversation } from '../../util/whatTypeOfConversation';
import * as log from '../../logging/log'; import * as log from '../../logging/log';
import type { ConversationAttributesType } from '../../model-types.d'; import type { ConversationAttributesType } from '../../model-types.d';
import { isAciString } from '../../types/ServiceId';
import type { reportSpamJobQueue } from '../reportSpamJobQueue'; import type { reportSpamJobQueue } from '../reportSpamJobQueue';
export async function addReportSpamJob({ export async function addReportSpamJob({
@ -13,7 +14,10 @@ export async function addReportSpamJob({
jobQueue, jobQueue,
}: Readonly<{ }: Readonly<{
conversation: Readonly< conversation: Readonly<
Pick<ConversationAttributesType, 'id' | 'type' | 'uuid' | 'reportingToken'> Pick<
ConversationAttributesType,
'id' | 'type' | 'serviceId' | 'reportingToken'
>
>; >;
getMessageServerGuidsForSpam: ( getMessageServerGuidsForSpam: (
conversationId: string conversationId: string
@ -25,10 +29,10 @@ export async function addReportSpamJob({
'addReportSpamJob: cannot report spam for non-direct conversations' 'addReportSpamJob: cannot report spam for non-direct conversations'
); );
const { uuid } = conversation; const { serviceId: aci } = conversation;
if (!uuid) { if (!aci || !isAciString(aci)) {
log.info( log.info(
'addReportSpamJob got a conversation with no UUID, which the server does not support. Doing nothing' 'addReportSpamJob got a conversation with no aci, which the server does not support. Doing nothing'
); );
return; return;
} }
@ -44,5 +48,5 @@ export async function addReportSpamJob({
return; return;
} }
await jobQueue.add({ uuid, serverGuids, token: conversation.reportingToken }); await jobQueue.add({ aci, serverGuids, token: conversation.reportingToken });
} }

View file

@ -243,7 +243,7 @@ export async function sendDeleteStoryForEveryone(
destination: undefined, destination: undefined,
destinationServiceId, destinationServiceId,
storyMessageRecipients: updatedStoryRecipients?.map( storyMessageRecipients: updatedStoryRecipients?.map(
({ destinationUuid: legacyDestinationUuid, ...rest }) => { ({ destinationServiceId: legacyDestinationUuid, ...rest }) => {
return { return {
// The field was renamed. // The field was renamed.
legacyDestinationUuid, legacyDestinationUuid,

View file

@ -559,12 +559,11 @@ async function getMessageSendData({
}); });
const storyReaction = message.get('storyReaction'); const storyReaction = message.get('storyReaction');
const storySourceUuid = storyMessage?.get('sourceUuid'); const storySourceServiceId = storyMessage?.get('sourceServiceId');
let reactionForSend: ReactionType | undefined; let reactionForSend: ReactionType | undefined;
if (storyReaction) { if (storyReaction) {
const { targetAuthorUuid: targetAuthorAci, ...restOfReaction } = const { targetAuthorAci, ...restOfReaction } = storyReaction;
storyReaction;
reactionForSend = { reactionForSend = {
...restOfReaction, ...restOfReaction,
@ -592,9 +591,9 @@ async function getMessageSendData({
storyMessage, storyMessage,
storyContext: storyMessage storyContext: storyMessage
? { ? {
authorAci: storySourceUuid authorAci: storySourceServiceId
? normalizeAci( ? normalizeAci(
storySourceUuid, storySourceServiceId,
'sendNormalMessage.storyContext.authorAci' 'sendNormalMessage.storyContext.authorAci'
) )
: undefined, : undefined,
@ -716,11 +715,8 @@ async function uploadMessageQuote(
return { return {
isGiftBadge: loadedQuote.isGiftBadge, isGiftBadge: loadedQuote.isGiftBadge,
id: loadedQuote.id, id: loadedQuote.id,
authorAci: loadedQuote.authorUuid authorAci: loadedQuote.authorAci
? normalizeAci( ? normalizeAci(loadedQuote.authorAci, 'sendNormalMessage.quote.authorAci')
loadedQuote.authorUuid,
'sendNormalMessage.quote.authorUuid'
)
: undefined, : undefined,
text: loadedQuote.text, text: loadedQuote.text,
bodyRanges: loadedQuote.bodyRanges, bodyRanges: loadedQuote.bodyRanges,

View file

@ -136,11 +136,8 @@ export async function sendReaction(
? await ourProfileKeyService.get() ? await ourProfileKeyService.get()
: undefined; : undefined;
const { const { emoji, targetAuthorAci, ...restOfPendingReaction } =
emoji, pendingReaction;
targetAuthorUuid: targetAuthorAci,
...restOfPendingReaction
} = pendingReaction;
const reactionForSend = { const reactionForSend = {
...restOfPendingReaction, ...restOfPendingReaction,

View file

@ -26,7 +26,6 @@ import { drop } from '../../util/drop';
import { strictAssert } from '../../util/assert'; import { strictAssert } from '../../util/assert';
import type { DecryptionErrorEventData } from '../../textsecure/messageReceiverEvents'; import type { DecryptionErrorEventData } from '../../textsecure/messageReceiverEvents';
import type { LoggerType } from '../../types/Logging'; import type { LoggerType } from '../../types/Logging';
import { isAciString } from '../../types/ServiceId';
import { startAutomaticSessionReset } from '../../util/handleRetry'; import { startAutomaticSessionReset } from '../../util/handleRetry';
function failoverToLocalReset( function failoverToLocalReset(
@ -49,9 +48,8 @@ export async function sendResendRequest(
timeRemaining, timeRemaining,
log, log,
}: ConversationQueueJobBundle, }: ConversationQueueJobBundle,
{ senderUuid: senderAci, ...restOfData }: ResendRequestJobData { senderAci, ...restOfData }: ResendRequestJobData
): Promise<void> { ): Promise<void> {
strictAssert(isAciString(senderAci), 'senderUuid is not an ACI');
const data = { const data = {
...restOfData, ...restOfData,
senderAci, senderAci,
@ -90,9 +88,8 @@ export async function sendResendRequest(
// Note: we will send to blocked users, to those still in message request state, etc. // Note: we will send to blocked users, to those still in message request state, etc.
// Any needed blocking should still apply once the decryption error is fixed. // Any needed blocking should still apply once the decryption error is fixed.
const senderUuid = conversation.get('uuid'); if (conversation.getAci() !== senderAci) {
if (!senderUuid) { log.error('conversation was missing a aci, cancelling job.');
log.error('conversation was missing a uuid, cancelling job.');
failoverToLocalReset(log, data); failoverToLocalReset(log, data);
return; return;
} }
@ -113,7 +110,7 @@ export async function sendResendRequest(
await handleMessageSend( await handleMessageSend(
messaging.sendMessageProtoAndWait({ messaging.sendMessageProtoAndWait({
timestamp, timestamp,
recipients: [senderUuid], recipients: [senderAci],
proto: plaintext, proto: plaintext,
contentHint: ContentHint.DEFAULT, contentHint: ContentHint.DEFAULT,
groupId, groupId,
@ -141,7 +138,7 @@ export async function sendResendRequest(
receivedAt: receivedAtDate, receivedAt: receivedAtDate,
receivedAtCounter, receivedAtCounter,
sentAt: timestamp, sentAt: timestamp,
senderUuid, senderAci,
wasOpened, wasOpened,
}); });
@ -162,7 +159,7 @@ export async function sendResendRequest(
await conversation.addDeliveryIssue({ await conversation.addDeliveryIssue({
receivedAt: receivedAtDate, receivedAt: receivedAtDate,
receivedAtCounter, receivedAtCounter,
senderUuid, senderAci,
sentAt: timestamp, sentAt: timestamp,
}); });
}) })

View file

@ -57,10 +57,10 @@ export async function sendSavedProto(
return; return;
} }
const uuid = conversation.get('uuid'); const serviceId = conversation.getServiceId();
if (!uuid) { if (!serviceId) {
log.info( log.info(
`conversation ${conversation.idForLogging()} was missing uuid, cancelling job.` `conversation ${conversation.idForLogging()} was missing serviceId, cancelling job.`
); );
return; return;
} }
@ -84,7 +84,7 @@ export async function sendSavedProto(
groupId, groupId,
options: sendOptions, options: sendOptions,
proto, proto,
recipients: [uuid], recipients: [serviceId],
timestamp: originalTimestamp, timestamp: originalTimestamp,
urgent, urgent,
story, story,

View file

@ -206,7 +206,7 @@ export async function sendStory(
serviceId: ServiceIdString, serviceId: ServiceIdString,
canReply?: boolean canReply?: boolean
): void { ): void {
if (conversation.get('uuid') === serviceId) { if (conversation.getServiceId() === serviceId) {
return; return;
} }

View file

@ -3,6 +3,7 @@
import { chunk } from 'lodash'; import { chunk } from 'lodash';
import type { LoggerType } from '../../types/Logging'; import type { LoggerType } from '../../types/Logging';
import type { AciString } from '../../types/ServiceId';
import { normalizeAci } from '../../types/ServiceId'; import { normalizeAci } from '../../types/ServiceId';
import { getSendOptions } from '../../util/getSendOptions'; import { getSendOptions } from '../../util/getSendOptions';
import type { SendTypesType } from '../../util/handleMessageSend'; import type { SendTypesType } from '../../util/handleMessageSend';
@ -21,7 +22,7 @@ const CHUNK_SIZE = 100;
export type SyncType = { export type SyncType = {
messageId?: string; messageId?: string;
senderE164?: string; senderE164?: string;
senderUuid?: string; senderAci?: AciString;
timestamp: number; timestamp: number;
}; };
export enum SyncTypeList { export enum SyncTypeList {
@ -41,13 +42,18 @@ export function parseRawSyncDataArray(value: unknown): Array<SyncType> {
return value.map((item: unknown) => { return value.map((item: unknown) => {
strictAssert(isRecord(item), 'sync is not an object'); strictAssert(isRecord(item), 'sync is not an object');
const { messageId, senderE164, senderUuid, timestamp } = item; const { messageId, senderE164, timestamp } = item;
strictAssert(typeof timestamp === 'number', 'timestamp should be a number'); strictAssert(typeof timestamp === 'number', 'timestamp should be a number');
const rawSenderAci = parseOptionalString('senderAci', item.senderAci);
const senderAci = rawSenderAci
? normalizeAci(rawSenderAci, 'parseRawSyncDataArray')
: undefined;
return { return {
messageId: parseOptionalString('messageId', messageId), messageId: parseOptionalString('messageId', messageId),
senderE164: parseOptionalString('senderE164', senderE164), senderE164: parseOptionalString('senderE164', senderE164),
senderUuid: parseOptionalString('senderUuid', senderUuid), senderAci,
timestamp, timestamp,
}; };
}); });
@ -148,11 +154,11 @@ export async function runSyncJob({
} }
} }
const aciSyncs = syncs.map(({ senderUuid, ...rest }) => { const aciSyncs = syncs.map(({ senderAci, ...rest }) => {
return { return {
...rest, ...rest,
senderAci: senderUuid senderAci: senderAci
? normalizeAci(senderUuid, 'syncHelpers.senderUuid') ? normalizeAci(senderAci, 'syncHelpers.senderAci')
: undefined, : undefined,
}; };
}); });

View file

@ -7,6 +7,7 @@ import { strictAssert } from '../util/assert';
import { waitForOnline } from '../util/waitForOnline'; import { waitForOnline } from '../util/waitForOnline';
import { isDone as isDeviceLinked } from '../util/registration'; import { isDone as isDeviceLinked } from '../util/registration';
import type { LoggerType } from '../types/Logging'; import type { LoggerType } from '../types/Logging';
import { aciSchema } from '../types/ServiceId';
import { map } from '../util/iterables'; import { map } from '../util/iterables';
import { JobQueue } from './JobQueue'; import { JobQueue } from './JobQueue';
@ -27,7 +28,7 @@ const isRetriable4xxStatus = (code: number): boolean =>
RETRYABLE_4XX_FAILURE_STATUSES.has(code); RETRYABLE_4XX_FAILURE_STATUSES.has(code);
const reportSpamJobDataSchema = z.object({ const reportSpamJobDataSchema = z.object({
uuid: z.string().min(1), aci: aciSchema,
token: z.string().optional(), token: z.string().optional(),
serverGuids: z.string().array().min(1).max(1000), serverGuids: z.string().array().min(1).max(1000),
}); });
@ -49,7 +50,7 @@ export class ReportSpamJobQueue extends JobQueue<ReportSpamJobData> {
{ data }: Readonly<{ data: ReportSpamJobData }>, { data }: Readonly<{ data: ReportSpamJobData }>,
{ log }: Readonly<{ log: LoggerType }> { log }: Readonly<{ log: LoggerType }>
): Promise<void> { ): Promise<void> {
const { uuid: senderUuid, token, serverGuids } = data; const { aci: senderAci, token, serverGuids } = data;
await new Promise<void>(resolve => { await new Promise<void>(resolve => {
window.storage.onready(resolve); window.storage.onready(resolve);
@ -68,7 +69,7 @@ export class ReportSpamJobQueue extends JobQueue<ReportSpamJobData> {
try { try {
await Promise.all( await Promise.all(
map(serverGuids, serverGuid => map(serverGuids, serverGuid =>
server.reportMessage({ senderUuid, serverGuid, token }) server.reportMessage({ senderAci, serverGuid, token })
) )
); );
} catch (err: unknown) { } catch (err: unknown) {

View file

@ -67,7 +67,7 @@ export class SingleProtoJobQueue extends JobQueue<SingleProtoJobData> {
const { const {
contentHint, contentHint,
identifier, serviceId,
isSyncMessage, isSyncMessage,
messageIds = [], messageIds = [],
protoBase64, protoBase64,
@ -75,14 +75,12 @@ export class SingleProtoJobQueue extends JobQueue<SingleProtoJobData> {
urgent, urgent,
} = data; } = data;
log.info( log.info(
`starting ${type} send to ${identifier} with timestamp ${timestamp}` `starting ${type} send to ${serviceId} with timestamp ${timestamp}`
); );
const conversation = window.ConversationController.get(identifier); const conversation = window.ConversationController.get(serviceId);
if (!conversation) { if (!conversation) {
throw new Error( throw new Error(`Failed to get conversation for serviceId ${serviceId}`);
`Failed to get conversation for identifier ${identifier}`
);
} }
if (!isConversationAccepted(conversation.attributes)) { if (!isConversationAccepted(conversation.attributes)) {
@ -103,13 +101,6 @@ export class SingleProtoJobQueue extends JobQueue<SingleProtoJobData> {
); );
return; return;
} }
const serviceId = conversation.getServiceId();
if (!serviceId) {
log.info(
`conversation ${conversation.idForLogging()} has no serviceId; refusing to send`
);
return;
}
const proto = Proto.Content.decode(Bytes.fromBase64(protoBase64)); const proto = Proto.Content.decode(Bytes.fromBase64(protoBase64));
const options = await getSendOptions(conversation.attributes, { const options = await getSendOptions(conversation.attributes, {

View file

@ -28,7 +28,7 @@ export function forMessage(
| 'editMessageTimestamp' | 'editMessageTimestamp'
| 'sent_at' | 'sent_at'
| 'source' | 'source'
| 'sourceUuid' | 'sourceServiceId'
| 'timestamp' | 'timestamp'
| 'type' | 'type'
> >

View file

@ -23,7 +23,7 @@ import {
import type { DeleteSentProtoRecipientOptionsType } from '../sql/Interface'; import type { DeleteSentProtoRecipientOptionsType } from '../sql/Interface';
import dataInterface from '../sql/Client'; import dataInterface from '../sql/Client';
import * as log from '../logging/log'; import * as log from '../logging/log';
import { getSourceUuid } from '../messages/helpers'; import { getSourceServiceId } from '../messages/helpers';
import { queueUpdateMessage } from '../util/messageBatcher'; import { queueUpdateMessage } from '../util/messageBatcher';
import { getMessageSentTimestamp } from '../util/getMessageSentTimestamp'; import { getMessageSentTimestamp } from '../util/getMessageSentTimestamp';
@ -61,8 +61,8 @@ const deleteSentProtoBatcher = createWaitBatcher({
items items
); );
for (const uuid of successfulPhoneNumberShares) { for (const serviceId of successfulPhoneNumberShares) {
const convo = window.ConversationController.get(uuid); const convo = window.ConversationController.get(serviceId);
if (!convo) { if (!convo) {
continue; continue;
} }
@ -158,8 +158,8 @@ export class MessageReceipts extends Collection<MessageReceiptModel> {
} }
const ourAci = window.textsecure.storage.user.getCheckedAci(); const ourAci = window.textsecure.storage.user.getCheckedAci();
const sourceUuid = getSourceUuid(message.attributes); const sourceServiceId = getSourceServiceId(message.attributes);
if (ourAci !== sourceUuid) { if (ourAci !== sourceServiceId) {
return []; return [];
} }
@ -327,7 +327,7 @@ export class MessageReceipts extends Collection<MessageReceiptModel> {
]); ]);
} else { } else {
log.warn( log.warn(
`MessageReceipts.onReceipt: Missing uuid or deviceId for deliveredTo ${sourceConversationId}` `MessageReceipts.onReceipt: Missing serviceId or deviceId for deliveredTo ${sourceConversationId}`
); );
} }
} }

View file

@ -43,16 +43,16 @@ export class MessageRequests extends Collection<MessageRequestModel> {
} }
} }
if (conversation.get('uuid')) { if (conversation.getServiceId()) {
const syncByUuid = this.findWhere({ const syncByAci = this.findWhere({
threadAci: conversation.get('uuid'), threadAci: conversation.getServiceId(),
}); });
if (syncByUuid) { if (syncByAci) {
log.info( log.info(
`Found early message request response for UUID ${conversation.idForLogging()}` `Found early message request response for aci ${conversation.idForLogging()}`
); );
this.remove(syncByUuid); this.remove(syncByAci);
return syncByUuid; return syncByAci;
} }
} }
@ -88,7 +88,7 @@ export class MessageRequests extends Collection<MessageRequestModel> {
if (!conversation && (threadE164 || threadAci)) { if (!conversation && (threadE164 || threadAci)) {
conversation = window.ConversationController.lookupOrCreate({ conversation = window.ConversationController.lookupOrCreate({
e164: threadE164, e164: threadE164,
uuid: threadAci, serviceId: threadAci,
reason: 'MessageRequests.onResponse', reason: 'MessageRequests.onResponse',
}); });
} }

View file

@ -48,7 +48,7 @@ export class Reactions extends Collection<ReactionModel> {
const senderId = getContactId(message.attributes); const senderId = getContactId(message.attributes);
const reactionsBySource = this.filter(re => { const reactionsBySource = this.filter(re => {
const targetSender = window.ConversationController.lookupOrCreate({ const targetSender = window.ConversationController.lookupOrCreate({
uuid: re.get('targetAuthorUuid'), serviceId: re.get('targetAuthorAci'),
reason: 'Reactions.forMessage', reason: 'Reactions.forMessage',
}); });
const targetTimestamp = re.get('targetTimestamp'); const targetTimestamp = re.get('targetTimestamp');
@ -92,7 +92,7 @@ export class Reactions extends Collection<ReactionModel> {
// to to figure that out. // to to figure that out.
const targetAuthorConversation = const targetAuthorConversation =
window.ConversationController.lookupOrCreate({ window.ConversationController.lookupOrCreate({
uuid: reaction.get('targetAuthorUuid'), serviceId: reaction.get('targetAuthorAci'),
reason: 'Reactions.onReaction', reason: 'Reactions.onReaction',
}); });
const targetConversationId = targetAuthorConversation?.id; const targetConversationId = targetAuthorConversation?.id;
@ -122,7 +122,7 @@ export class Reactions extends Collection<ReactionModel> {
'No message for reaction', 'No message for reaction',
reaction.get('timestamp'), reaction.get('timestamp'),
'targeting', 'targeting',
reaction.get('targetAuthorUuid'), reaction.get('targetAuthorAci'),
reaction.get('targetTimestamp') reaction.get('targetTimestamp')
); );
@ -147,7 +147,7 @@ export class Reactions extends Collection<ReactionModel> {
if (!targetConversation) { if (!targetConversation) {
log.info( log.info(
'No target conversation for reaction', 'No target conversation for reaction',
reaction.get('targetAuthorUuid'), reaction.get('targetAuthorAci'),
reaction.get('targetTimestamp') reaction.get('targetTimestamp')
); );
return undefined; return undefined;

View file

@ -48,7 +48,7 @@ async function maybeItIsAReactionReadSync(sync: ReadSyncModel): Promise<void> {
notificationService.removeBy({ notificationService.removeBy({
conversationId: readReaction.conversationId, conversationId: readReaction.conversationId,
emoji: readReaction.emoji, emoji: readReaction.emoji,
targetAuthorUuid: readReaction.targetAuthorUuid, targetAuthorAci: readReaction.targetAuthorAci,
targetTimestamp: readReaction.targetTimestamp, targetTimestamp: readReaction.targetTimestamp,
}); });
} }
@ -65,7 +65,7 @@ export class ReadSyncs extends Collection {
forMessage(message: MessageModel): ReadSyncModel | null { forMessage(message: MessageModel): ReadSyncModel | null {
const sender = window.ConversationController.lookupOrCreate({ const sender = window.ConversationController.lookupOrCreate({
e164: message.get('source'), e164: message.get('source'),
uuid: message.get('sourceUuid'), serviceId: message.get('sourceServiceId'),
reason: 'ReadSyncs.forMessage', reason: 'ReadSyncs.forMessage',
}); });
const messageTimestamp = getMessageSentTimestamp(message.attributes, { const messageTimestamp = getMessageSentTimestamp(message.attributes, {
@ -95,7 +95,7 @@ export class ReadSyncs extends Collection {
const found = messages.find(item => { const found = messages.find(item => {
const sender = window.ConversationController.lookupOrCreate({ const sender = window.ConversationController.lookupOrCreate({
e164: item.source, e164: item.source,
uuid: item.sourceUuid, serviceId: item.sourceServiceId,
reason: 'ReadSyncs.onSync', reason: 'ReadSyncs.onSync',
}); });

View file

@ -29,16 +29,16 @@ export class ViewOnceOpenSyncs extends Collection<ViewOnceOpenSyncModel> {
} }
forMessage(message: MessageModel): ViewOnceOpenSyncModel | null { forMessage(message: MessageModel): ViewOnceOpenSyncModel | null {
const syncBySourceUuid = this.find(item => { const syncBySourceAci = this.find(item => {
return ( return (
item.get('sourceAci') === message.get('sourceUuid') && item.get('sourceAci') === message.get('sourceServiceId') &&
item.get('timestamp') === message.get('sent_at') item.get('timestamp') === message.get('sent_at')
); );
}); });
if (syncBySourceUuid) { if (syncBySourceAci) {
log.info('Found early view once open sync for message'); log.info('Found early view once open sync for message');
this.remove(syncBySourceUuid); this.remove(syncBySourceAci);
return syncBySourceUuid; return syncBySourceAci;
} }
const syncBySource = this.find(item => { const syncBySource = this.find(item => {
@ -63,7 +63,7 @@ export class ViewOnceOpenSyncs extends Collection<ViewOnceOpenSyncModel> {
); );
const found = messages.find(item => { const found = messages.find(item => {
const itemSourceAci = item.sourceUuid; const itemSourceAci = item.sourceServiceId;
const syncSourceAci = sync.get('sourceAci'); const syncSourceAci = sync.get('sourceAci');
const itemSource = item.source; const itemSource = item.source;
const syncSource = sync.get('source'); const syncSource = sync.get('source');

View file

@ -43,7 +43,7 @@ export class ViewSyncs extends Collection {
forMessage(message: MessageModel): Array<ViewSyncModel> { forMessage(message: MessageModel): Array<ViewSyncModel> {
const sender = window.ConversationController.lookupOrCreate({ const sender = window.ConversationController.lookupOrCreate({
e164: message.get('source'), e164: message.get('source'),
uuid: message.get('sourceUuid'), serviceId: message.get('sourceServiceId'),
reason: 'ViewSyncs.forMessage', reason: 'ViewSyncs.forMessage',
}); });
const messageTimestamp = getMessageSentTimestamp(message.attributes, { const messageTimestamp = getMessageSentTimestamp(message.attributes, {
@ -73,7 +73,7 @@ export class ViewSyncs extends Collection {
const found = messages.find(item => { const found = messages.find(item => {
const sender = window.ConversationController.lookupOrCreate({ const sender = window.ConversationController.lookupOrCreate({
e164: item.source, e164: item.source,
uuid: item.sourceUuid, serviceId: item.sourceServiceId,
reason: 'ViewSyncs.onSync', reason: 'ViewSyncs.onSync',
}); });

View file

@ -111,16 +111,16 @@ export function getPaymentEventDescription(
export function isQuoteAMatch( export function isQuoteAMatch(
message: MessageAttributesType | null | undefined, message: MessageAttributesType | null | undefined,
conversationId: string, conversationId: string,
quote: Pick<QuotedMessageType, 'id' | 'authorUuid' | 'author'> quote: Pick<QuotedMessageType, 'id' | 'authorAci' | 'author'>
): message is MessageAttributesType { ): message is MessageAttributesType {
if (!message) { if (!message) {
return false; return false;
} }
const { authorUuid, id } = quote; const { authorAci, id } = quote;
const authorConversation = window.ConversationController.lookupOrCreate({ const authorConversation = window.ConversationController.lookupOrCreate({
e164: 'author' in quote ? quote.author : undefined, e164: 'author' in quote ? quote.author : undefined,
uuid: authorUuid, serviceId: authorAci,
reason: 'helpers.isQuoteAMatch', reason: 'helpers.isQuoteAMatch',
}); });
@ -137,18 +137,18 @@ export function isQuoteAMatch(
} }
export function getContactId( export function getContactId(
message: Pick<MessageAttributesType, 'type' | 'source' | 'sourceUuid'> message: Pick<MessageAttributesType, 'type' | 'source' | 'sourceServiceId'>
): string | undefined { ): string | undefined {
const source = getSource(message); const source = getSource(message);
const sourceUuid = getSourceUuid(message); const sourceServiceId = getSourceServiceId(message);
if (!source && !sourceUuid) { if (!source && !sourceServiceId) {
return window.ConversationController.getOurConversationId(); return window.ConversationController.getOurConversationId();
} }
const conversation = window.ConversationController.lookupOrCreate({ const conversation = window.ConversationController.lookupOrCreate({
e164: source, e164: source,
uuid: sourceUuid, serviceId: sourceServiceId,
reason: 'helpers.getContactId', reason: 'helpers.getContactId',
}); });
return conversation?.id; return conversation?.id;
@ -191,15 +191,15 @@ export function getSourceDevice(
return sourceDevice || window.textsecure.storage.user.getDeviceId(); return sourceDevice || window.textsecure.storage.user.getDeviceId();
} }
export function getSourceUuid( export function getSourceServiceId(
message: Pick<MessageAttributesType, 'type' | 'sourceUuid'> message: Pick<MessageAttributesType, 'type' | 'sourceServiceId'>
): ServiceIdString | undefined { ): ServiceIdString | undefined {
if (isIncoming(message) || isStory(message)) { if (isIncoming(message) || isStory(message)) {
return message.sourceUuid; return message.sourceServiceId;
} }
if (!isOutgoing(message)) { if (!isOutgoing(message)) {
log.warn( log.warn(
'Message.getSourceUuid: Called for non-incoming/non-outgoing message' 'Message.getSourceServiceId: Called for non-incoming/non-outgoing message'
); );
} }

47
ts/model-types.d.ts vendored
View file

@ -49,7 +49,7 @@ export type LastMessageStatus =
export type SenderKeyDeviceType = { export type SenderKeyDeviceType = {
id: number; id: number;
identifier: string; serviceId: ServiceIdString;
registrationId: number; registrationId: number;
}; };
@ -69,7 +69,7 @@ export type CustomError = Error & {
export type GroupMigrationType = { export type GroupMigrationType = {
areWeInvited: boolean; areWeInvited: boolean;
droppedMemberIds: Array<string>; droppedMemberIds: Array<string>;
invitedMembers: Array<GroupV2PendingMemberType>; invitedMembers: Array<LegacyMigrationPendingMemberType>;
}; };
export type QuotedAttachment = { export type QuotedAttachment = {
@ -86,7 +86,7 @@ export type QuotedMessageType = {
// `author` is an old attribute that holds the author's E164. We shouldn't use it for // `author` is an old attribute that holds the author's E164. We shouldn't use it for
// new messages, but old messages might have this attribute. // new messages, but old messages might have this attribute.
author?: string; author?: string;
authorUuid?: string; authorAci?: AciString;
bodyRanges?: ReadonlyArray<RawBodyRange>; bodyRanges?: ReadonlyArray<RawBodyRange>;
id: number; id: number;
isGiftBadge?: boolean; isGiftBadge?: boolean;
@ -98,17 +98,10 @@ export type QuotedMessageType = {
type StoryReplyContextType = { type StoryReplyContextType = {
attachment?: AttachmentType; attachment?: AttachmentType;
authorUuid?: string; authorAci?: AciString;
messageId: string; messageId: string;
}; };
export type RetryOptions = Readonly<{
type: 'session-reset';
uuid: string;
e164: string;
now: number;
}>;
export type GroupV1Update = { export type GroupV1Update = {
avatarUpdated?: boolean; avatarUpdated?: boolean;
joined?: Array<string>; joined?: Array<string>;
@ -119,7 +112,7 @@ export type GroupV1Update = {
export type MessageReactionType = { export type MessageReactionType = {
emoji: undefined | string; emoji: undefined | string;
fromId: string; fromId: string;
targetAuthorUuid: AciString; targetAuthorAci: AciString;
targetTimestamp: number; targetTimestamp: number;
timestamp: number; timestamp: number;
isSentByConversationId?: Record<string, boolean>; isSentByConversationId?: Record<string, boolean>;
@ -169,7 +162,6 @@ export type MessageAttributesType = {
quote?: QuotedMessageType; quote?: QuotedMessageType;
reactions?: ReadonlyArray<MessageReactionType>; reactions?: ReadonlyArray<MessageReactionType>;
requiredProtocolVersion?: number; requiredProtocolVersion?: number;
retryOptions?: RetryOptions;
sourceDevice?: number; sourceDevice?: number;
storyDistributionListId?: StoryDistributionIdString; storyDistributionListId?: StoryDistributionIdString;
storyId?: string; storyId?: string;
@ -210,7 +202,7 @@ export type MessageAttributesType = {
conversationId: string; conversationId: string;
storyReaction?: { storyReaction?: {
emoji: string; emoji: string;
targetAuthorUuid: AciString; targetAuthorAci: AciString;
targetTimestamp: number; targetTimestamp: number;
}; };
giftBadge?: { giftBadge?: {
@ -225,7 +217,7 @@ export type MessageAttributesType = {
expireTimer?: DurationInSeconds; expireTimer?: DurationInSeconds;
fromSync?: unknown; fromSync?: unknown;
source?: string; source?: string;
sourceUuid?: ServiceIdString; sourceServiceId?: ServiceIdString;
}; };
conversationMerge?: { conversationMerge?: {
renderInfo: ConversationRenderInfoType; renderInfo: ConversationRenderInfoType;
@ -249,12 +241,12 @@ export type MessageAttributesType = {
serverGuid?: string; serverGuid?: string;
serverTimestamp?: number; serverTimestamp?: number;
source?: string; source?: string;
sourceUuid?: ServiceIdString; sourceServiceId?: ServiceIdString;
timestamp: number; timestamp: number;
// Backwards-compatibility with prerelease data schema // Backwards-compatibility with prerelease data schema
invitedGV2Members?: Array<GroupV2PendingMemberType>; invitedGV2Members?: Array<LegacyMigrationPendingMemberType>;
droppedGV2MemberIds?: Array<string>; droppedGV2MemberIds?: Array<string>;
sendHQImages?: boolean; sendHQImages?: boolean;
@ -283,7 +275,7 @@ export type ConversationLastProfileType = Readonly<{
export type ValidateConversationType = Pick< export type ValidateConversationType = Pick<
ConversationAttributesType, ConversationAttributesType,
'e164' | 'uuid' | 'type' | 'groupId' 'e164' | 'serviceId' | 'type' | 'groupId'
>; >;
export type DraftEditMessageType = { export type DraftEditMessageType = {
@ -378,7 +370,7 @@ export type ConversationAttributesType = {
version: number; version: number;
// Private core info // Private core info
uuid?: ServiceIdString; serviceId?: ServiceIdString;
pni?: PniString; pni?: PniString;
e164?: string; e164?: string;
@ -470,7 +462,7 @@ export type ConversationRenderInfoType = Pick<
>; >;
export type GroupV2MemberType = { export type GroupV2MemberType = {
uuid: AciString; aci: AciString;
role: MemberRoleEnum; role: MemberRoleEnum;
joinedAtVersion: number; joinedAtVersion: number;
@ -481,20 +473,27 @@ export type GroupV2MemberType = {
approvedByAdmin?: boolean; approvedByAdmin?: boolean;
}; };
export type LegacyMigrationPendingMemberType = {
addedByUserId?: string;
uuid: string;
timestamp: number;
role: MemberRoleEnum;
};
export type GroupV2PendingMemberType = { export type GroupV2PendingMemberType = {
addedByUserId?: AciString; addedByUserId?: AciString;
uuid: ServiceIdString; serviceId: ServiceIdString;
timestamp: number; timestamp: number;
role: MemberRoleEnum; role: MemberRoleEnum;
}; };
export type GroupV2BannedMemberType = { export type GroupV2BannedMemberType = {
uuid: ServiceIdString; serviceId: ServiceIdString;
timestamp: number; timestamp: number;
}; };
export type GroupV2PendingAdminApprovalType = { export type GroupV2PendingAdminApprovalType = {
uuid: AciString; aci: AciString;
timestamp: number; timestamp: number;
}; };
@ -517,7 +516,7 @@ export type ReactionAttributesType = {
// Necessary to put 1:1 story replies into the right conversation - not the same // Necessary to put 1:1 story replies into the right conversation - not the same
// conversation as the target message! // conversation as the target message!
storyReactionMessage?: MessageModel; storyReactionMessage?: MessageModel;
targetAuthorUuid: AciString; targetAuthorAci: AciString;
targetTimestamp: number; targetTimestamp: number;
timestamp: number; timestamp: number;
}; };

View file

@ -82,7 +82,6 @@ import type { DraftBodyRanges } from '../types/BodyRange';
import { BodyRange } from '../types/BodyRange'; import { BodyRange } from '../types/BodyRange';
import { migrateColor } from '../util/migrateColor'; import { migrateColor } from '../util/migrateColor';
import { isNotNil } from '../util/isNotNil'; import { isNotNil } from '../util/isNotNil';
import { resolveSenderKeyDevice } from '../util/resolveSenderKeyDevice';
import { import {
NotificationType, NotificationType,
notificationService, notificationService,
@ -304,15 +303,16 @@ export class ConversationModel extends window.Backbone
// Note that we intentionally don't use `initialize()` method because it // Note that we intentionally don't use `initialize()` method because it
// isn't compatible with esnext output of esbuild. // isn't compatible with esnext output of esbuild.
const uuid = this.get('uuid'); const serviceId = this.getServiceId();
const normalizedServiceId = const normalizedServiceId =
uuid && normalizeServiceId(uuid, 'ConversationModel.initialize'); serviceId &&
if (uuid && normalizedServiceId !== uuid) { normalizeServiceId(serviceId, 'ConversationModel.initialize');
if (serviceId && normalizedServiceId !== serviceId) {
log.warn( log.warn(
'ConversationModel.initialize: normalizing serviceId from ' + 'ConversationModel.initialize: normalizing serviceId from ' +
`${uuid} to ${normalizedServiceId}` `${serviceId} to ${normalizedServiceId}`
); );
this.set('uuid', normalizedServiceId); this.set('serviceId', normalizedServiceId);
} }
if (isValidE164(attributes.id, false)) { if (isValidE164(attributes.id, false)) {
@ -805,8 +805,8 @@ export class ConversationModel extends window.Backbone
} }
const e164 = this.get('e164'); const e164 = this.get('e164');
const pni = this.get('pni'); const pni = this.getPni();
const aci = this.get('uuid'); const aci = this.getServiceId();
if (e164 && pni && aci && pni !== aci) { if (e164 && pni && aci && pni !== aci) {
this.updateE164(undefined); this.updateE164(undefined);
this.updatePni(undefined); this.updatePni(undefined);
@ -878,9 +878,9 @@ export class ConversationModel extends window.Backbone
let blocked = false; let blocked = false;
const wasBlocked = this.isBlocked(); const wasBlocked = this.isBlocked();
const uuid = this.get('uuid'); const serviceId = this.getServiceId();
if (uuid) { if (serviceId) {
drop(window.storage.blocked.addBlockedUuid(uuid)); drop(window.storage.blocked.addBlockedServiceId(serviceId));
blocked = true; blocked = true;
} }
@ -910,9 +910,9 @@ export class ConversationModel extends window.Backbone
let unblocked = false; let unblocked = false;
const wasBlocked = this.isBlocked(); const wasBlocked = this.isBlocked();
const uuid = this.get('uuid'); const serviceId = this.getServiceId();
if (uuid) { if (serviceId) {
drop(window.storage.blocked.removeBlockedUuid(uuid)); drop(window.storage.blocked.removeBlockedServiceId(serviceId));
unblocked = true; unblocked = true;
} }
@ -977,10 +977,10 @@ export class ConversationModel extends window.Backbone
}); });
window.reduxActions?.stories.removeAllContactStories(this.id); window.reduxActions?.stories.removeAllContactStories(this.id);
const uuid = this.get('uuid'); const serviceId = this.getServiceId();
if (uuid) { if (serviceId) {
window.reduxActions?.storyDistributionLists.removeMemberFromAllDistributionLists( window.reduxActions?.storyDistributionLists.removeMemberFromAllDistributionLists(
uuid serviceId
); );
} }
@ -1162,7 +1162,7 @@ export class ConversationModel extends window.Backbone
); );
} }
if (!this.get('uuid')) { if (!this.getServiceId()) {
return; return;
} }
@ -1353,12 +1353,12 @@ export class ConversationModel extends window.Backbone
} }
async onNewMessage(message: MessageModel): Promise<void> { async onNewMessage(message: MessageModel): Promise<void> {
const uuid = message.get('sourceUuid'); const serviceId = message.get('sourceServiceId');
const e164 = message.get('source'); const e164 = message.get('source');
const sourceDevice = message.get('sourceDevice'); const sourceDevice = message.get('sourceDevice');
const source = window.ConversationController.lookupOrCreate({ const source = window.ConversationController.lookupOrCreate({
uuid, serviceId,
e164, e164,
reason: 'ConversationModel.onNewMessage', reason: 'ConversationModel.onNewMessage',
}); });
@ -1855,27 +1855,29 @@ export class ConversationModel extends window.Backbone
this.captureChange('updateE164'); this.captureChange('updateE164');
} }
updateUuid(uuid?: ServiceIdString): void { updateServiceId(serviceId?: ServiceIdString): void {
const oldValue = this.get('uuid'); const oldValue = this.getServiceId();
if (uuid === oldValue) { if (serviceId === oldValue) {
return; return;
} }
this.set( this.set(
'uuid', 'serviceId',
uuid ? normalizeServiceId(uuid, 'Conversation.updateUuid') : undefined serviceId
? normalizeServiceId(serviceId, 'Conversation.updateServiceId')
: undefined
); );
window.Signal.Data.updateConversation(this.attributes); window.Signal.Data.updateConversation(this.attributes);
this.trigger('idUpdated', this, 'uuid', oldValue); this.trigger('idUpdated', this, 'serviceId', oldValue);
// We should delete the old sessions and identity information in all situations except // We should delete the old sessions and identity information in all situations except
// for the case where we need to do old and new PNI comparisons. We'll wait // for the case where we need to do old and new PNI comparisons. We'll wait
// for the PNI update to do that. // for the PNI update to do that.
if (oldValue && oldValue !== this.get('pni')) { if (oldValue && oldValue !== this.getPni()) {
drop(window.textsecure.storage.protocol.removeIdentityKey(oldValue)); drop(window.textsecure.storage.protocol.removeIdentityKey(oldValue));
} }
this.captureChange('updateUuid'); this.captureChange('updateServiceId');
} }
trackPreviousIdentityKey(publicKey: Uint8Array): void { trackPreviousIdentityKey(publicKey: Uint8Array): void {
@ -1902,7 +1904,7 @@ export class ConversationModel extends window.Backbone
} }
updatePni(pni?: PniString): void { updatePni(pni?: PniString): void {
const oldValue = this.get('pni'); const oldValue = this.getPni();
if (pni === oldValue) { if (pni === oldValue) {
return; return;
} }
@ -1913,9 +1915,9 @@ export class ConversationModel extends window.Backbone
); );
const pniIsPrimaryId = const pniIsPrimaryId =
!this.get('uuid') || !this.getServiceId() ||
this.get('uuid') === oldValue || this.getServiceId() === oldValue ||
this.get('uuid') === pni; this.getServiceId() === pni;
const haveSentMessage = Boolean( const haveSentMessage = Boolean(
this.get('profileSharing') || this.get('sentMessageCount') this.get('profileSharing') || this.get('sentMessageCount')
); );
@ -1958,9 +1960,9 @@ export class ConversationModel extends window.Backbone
drop(window.textsecure.storage.protocol.removeIdentityKey(oldValue)); drop(window.textsecure.storage.protocol.removeIdentityKey(oldValue));
} }
if (pni && !this.get('uuid')) { if (pni && !this.getServiceId()) {
log.warn( log.warn(
`updatePni/${this.idForLogging()}: pni field set to ${pni}, but uuid field is empty!` `updatePni/${this.idForLogging()}: pni field set to ${pni}, but service id field is empty!`
); );
} }
@ -2053,14 +2055,19 @@ export class ConversationModel extends window.Backbone
type: conversationQueueJobEnum.enum.Receipts, type: conversationQueueJobEnum.enum.Receipts,
conversationId: this.get('id'), conversationId: this.get('id'),
receiptsType: ReceiptType.Read, receiptsType: ReceiptType.Read,
receipts: readMessages.map(m => ({ receipts: readMessages.map(m => {
const { sourceServiceId: senderAci } = m;
strictAssert(isAciString(senderAci), "Can't send receipt to PNI");
return {
messageId: m.id, messageId: m.id,
conversationId, conversationId,
senderE164: m.source, senderE164: m.source,
senderUuid: m.sourceUuid, senderAci,
timestamp: getMessageSentTimestamp(m, { log }), timestamp: getMessageSentTimestamp(m, { log }),
isDirectConversation: isDirectConversation(this.attributes), isDirectConversation: isDirectConversation(this.attributes),
})), };
}),
}); });
} }
@ -2266,7 +2273,7 @@ export class ConversationModel extends window.Backbone
this.set({ this.set({
pendingAdminApprovalV2: [ pendingAdminApprovalV2: [
{ {
uuid: ourAci, aci: ourAci,
timestamp: Date.now(), timestamp: Date.now(),
}, },
], ],
@ -2828,23 +2835,23 @@ export class ConversationModel extends window.Backbone
async addDeliveryIssue({ async addDeliveryIssue({
receivedAt, receivedAt,
receivedAtCounter, receivedAtCounter,
senderUuid, senderAci,
sentAt, sentAt,
}: { }: {
receivedAt: number; receivedAt: number;
receivedAtCounter: number; receivedAtCounter: number;
senderUuid: string; senderAci: AciString;
sentAt: number; sentAt: number;
}): Promise<void> { }): Promise<void> {
log.info(`addDeliveryIssue: adding for ${this.idForLogging()}`, { log.info(`addDeliveryIssue: adding for ${this.idForLogging()}`, {
sentAt, sentAt,
senderUuid, senderAci,
}); });
const message = { const message = {
conversationId: this.id, conversationId: this.id,
type: 'delivery-issue', type: 'delivery-issue',
sourceUuid: senderUuid, sourceServiceId: senderAci,
sent_at: receivedAt, sent_at: receivedAt,
received_at: receivedAtCounter, received_at: receivedAtCounter,
received_at_ms: receivedAt, received_at_ms: receivedAt,
@ -2945,15 +2952,11 @@ export class ConversationModel extends window.Backbone
if (senderKeyInfo) { if (senderKeyInfo) {
const updatedSenderKeyInfo = { const updatedSenderKeyInfo = {
...senderKeyInfo, ...senderKeyInfo,
memberDevices: senderKeyInfo.memberDevices memberDevices: senderKeyInfo.memberDevices.filter(
.map(resolveSenderKeyDevice) ({ serviceId: memberServiceId }) => {
.filter(isNotNil)
.filter(({ serviceId: memberServiceId }) => {
return memberServiceId !== keyChangedId; return memberServiceId !== keyChangedId;
}) }
.map(({ serviceId: memberServiceId, ...rest }) => { ),
return { identifier: memberServiceId, ...rest };
}),
}; };
this.set('senderKeyInfo', updatedSenderKeyInfo); this.set('senderKeyInfo', updatedSenderKeyInfo);
@ -3267,7 +3270,7 @@ export class ConversationModel extends window.Backbone
newValue: string newValue: string
): Promise<void> { ): Promise<void> {
const sourceServiceId = this.getCheckedServiceId( const sourceServiceId = this.getCheckedServiceId(
'Change number notification without uuid' 'Change number notification without service id'
); );
const { storage } = window.textsecure; const { storage } = window.textsecure;
@ -3299,7 +3302,7 @@ export class ConversationModel extends window.Backbone
return convo.addNotification('change-number-notification', { return convo.addNotification('change-number-notification', {
readStatus: ReadStatus.Read, readStatus: ReadStatus.Read,
seenStatus: SeenStatus.Unseen, seenStatus: SeenStatus.Unseen,
sourceUuid: sourceServiceId, sourceServiceId,
}); });
}) })
); );
@ -3379,7 +3382,7 @@ export class ConversationModel extends window.Backbone
} }
const members = this.get('membersV2') || []; const members = this.get('membersV2') || [];
const member = members.find(x => x.uuid === serviceId); const member = members.find(x => x.aci === serviceId);
if (!member) { if (!member) {
return false; return false;
} }
@ -3390,7 +3393,7 @@ export class ConversationModel extends window.Backbone
} }
getServiceId(): ServiceIdString | undefined { getServiceId(): ServiceIdString | undefined {
return this.get('uuid'); return this.get('serviceId');
} }
getCheckedServiceId(reason: string): ServiceIdString { getCheckedServiceId(reason: string): ServiceIdString {
@ -3400,7 +3403,7 @@ export class ConversationModel extends window.Backbone
} }
getAci(): AciString | undefined { getAci(): AciString | undefined {
const value = this.get('uuid'); const value = this.getServiceId();
if (value && isAciString(value)) { if (value && isAciString(value)) {
return value; return value;
} }
@ -4483,7 +4486,7 @@ export class ConversationModel extends window.Backbone
await Promise.all( await Promise.all(
conversations.map(conversation => conversations.map(conversation =>
getProfile(conversation.get('uuid'), conversation.get('e164')) getProfile(conversation.getServiceId(), conversation.get('e164'))
) )
); );
} }
@ -4653,8 +4656,8 @@ export class ConversationModel extends window.Backbone
return; return;
} }
const uuid = this.get('uuid'); const serviceId = this.getServiceId();
if (!uuid) { if (!serviceId) {
return; return;
} }
@ -4663,7 +4666,7 @@ export class ConversationModel extends window.Backbone
return lastProfile.profileKeyVersion; return lastProfile.profileKeyVersion;
} }
const profileKeyVersion = deriveProfileKeyVersion(profileKey, uuid); const profileKeyVersion = deriveProfileKeyVersion(profileKey, serviceId);
if (!profileKeyVersion) { if (!profileKeyVersion) {
log.warn( log.warn(
'deriveProfileKeyVersion: Failed to derive profile key version, ' + 'deriveProfileKeyVersion: Failed to derive profile key version, ' +
@ -4733,7 +4736,7 @@ export class ConversationModel extends window.Backbone
hasMember(serviceId: ServiceIdString): boolean { hasMember(serviceId: ServiceIdString): boolean {
const members = this.getMembers(); const members = this.getMembers();
return members.some(member => member.get('uuid') === serviceId); return members.some(member => member.getServiceId() === serviceId);
} }
fetchContacts(): void { fetchContacts(): void {
@ -4818,7 +4821,7 @@ export class ConversationModel extends window.Backbone
} }
// Set of items to captureChanges on: // Set of items to captureChanges on:
// [-] uuid // [-] serviceId
// [-] e164 // [-] e164
// [X] profileKey // [X] profileKey
// [-] identityKey // [-] identityKey
@ -4912,14 +4915,14 @@ export class ConversationModel extends window.Backbone
const ourAci = window.textsecure.storage.user.getCheckedAci(); const ourAci = window.textsecure.storage.user.getCheckedAci();
const ourPni = window.textsecure.storage.user.getCheckedPni(); const ourPni = window.textsecure.storage.user.getCheckedPni();
const ourUuids: Set<ServiceIdString> = new Set([ourAci, ourPni]); const ourServiceIds: Set<ServiceIdString> = new Set([ourAci, ourPni]);
const mentionsMe = (message.get('bodyRanges') || []).some(bodyRange => { const mentionsMe = (message.get('bodyRanges') || []).some(bodyRange => {
if (!BodyRange.isMention(bodyRange)) { if (!BodyRange.isMention(bodyRange)) {
return false; return false;
} }
return ourUuids.has( return ourServiceIds.has(
normalizeServiceId(bodyRange.mentionUuid, 'notify: mentionsMe check') normalizeServiceId(bodyRange.mentionAci, 'notify: mentionsMe check')
); );
}); });
if (!mentionsMe) { if (!mentionsMe) {
@ -5281,7 +5284,7 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
/** /**
* window.Backbone defines a `_byId` field. Here we set up additional `_byE164`, * window.Backbone defines a `_byId` field. Here we set up additional `_byE164`,
* `_byUuid`, and `_byGroupId` fields so we can track conversations by more * `_byServiceId`, and `_byGroupId` fields so we can track conversations by more
* than just their id. * than just their id.
*/ */
initialize() { initialize() {
@ -5294,8 +5297,8 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
if (idProp === 'e164') { if (idProp === 'e164') {
delete this._byE164[oldValue]; delete this._byE164[oldValue];
} }
if (idProp === 'uuid') { if (idProp === 'serviceId') {
delete this._byUuid[oldValue]; delete this._byServiceId[oldValue];
} }
if (idProp === 'pni') { if (idProp === 'pni') {
delete this._byPni[oldValue]; delete this._byPni[oldValue];
@ -5308,11 +5311,11 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
if (e164) { if (e164) {
this._byE164[e164] = model; this._byE164[e164] = model;
} }
const uuid = model.get('uuid'); const serviceId = model.getServiceId();
if (uuid) { if (serviceId) {
this._byUuid[uuid] = model; this._byServiceId[serviceId] = model;
} }
const pni = model.get('pni'); const pni = model.getPni();
if (pni) { if (pni) {
this._byPni[pni] = model; this._byPni[pni] = model;
} }
@ -5340,28 +5343,28 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
if (e164) { if (e164) {
const existing = this._byE164[e164]; const existing = this._byE164[e164];
// Prefer the contact with both e164 and uuid // Prefer the contact with both e164 and serviceId
if (!existing || (existing && !existing.get('uuid'))) { if (!existing || (existing && !existing.getServiceId())) {
this._byE164[e164] = model; this._byE164[e164] = model;
} }
} }
const uuid = model.get('uuid'); const serviceId = model.getServiceId();
if (uuid) { if (serviceId) {
const existing = this._byUuid[uuid]; const existing = this._byServiceId[serviceId];
// Prefer the contact with both e164 and uuid // Prefer the contact with both e164 and seviceId
if (!existing || (existing && !existing.get('e164'))) { if (!existing || (existing && !existing.get('e164'))) {
this._byUuid[uuid] = model; this._byServiceId[serviceId] = model;
} }
} }
const pni = model.get('pni'); const pni = model.getPni();
if (pni) { if (pni) {
const existing = this._byPni[pni]; const existing = this._byPni[pni];
// Prefer the contact with both uuid and pni // Prefer the contact with both serviceId and pni
if (!existing || (existing && !existing.get('uuid'))) { if (!existing || (existing && !existing.getServiceId())) {
this._byPni[pni] = model; this._byPni[pni] = model;
} }
} }
@ -5375,7 +5378,7 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
eraseLookups() { eraseLookups() {
this._byE164 = Object.create(null); this._byE164 = Object.create(null);
this._byUuid = Object.create(null); this._byServiceId = Object.create(null);
this._byPni = Object.create(null); this._byPni = Object.create(null);
this._byGroupId = Object.create(null); this._byGroupId = Object.create(null);
}, },
@ -5427,7 +5430,7 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
/** /**
* window.Backbone collections have a `_byId` field that `get` defers to. Here, we * window.Backbone collections have a `_byId` field that `get` defers to. Here, we
* override `get` to first access our custom `_byE164`, `_byUuid`, and * override `get` to first access our custom `_byE164`, `_byServiceId`, and
* `_byGroupId` functions, followed by falling back to the original * `_byGroupId` functions, followed by falling back to the original
* window.Backbone implementation. * window.Backbone implementation.
*/ */
@ -5435,7 +5438,7 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
return ( return (
this._byE164[id] || this._byE164[id] ||
this._byE164[`+${id}`] || this._byE164[`+${id}`] ||
this._byUuid[id] || this._byServiceId[id] ||
this._byPni[id] || this._byPni[id] ||
this._byGroupId[id] || this._byGroupId[id] ||
window.Backbone.Collection.prototype.get.call(this, id) window.Backbone.Collection.prototype.get.call(this, id)

View file

@ -45,7 +45,7 @@ import { getMessageSentTimestamp } from '../util/getMessageSentTimestamp';
import type { ReactionType } from '../types/Reactions'; import type { ReactionType } from '../types/Reactions';
import type { ServiceIdString } from '../types/ServiceId'; import type { ServiceIdString } from '../types/ServiceId';
import { normalizeServiceId } from '../types/ServiceId'; import { isAciString, normalizeServiceId } from '../types/ServiceId';
import * as reactionUtil from '../reactions/util'; import * as reactionUtil from '../reactions/util';
import * as Stickers from '../types/Stickers'; import * as Stickers from '../types/Stickers';
import * as Errors from '../types/errors'; import * as Errors from '../types/errors';
@ -133,7 +133,7 @@ import { cleanupMessage, deleteMessageData } from '../util/cleanup';
import { import {
getContact, getContact,
getSource, getSource,
getSourceUuid, getSourceServiceId,
isCustomError, isCustomError,
messageHasPaymentEvent, messageHasPaymentEvent,
isQuoteAMatch, isQuoteAMatch,
@ -294,13 +294,13 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
getSenderIdentifier(): string { getSenderIdentifier(): string {
const sentAt = this.get('sent_at'); const sentAt = this.get('sent_at');
const source = this.get('source'); const source = this.get('source');
const sourceUuid = this.get('sourceUuid'); const sourceServiceId = this.get('sourceServiceId');
const sourceDevice = this.get('sourceDevice'); const sourceDevice = this.get('sourceDevice');
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const conversation = window.ConversationController.lookupOrCreate({ const conversation = window.ConversationController.lookupOrCreate({
e164: source, e164: source,
uuid: sourceUuid, serviceId: sourceServiceId,
reason: 'MessageModel.getSenderIdentifier', reason: 'MessageModel.getSenderIdentifier',
})!; })!;
@ -372,7 +372,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
attachment: undefined, attachment: undefined,
// This is ok to do because story replies only show in 1:1 conversations // This is ok to do because story replies only show in 1:1 conversations
// so the story that was quoted should be from the same conversation. // so the story that was quoted should be from the same conversation.
authorUuid: conversation?.get('uuid'), authorAci: conversation?.getAci(),
// No messageId, referenced story not found! // No messageId, referenced story not found!
messageId: '', messageId: '',
}, },
@ -389,10 +389,12 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
attachment = undefined; attachment = undefined;
} }
const { sourceServiceId: authorAci } = message;
strictAssert(isAciString(authorAci), 'Story message from pni');
this.set({ this.set({
storyReplyContext: { storyReplyContext: {
attachment, attachment,
authorUuid: message.sourceUuid, authorAci,
messageId: message.id, messageId: message.id,
}, },
}); });
@ -510,7 +512,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
} }
if (messageHasPaymentEvent(attributes)) { if (messageHasPaymentEvent(attributes)) {
const sender = findAndFormatContact(attributes.sourceUuid); const sender = findAndFormatContact(attributes.sourceServiceId);
const conversation = findAndFormatContact(attributes.conversationId); const conversation = findAndFormatContact(attributes.conversationId);
return { return {
text: getPaymentEventNotificationText( text: getPaymentEventNotificationText(
@ -850,7 +852,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if ( if (
attributes.type === 'incoming' && attributes.type === 'incoming' &&
attributes.storyReaction.targetAuthorUuid === ourAci attributes.storyReaction.targetAuthorAci === ourAci
) { ) {
return window.i18n('icu:Quote__story-reaction-notification--incoming', { return window.i18n('icu:Quote__story-reaction-notification--incoming', {
emoji: attributes.storyReaction.emoji, emoji: attributes.storyReaction.emoji,
@ -990,11 +992,11 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if (!fromSync) { if (!fromSync) {
const senderE164 = getSource(this.attributes); const senderE164 = getSource(this.attributes);
const senderUuid = getSourceUuid(this.attributes); const senderAci = getSourceServiceId(this.attributes);
const timestamp = this.get('sent_at'); const timestamp = this.get('sent_at');
if (senderUuid === undefined) { if (senderAci === undefined || !isAciString(senderAci)) {
throw new Error('markViewOnceMessageViewed: senderUuid is undefined'); throw new Error('markViewOnceMessageViewed: senderAci is undefined');
} }
if (window.ConversationController.areWePrimaryDevice()) { if (window.ConversationController.areWePrimaryDevice()) {
@ -1009,7 +1011,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
viewOnceOpens: [ viewOnceOpens: [
{ {
senderE164, senderE164,
senderUuid, senderAci,
timestamp, timestamp,
}, },
], ],
@ -1050,8 +1052,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
return; return;
} }
const { authorUuid, author, id: sentAt, referencedMessageNotFound } = quote; const { authorAci, author, id: sentAt, referencedMessageNotFound } = quote;
const contact = window.ConversationController.get(authorUuid || author); const contact = window.ConversationController.get(authorAci || author);
// Is the quote really without a reference? Check with our in memory store // Is the quote really without a reference? Check with our in memory store
// first to make sure it's not there. // first to make sure it's not there.
@ -1289,12 +1291,15 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if (!isIncoming(this.attributes)) { if (!isIncoming(this.attributes)) {
return null; return null;
} }
const sourceUuid = this.get('sourceUuid'); const sourceServiceId = this.get('sourceServiceId');
if (!sourceUuid) { if (!sourceServiceId) {
return null; return null;
} }
return window.ConversationController.getOrCreate(sourceUuid, 'private'); return window.ConversationController.getOrCreate(
sourceServiceId,
'private'
);
} }
async retrySend(): Promise<void> { async retrySend(): Promise<void> {
@ -1318,7 +1323,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
currentConversationRecipients = new Set( currentConversationRecipients = new Set(
storyDistribution.members storyDistribution.members
.map(uuid => window.ConversationController.get(uuid)?.id) .map(serviceId => window.ConversationController.get(serviceId)?.id)
.filter(isNotNil) .filter(isNotNil)
); );
} else { } else {
@ -1947,9 +1952,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
strictAssert(id, 'Quote must have an id'); strictAssert(id, 'Quote must have an id');
const result: QuotedMessageType = { const result: QuotedMessageType = {
...omit(quote, 'authorAci'), ...quote,
authorUuid: quote.authorAci,
id, id,
attachments: quote.attachments.slice(), attachments: quote.attachments.slice(),
@ -2135,7 +2139,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// eslint-disable-next-line @typescript-eslint/no-this-alias // eslint-disable-next-line @typescript-eslint/no-this-alias
const message = this; const message = this;
const source = message.get('source'); const source = message.get('source');
const sourceUuid = message.get('sourceUuid'); const sourceServiceId = message.get('sourceServiceId');
const type = message.get('type'); const type = message.get('type');
const conversationId = message.get('conversationId'); const conversationId = message.get('conversationId');
@ -2210,7 +2214,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const destinationConversation = const destinationConversation =
window.ConversationController.lookupOrCreate({ window.ConversationController.lookupOrCreate({
uuid: destinationServiceId, serviceId: destinationServiceId,
e164: destination || undefined, e164: destination || undefined,
reason: `handleDataMessage(${initialMessage.timestamp})`, reason: `handleDataMessage(${initialMessage.timestamp})`,
}); });
@ -2344,7 +2348,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const sender = window.ConversationController.lookupOrCreate({ const sender = window.ConversationController.lookupOrCreate({
e164: source, e164: source,
uuid: sourceUuid, serviceId: sourceServiceId,
reason: 'handleDataMessage', reason: 'handleDataMessage',
})!; })!;
const hasGroupV2Prop = Boolean(initialMessage.groupV2); const hasGroupV2Prop = Boolean(initialMessage.groupV2);
@ -2352,7 +2356,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// Drop if from blocked user. Only GroupV2 messages should need to be dropped here. // Drop if from blocked user. Only GroupV2 messages should need to be dropped here.
const isBlocked = const isBlocked =
(source && window.storage.blocked.isBlocked(source)) || (source && window.storage.blocked.isBlocked(source)) ||
(sourceUuid && window.storage.blocked.isUuidBlocked(sourceUuid)); (sourceServiceId &&
window.storage.blocked.isServiceIdBlocked(sourceServiceId));
if (isBlocked) { if (isBlocked) {
log.info( log.info(
`${idLog}: Dropping message from blocked sender. hasGroupV2Prop: ${hasGroupV2Prop}` `${idLog}: Dropping message from blocked sender. hasGroupV2Prop: ${hasGroupV2Prop}`
@ -2371,7 +2376,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
type === 'incoming' && type === 'incoming' &&
!isDirectConversation(conversation.attributes) && !isDirectConversation(conversation.attributes) &&
hasGroupV2Prop && hasGroupV2Prop &&
(!areWeMember || (sourceUuid && !conversation.hasMember(sourceUuid))) (!areWeMember ||
(sourceServiceId && !conversation.hasMember(sourceServiceId)))
) { ) {
log.warn( log.warn(
`${idLog}: Received message destined for group, which we or the sender are not a part of. Dropping.` `${idLog}: Received message destined for group, which we or the sender are not a part of. Dropping.`
@ -2423,11 +2429,15 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// The queue can be paused easily. // The queue can be paused easily.
drop( drop(
window.Whisper.deliveryReceiptQueue.add(() => { window.Whisper.deliveryReceiptQueue.add(() => {
strictAssert(
isAciString(sourceServiceId),
'Incoming message must be from ACI'
);
window.Whisper.deliveryReceiptBatcher.add({ window.Whisper.deliveryReceiptBatcher.add({
messageId, messageId,
conversationId, conversationId,
senderE164: source, senderE164: source,
senderUuid: sourceUuid, senderAci: sourceServiceId,
timestamp: this.get('sent_at'), timestamp: this.get('sent_at'),
isDirectConversation: isDirectConversation( isDirectConversation: isDirectConversation(
conversation.attributes conversation.attributes
@ -2456,7 +2466,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const sendState = sendStateByConversationId[sender.id]; const sendState = sendStateByConversationId[sender.id];
const storyQuoteIsFromSelf = const storyQuoteIsFromSelf =
candidateQuote.get('sourceUuid') === candidateQuote.get('sourceServiceId') ===
window.storage.user.getCheckedAci(); window.storage.user.getCheckedAci();
if (!storyQuoteIsFromSelf) { if (!storyQuoteIsFromSelf) {
@ -2573,7 +2583,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
} }
const ourPni = window.textsecure.storage.user.getCheckedPni(); const ourPni = window.textsecure.storage.user.getCheckedPni();
const ourUuids: Set<ServiceIdString> = new Set([ourAci, ourPni]); const ourServiceIds: Set<ServiceIdString> = new Set([ourAci, ourPni]);
message.set({ message.set({
id: messageId, id: messageId,
@ -2594,9 +2604,9 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if (!BodyRange.isMention(bodyRange)) { if (!BodyRange.isMention(bodyRange)) {
return false; return false;
} }
return ourUuids.has( return ourServiceIds.has(
normalizeServiceId( normalizeServiceId(
bodyRange.mentionUuid, bodyRange.mentionAci,
'handleDataMessage: mentionsMe check' 'handleDataMessage: mentionsMe check'
) )
); );
@ -2675,7 +2685,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
message.set({ message.set({
expirationTimerUpdate: { expirationTimerUpdate: {
source, source,
sourceUuid, sourceServiceId,
expireTimer: initialMessage.expireTimer, expireTimer: initialMessage.expireTimer,
}, },
}); });
@ -2697,7 +2707,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// point and these calls will return early. // point and these calls will return early.
if (dataMessage.expireTimer) { if (dataMessage.expireTimer) {
void conversation.updateExpirationTimer(dataMessage.expireTimer, { void conversation.updateExpirationTimer(dataMessage.expireTimer, {
source: sourceUuid || source, source: sourceServiceId || source,
receivedAt: message.get('received_at'), receivedAt: message.get('received_at'),
receivedAtMS: message.get('received_at_ms'), receivedAtMS: message.get('received_at_ms'),
sentAt: message.get('sent_at'), sentAt: message.get('sent_at'),
@ -2710,7 +2720,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
!isEndSession(message.attributes) !isEndSession(message.attributes)
) { ) {
void conversation.updateExpirationTimer(undefined, { void conversation.updateExpirationTimer(undefined, {
source: sourceUuid || source, source: sourceServiceId || source,
receivedAt: message.get('received_at'), receivedAt: message.get('received_at'),
receivedAtMS: message.get('received_at_ms'), receivedAtMS: message.get('received_at_ms'),
sentAt: message.get('sent_at'), sentAt: message.get('sent_at'),
@ -2723,7 +2733,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const { profileKey } = initialMessage; const { profileKey } = initialMessage;
if ( if (
source === window.textsecure.storage.user.getNumber() || source === window.textsecure.storage.user.getNumber() ||
sourceUuid === window.textsecure.storage.user.getAci() sourceServiceId === window.textsecure.storage.user.getAci()
) { ) {
conversation.set({ profileSharing: true }); conversation.set({ profileSharing: true });
} else if (isDirectConversation(conversation.attributes)) { } else if (isDirectConversation(conversation.attributes)) {
@ -2731,7 +2741,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
} else { } else {
const local = window.ConversationController.lookupOrCreate({ const local = window.ConversationController.lookupOrCreate({
e164: source, e164: source,
uuid: sourceUuid, serviceId: sourceServiceId,
reason: 'handleDataMessage:setProfileKey', reason: 'handleDataMessage:setProfileKey',
}); });
void local?.setProfileKey(profileKey); void local?.setProfileKey(profileKey);
@ -2952,7 +2962,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const newReaction: MessageReactionType = { const newReaction: MessageReactionType = {
emoji: reaction.get('remove') ? undefined : reaction.get('emoji'), emoji: reaction.get('remove') ? undefined : reaction.get('emoji'),
fromId: reaction.get('fromId'), fromId: reaction.get('fromId'),
targetAuthorUuid: reaction.get('targetAuthorUuid'), targetAuthorAci: reaction.get('targetAuthorAci'),
targetTimestamp: reaction.get('targetTimestamp'), targetTimestamp: reaction.get('targetTimestamp'),
timestamp: reaction.get('timestamp'), timestamp: reaction.get('timestamp'),
isSentByConversationId: isFromThisDevice isSentByConversationId: isFromThisDevice
@ -3001,7 +3011,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
storyId: storyMessage.id, storyId: storyMessage.id,
storyReaction: { storyReaction: {
emoji: reaction.get('emoji'), emoji: reaction.get('emoji'),
targetAuthorUuid: reaction.get('targetAuthorUuid'), targetAuthorAci: reaction.get('targetAuthorAci'),
targetTimestamp: reaction.get('targetTimestamp'), targetTimestamp: reaction.get('targetTimestamp'),
}, },
}); });
@ -3097,7 +3107,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
await window.Signal.Data.removeReactionFromConversation({ await window.Signal.Data.removeReactionFromConversation({
emoji: reaction.get('emoji'), emoji: reaction.get('emoji'),
fromId: reaction.get('fromId'), fromId: reaction.get('fromId'),
targetAuthorServiceId: reaction.get('targetAuthorUuid'), targetAuthorServiceId: reaction.get('targetAuthorAci'),
targetTimestamp: reaction.get('targetTimestamp'), targetTimestamp: reaction.get('targetTimestamp'),
}); });
} else { } else {
@ -3135,7 +3145,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
fromId: reaction.get('fromId'), fromId: reaction.get('fromId'),
messageId: this.id, messageId: this.id,
messageReceivedAt: this.get('received_at'), messageReceivedAt: this.get('received_at'),
targetAuthorUuid: reaction.get('targetAuthorUuid'), targetAuthorAci: reaction.get('targetAuthorAci'),
targetTimestamp: reaction.get('targetTimestamp'), targetTimestamp: reaction.get('targetTimestamp'),
}); });
} }

View file

@ -5,6 +5,7 @@ import Fuse from 'fuse.js';
import { get } from 'lodash'; import { get } from 'lodash';
import type { ConversationType } from '../state/ducks/conversations'; import type { ConversationType } from '../state/ducks/conversations';
import type { ServiceIdString } from '../types/ServiceId';
import { filter, map } from '../util/iterables'; import { filter, map } from '../util/iterables';
import { removeDiacritics } from '../util/removeDiacritics'; import { removeDiacritics } from '../util/removeDiacritics';
@ -67,9 +68,13 @@ export class MemberRepository {
: undefined; : undefined;
} }
getMemberByUuid(uuid?: string): ConversationType | undefined { getMemberByServiceId(
return uuid serviceId?: ServiceIdString
? this.members.find(({ uuid: memberUuid }) => memberUuid === uuid) ): ConversationType | undefined {
return serviceId
? this.members.find(
({ serviceId: memberServiceId }) => memberServiceId === serviceId
)
: undefined; : undefined;
} }

View file

@ -33,21 +33,21 @@ export class MentionBlot extends Embed {
} }
static override value(node: HTMLElement): MentionBlotValue { static override value(node: HTMLElement): MentionBlotValue {
const { uuid, title } = node.dataset; const { aci, title } = node.dataset;
if (uuid === undefined || title === undefined) { if (aci === undefined || title === undefined) {
throw new Error( throw new Error(
`Failed to make MentionBlot with uuid: ${uuid}, title: ${title}` `Failed to make MentionBlot with aci: ${aci}, title: ${title}`
); );
} }
return { return {
uuid: normalizeAci(uuid, 'quill mention blot'), aci: normalizeAci(aci, 'quill mention blot'),
title, title,
}; };
} }
static buildSpan(mention: MentionBlotValue, node: HTMLElement): void { static buildSpan(mention: MentionBlotValue, node: HTMLElement): void {
node.setAttribute('data-uuid', mention.uuid || ''); node.setAttribute('data-aci', mention.aci || '');
node.setAttribute('data-title', mention.title || ''); node.setAttribute('data-title', mention.title || '');
node.setAttribute('contenteditable', 'false'); node.setAttribute('contenteditable', 'false');

View file

@ -261,7 +261,7 @@ export class MentionCompletion {
{memberResults.map((member, index) => ( {memberResults.map((member, index) => (
<button <button
type="button" type="button"
key={member.uuid} key={member.serviceId}
id={`mention-result--${member.name}`} id={`mention-result--${member.name}`}
role="option button" role="option button"
aria-selected={memberResultsIndex === index} aria-selected={memberResultsIndex === index}

View file

@ -5,6 +5,8 @@ import Delta from 'quill-delta';
import type { RefObject } from 'react'; import type { RefObject } from 'react';
import type { Matcher, AttributeMap } from 'quill'; import type { Matcher, AttributeMap } from 'quill';
import { assertDev } from '../../util/assert';
import { isAciString } from '../../types/ServiceId';
import type { MemberRepository } from '../memberRepository'; import type { MemberRepository } from '../memberRepository';
export const matchMention: ( export const matchMention: (
@ -21,12 +23,14 @@ export const matchMention: (
const { id } = node.dataset; const { id } = node.dataset;
const conversation = memberRepository.getMemberById(id); const conversation = memberRepository.getMemberById(id);
if (conversation && conversation.uuid) { if (conversation && conversation.serviceId) {
const { serviceId: aci } = conversation;
assertDev(isAciString(aci), 'Mentioned conversation has no ACI');
return new Delta().insert( return new Delta().insert(
{ {
mention: { mention: {
title, title,
uuid: conversation.uuid, aci,
}, },
}, },
attributes attributes
@ -37,15 +41,20 @@ export const matchMention: (
} }
if (node.classList.contains('mention-blot')) { if (node.classList.contains('mention-blot')) {
const { uuid } = node.dataset; const { aci } = node.dataset;
const conversation = memberRepository.getMemberByUuid(uuid); assertDev(isAciString(aci), 'Mentioned blot has invalid ACI');
const conversation = memberRepository.getMemberByServiceId(aci);
if (conversation && conversation.uuid) { if (conversation && conversation.serviceId) {
assertDev(
conversation.serviceId === aci,
'Mentioned conversation has no ACI'
);
return new Delta().insert( return new Delta().insert(
{ {
mention: { mention: {
title: title || conversation.title, title: title || conversation.title,
uuid: conversation.uuid, aci,
}, },
}, },
attributes attributes

View file

@ -18,7 +18,7 @@ import { isNotNil } from '../util/isNotNil';
import type { AciString } from '../types/ServiceId'; import type { AciString } from '../types/ServiceId';
export type MentionBlotValue = { export type MentionBlotValue = {
uuid: AciString; aci: AciString;
title: string; title: string;
}; };
@ -185,7 +185,7 @@ export const getTextAndRangesFromOps = (
if (isInsertMentionOp(op)) { if (isInsertMentionOp(op)) {
startingBodyRanges.push({ startingBodyRanges.push({
length: 1, // The length of `\uFFFC` length: 1, // The length of `\uFFFC`
mentionUuid: op.insert.mention.uuid, mentionAci: op.insert.mention.aci,
replacementText: op.insert.mention.title, replacementText: op.insert.mention.title,
start: acc.length, start: acc.length,
}); });
@ -291,13 +291,13 @@ export const getDeltaToRestartMention = (ops: Array<Op>): Delta => {
export const getDeltaToRemoveStaleMentions = ( export const getDeltaToRemoveStaleMentions = (
ops: Array<Op>, ops: Array<Op>,
memberUuids: Array<string> memberAcis: Array<AciString>
): Delta => { ): Delta => {
const newOps = ops.reduce((memo, op) => { const newOps = ops.reduce((memo, op) => {
if (op.insert) { if (op.insert) {
if ( if (
isInsertMentionOp(op) && isInsertMentionOp(op) &&
!memberUuids.includes(op.insert.mention.uuid) !memberAcis.includes(op.insert.mention.aci)
) { ) {
const deleteOp = { delete: 1 }; const deleteOp = { delete: 1 };
const textOp = { insert: `@${op.insert.mention.title}` }; const textOp = { insert: `@${op.insert.mention.title}` };
@ -360,7 +360,7 @@ export const insertMentionOps = (
return; return;
} }
const { start, length, mentionUuid, replacementText } = bodyRange; const { start, length, mentionAci, replacementText } = bodyRange;
const op = ops.shift(); const op = ops.shift();
@ -372,7 +372,7 @@ export const insertMentionOps = (
const right = insert.slice(start + length); const right = insert.slice(start + length);
const mention = { const mention = {
uuid: mentionUuid, aci: mentionAci,
title: replacementText, title: replacementText,
}; };

View file

@ -6,7 +6,7 @@ import { v4 as generateUuid } from 'uuid';
import { ReactionModel } from '../messageModifiers/Reactions'; import { ReactionModel } from '../messageModifiers/Reactions';
import { ReactionSource } from './ReactionSource'; import { ReactionSource } from './ReactionSource';
import { getMessageById } from '../messages/getMessageById'; import { getMessageById } from '../messages/getMessageById';
import { getSourceUuid, isStory } from '../messages/helpers'; import { getSourceServiceId, isStory } from '../messages/helpers';
import { strictAssert } from '../util/assert'; import { strictAssert } from '../util/assert';
import { isDirectConversation } from '../util/whatTypeOfConversation'; import { isDirectConversation } from '../util/whatTypeOfConversation';
import { incrementMessageCounter } from '../util/incrementMessageCounter'; import { incrementMessageCounter } from '../util/incrementMessageCounter';
@ -28,13 +28,13 @@ export async function enqueueReactionForSend({
const message = await getMessageById(messageId); const message = await getMessageById(messageId);
strictAssert(message, 'enqueueReactionForSend: no message found'); strictAssert(message, 'enqueueReactionForSend: no message found');
const targetAuthorUuid = getSourceUuid(message.attributes); const targetAuthorAci = getSourceServiceId(message.attributes);
strictAssert( strictAssert(
targetAuthorUuid, targetAuthorAci,
`enqueueReactionForSend: message ${message.idForLogging()} had no source UUID` `enqueueReactionForSend: message ${message.idForLogging()} had no source UUID`
); );
strictAssert( strictAssert(
isAciString(targetAuthorUuid), isAciString(targetAuthorAci),
`enqueueReactionForSend: message ${message.idForLogging()} had no source ACI` `enqueueReactionForSend: message ${message.idForLogging()} had no source ACI`
); );
@ -56,7 +56,7 @@ export async function enqueueReactionForSend({
const isMessageAStory = isStory(message.attributes); const isMessageAStory = isStory(message.attributes);
const targetConversation = const targetConversation =
isMessageAStory && isDirectConversation(messageConversation.attributes) isMessageAStory && isDirectConversation(messageConversation.attributes)
? window.ConversationController.get(targetAuthorUuid) ? window.ConversationController.get(targetAuthorAci)
: messageConversation; : messageConversation;
strictAssert( strictAssert(
targetConversation, targetConversation,
@ -92,7 +92,7 @@ export async function enqueueReactionForSend({
storyId: message.id, storyId: message.id,
storyReaction: { storyReaction: {
emoji, emoji,
targetAuthorUuid, targetAuthorAci,
targetTimestamp, targetTimestamp,
}, },
}) })
@ -104,7 +104,7 @@ export async function enqueueReactionForSend({
remove, remove,
source: ReactionSource.FromThisDevice, source: ReactionSource.FromThisDevice,
storyReactionMessage, storyReactionMessage,
targetAuthorUuid, targetAuthorAci,
targetTimestamp, targetTimestamp,
timestamp, timestamp,
}); });

View file

@ -136,7 +136,7 @@ export async function routineProfileRefresh({
totalCount += 1; totalCount += 1;
try { try {
await getProfileFn(conversation.get('uuid'), conversation.get('e164')); await getProfileFn(conversation.getServiceId(), conversation.get('e164'));
log.info( log.info(
`${logId}: refreshed profile for ${conversation.idForLogging()}` `${logId}: refreshed profile for ${conversation.idForLogging()}`
); );
@ -203,7 +203,7 @@ function* getFilteredConversations(
c => c =>
isDirectConversation(c.attributes) && isDirectConversation(c.attributes) &&
!c.isUnregisteredAndStale() && !c.isUnregisteredAndStale() &&
c.get('uuid') c.getServiceId()
); );
const sorted = sortBy(filtered, c => c.get('profileLastFetchedAt') || 0); const sorted = sortBy(filtered, c => c.get('profileLastFetchedAt') || 0);

View file

@ -369,9 +369,9 @@ export class CallingClass {
RingRTC.handleGroupCallRingUpdate = RingRTC.handleGroupCallRingUpdate =
this.handleGroupCallRingUpdate.bind(this); this.handleGroupCallRingUpdate.bind(this);
this.attemptToGiveOurUuidToRingRtc(); this.attemptToGiveOurServiceIdToRingRtc();
window.Whisper.events.on('userChanged', () => { window.Whisper.events.on('userChanged', () => {
this.attemptToGiveOurUuidToRingRtc(); this.attemptToGiveOurServiceIdToRingRtc();
}); });
ipcRenderer.on('stop-screen-share', () => { ipcRenderer.on('stop-screen-share', () => {
@ -381,7 +381,7 @@ export class CallingClass {
void this.cleanExpiredGroupCallRingsAndLoop(); void this.cleanExpiredGroupCallRingsAndLoop();
} }
private attemptToGiveOurUuidToRingRtc(): void { private attemptToGiveOurServiceIdToRingRtc(): void {
const ourAci = window.textsecure.storage.user.getAci(); const ourAci = window.textsecure.storage.user.getAci();
if (!ourAci) { if (!ourAci) {
// This can happen if we're not linked. It's okay if we hit this case. // This can happen if we're not linked. It's okay if we hit this case.
@ -610,7 +610,7 @@ export class CallingClass {
return getMembershipList(conversationId).map( return getMembershipList(conversationId).map(
member => member =>
new GroupMemberInfo( new GroupMemberInfo(
Buffer.from(uuidToBytes(member.uuid)), Buffer.from(uuidToBytes(member.aci)),
Buffer.from(member.uuidCiphertext) Buffer.from(member.uuidCiphertext)
) )
); );

View file

@ -5,7 +5,7 @@ import PQueue from 'p-queue';
import type { ContactSyncEvent } from '../textsecure/messageReceiverEvents'; import type { ContactSyncEvent } from '../textsecure/messageReceiverEvents';
import type { ModifiedContactDetails } from '../textsecure/ContactsParser'; import type { ModifiedContactDetails } from '../textsecure/ContactsParser';
import { normalizeServiceId } from '../types/ServiceId'; import { normalizeAci } from '../types/ServiceId';
import * as Conversation from '../types/Conversation'; import * as Conversation from '../types/Conversation';
import * as Errors from '../types/errors'; import * as Errors from '../types/errors';
import type { ValidateConversationType } from '../model-types.d'; import type { ValidateConversationType } from '../model-types.d';
@ -91,7 +91,7 @@ async function doContactSync({
for (const details of contacts) { for (const details of contacts) {
const partialConversation: ValidateConversationType = { const partialConversation: ValidateConversationType = {
e164: details.number, e164: details.number,
uuid: normalizeServiceId(details.aci, 'doContactSync'), serviceId: normalizeAci(details.aci, 'doContactSync'),
type: 'private', type: 'private',
}; };
@ -106,7 +106,7 @@ async function doContactSync({
const { conversation } = window.ConversationController.maybeMergeContacts({ const { conversation } = window.ConversationController.maybeMergeContacts({
e164: details.number, e164: details.number,
aci: details.aci, aci: normalizeAci(details.aci, 'contactSync.aci'),
reason: logId, reason: logId,
}); });

View file

@ -12,6 +12,7 @@ import * as durations from '../util/durations';
import { BackOff } from '../util/BackOff'; import { BackOff } from '../util/BackOff';
import { sleep } from '../util/sleep'; import { sleep } from '../util/sleep';
import { toDayMillis } from '../util/timestamp'; import { toDayMillis } from '../util/timestamp';
import { toAciObject, toPniObject, toTaggedPni } from '../types/ServiceId';
import * as log from '../logging/log'; import * as log from '../logging/log';
export const GROUP_CREDENTIALS_KEY = 'groupCredentials'; export const GROUP_CREDENTIALS_KEY = 'groupCredentials';
@ -150,10 +151,15 @@ export async function maybeFetchNewCredentials(): Promise<void> {
serverPublicParamsBase64 serverPublicParamsBase64
); );
const { pni, credentials: rawCredentials } = await server.getGroupCredentials( // Received credentials depend on us knowing up-to-date PNI. Use the latest
{ startDayInMs, endDayInMs } // value from the server and log error on mismatch.
const { pni: untaggedPni, credentials: rawCredentials } =
await server.getGroupCredentials({ startDayInMs, endDayInMs });
strictAssert(
untaggedPni,
'Server must give pni along with group credentials'
); );
strictAssert(pni, 'Server must give pni along with group credentials'); const pni = toTaggedPni(untaggedPni);
const localPni = window.storage.user.getPni(); const localPni = window.storage.user.getPni();
if (pni !== localPni) { if (pni !== localPni) {
@ -163,9 +169,9 @@ export async function maybeFetchNewCredentials(): Promise<void> {
const newCredentials = sortCredentials(rawCredentials).map( const newCredentials = sortCredentials(rawCredentials).map(
(item: GroupCredentialType) => { (item: GroupCredentialType) => {
const authCredential = const authCredential =
clientZKAuthOperations.receiveAuthCredentialWithPni( clientZKAuthOperations.receiveAuthCredentialWithPniAsServiceId(
aci, toAciObject(aci),
pni, toPniObject(pni),
item.redemptionTime, item.redemptionTime,
new AuthCredentialWithPniResponse( new AuthCredentialWithPniResponse(
Buffer.from(item.credential, 'base64') Buffer.from(item.credential, 'base64')

View file

@ -23,7 +23,7 @@ type NotificationDataType = Readonly<{
notificationIconAbsolutePath?: undefined | string; notificationIconAbsolutePath?: undefined | string;
reaction?: { reaction?: {
emoji: string; emoji: string;
targetAuthorUuid: string; targetAuthorAci: string;
targetTimestamp: number; targetTimestamp: number;
}; };
senderTitle: string; senderTitle: string;
@ -240,18 +240,18 @@ class NotificationService extends EventEmitter {
// Remove the last notification if both conditions hold: // Remove the last notification if both conditions hold:
// //
// 1. Either `conversationId` or `messageId` matches (if present) // 1. Either `conversationId` or `messageId` matches (if present)
// 2. `emoji`, `targetAuthorUuid`, `targetTimestamp` matches (if present) // 2. `emoji`, `targetAuthorAci`, `targetTimestamp` matches (if present)
public removeBy({ public removeBy({
conversationId, conversationId,
messageId, messageId,
emoji, emoji,
targetAuthorUuid, targetAuthorAci,
targetTimestamp, targetTimestamp,
}: Readonly<{ }: Readonly<{
conversationId?: string; conversationId?: string;
messageId?: string; messageId?: string;
emoji?: string; emoji?: string;
targetAuthorUuid?: string; targetAuthorAci?: string;
targetTimestamp?: number; targetTimestamp?: number;
}>): void { }>): void {
if (!this.notificationData) { if (!this.notificationData) {
@ -280,10 +280,10 @@ class NotificationService extends EventEmitter {
if ( if (
reaction && reaction &&
emoji && emoji &&
targetAuthorUuid && targetAuthorAci &&
targetTimestamp && targetTimestamp &&
(reaction.emoji !== emoji || (reaction.emoji !== emoji ||
reaction.targetAuthorUuid !== targetAuthorUuid || reaction.targetAuthorAci !== targetAuthorAci ||
reaction.targetTimestamp !== targetTimestamp) reaction.targetTimestamp !== targetTimestamp)
) { ) {
return; return;

View file

@ -81,7 +81,7 @@ export class ProfileService {
); );
} }
if (window.ConversationController.isSignalConversation(conversationId)) { if (window.ConversationController.isSignalConversationId(conversationId)) {
return; return;
} }

View file

@ -252,7 +252,7 @@ async function generateManifest(
identifierType = ITEM_TYPE.ACCOUNT; identifierType = ITEM_TYPE.ACCOUNT;
} else if (conversationType === ConversationTypes.Direct) { } else if (conversationType === ConversationTypes.Direct) {
// Contacts must have UUID // Contacts must have UUID
if (!conversation.get('uuid')) { if (!conversation.getServiceId()) {
continue; continue;
} }

View file

@ -335,7 +335,7 @@ export function toAccountRecord(
if (pinnedConversation.get('type') === 'private') { if (pinnedConversation.get('type') === 'private') {
pinnedConversationRecord.identifier = 'contact'; pinnedConversationRecord.identifier = 'contact';
pinnedConversationRecord.contact = { pinnedConversationRecord.contact = {
uuid: pinnedConversation.get('uuid'), serviceId: pinnedConversation.getServiceId(),
e164: pinnedConversation.get('e164'), e164: pinnedConversation.get('e164'),
}; };
} else if (isGroupV1(pinnedConversation.attributes)) { } else if (isGroupV1(pinnedConversation.attributes)) {
@ -1000,7 +1000,7 @@ export async function mergeContactRecord(
}); });
// We're going to ignore this; it's likely a PNI-only contact we've already merged // We're going to ignore this; it's likely a PNI-only contact we've already merged
if (conversation.get('uuid') !== serviceId) { if (conversation.getServiceId() !== serviceId) {
log.warn( log.warn(
`mergeContactRecord: ${conversation.idForLogging()} ` + `mergeContactRecord: ${conversation.idForLogging()} ` +
`with storageId ${conversation.get('storageID')} ` + `with storageId ${conversation.get('storageID')} ` +
@ -1319,14 +1319,19 @@ export async function mergeAccountRecord(
let conversation: ConversationModel | undefined; let conversation: ConversationModel | undefined;
if (contact) { if (contact) {
if (!contact.uuid && !contact.e164) { if (!contact.serviceId && !contact.e164) {
log.error( log.error(
'storageService.mergeAccountRecord: No uuid or e164 on contact' 'storageService.mergeAccountRecord: No serviceId or e164 on contact'
); );
return undefined; return undefined;
} }
conversation = window.ConversationController.lookupOrCreate({ conversation = window.ConversationController.lookupOrCreate({
uuid: contact.uuid, serviceId: contact.serviceId
? normalizeServiceId(
contact.serviceId,
'AccountRecord.pin.serviceId'
)
: undefined,
e164: contact.e164, e164: contact.e164,
reason: 'storageService.mergeAccountRecord', reason: 'storageService.mergeAccountRecord',
}); });
@ -1616,13 +1621,13 @@ export async function mergeStoryDistributionListRecord(
const localMembersListSet = new Set(localStoryDistributionList.members); const localMembersListSet = new Set(localStoryDistributionList.members);
const toAdd: Array<ServiceIdString> = remoteListMembers.filter( const toAdd: Array<ServiceIdString> = remoteListMembers.filter(
uuid => !localMembersListSet.has(uuid) serviceId => !localMembersListSet.has(serviceId)
); );
const remoteMemberListSet = new Set(remoteListMembers); const remoteMemberListSet = new Set(remoteListMembers);
const toRemove: Array<ServiceIdString> = const toRemove: Array<ServiceIdString> =
localStoryDistributionList.members.filter( localStoryDistributionList.members.filter(
uuid => !remoteMemberListSet.has(uuid) serviceId => !remoteMemberListSet.has(serviceId)
); );
details.push('updated'); details.push('updated');

View file

@ -112,7 +112,7 @@ export function getStoryDataFromMessageAttributes(
'readStatus', 'readStatus',
'sendStateByConversationId', 'sendStateByConversationId',
'source', 'source',
'sourceUuid', 'sourceServiceId',
'storyDistributionListId', 'storyDistributionListId',
'storyRecipientsVersion', 'storyRecipientsVersion',
'timestamp', 'timestamp',
@ -144,7 +144,7 @@ async function repairUnexpiredStories(): Promise<void> {
const storiesWithExpiry = storyData const storiesWithExpiry = storyData
.filter( .filter(
story => story =>
story.sourceUuid !== SIGNAL_ACI && story.sourceServiceId !== SIGNAL_ACI &&
(!story.expirationStartTimestamp || (!story.expirationStartTimestamp ||
!story.expireTimer || !story.expireTimer ||
story.expireTimer > DAY_AS_SECONDS) story.expireTimer > DAY_AS_SECONDS)

View file

@ -29,7 +29,7 @@ export async function writeProfile(
if (!model) { if (!model) {
return; return;
} }
await getProfile(model.get('uuid'), model.get('e164')); await getProfile(model.getServiceId(), model.get('e164'));
// Encrypt the profile data, update profile, and if needed upload the avatar // Encrypt the profile data, update profile, and if needed upload the avatar
const { const {

View file

@ -15,7 +15,7 @@ import { assertDev, softAssert } from '../util/assert';
import { mapObjectWithSpec } from '../util/mapObjectWithSpec'; import { mapObjectWithSpec } from '../util/mapObjectWithSpec';
import type { ObjectMappingSpecType } from '../util/mapObjectWithSpec'; import type { ObjectMappingSpecType } from '../util/mapObjectWithSpec';
import { cleanDataForIpc } from './cleanDataForIpc'; import { cleanDataForIpc } from './cleanDataForIpc';
import type { AciString } from '../types/ServiceId'; import type { AciString, ServiceIdString } from '../types/ServiceId';
import createTaskWithTimeout from '../textsecure/TaskWithTimeout'; import createTaskWithTimeout from '../textsecure/TaskWithTimeout';
import * as log from '../logging/log'; import * as log from '../logging/log';
import { isValidUuid } from '../util/isValidUuid'; import { isValidUuid } from '../util/isValidUuid';
@ -514,19 +514,19 @@ function handleSearchMessageJSON(
async function searchMessages({ async function searchMessages({
query, query,
options, options,
contactUuidsMatchingQuery, contactServiceIdsMatchingQuery,
conversationId, conversationId,
}: { }: {
query: string; query: string;
options?: { limit?: number }; options?: { limit?: number };
contactUuidsMatchingQuery?: Array<string>; contactServiceIdsMatchingQuery?: Array<ServiceIdString>;
conversationId?: string; conversationId?: string;
}): Promise<Array<ClientSearchResultMessageType>> { }): Promise<Array<ClientSearchResultMessageType>> {
const messages = await channels.searchMessages({ const messages = await channels.searchMessages({
query, query,
conversationId, conversationId,
options, options,
contactUuidsMatchingQuery, contactServiceIdsMatchingQuery,
}); });
return handleSearchMessageJSON(messages); return handleSearchMessageJSON(messages);

View file

@ -14,7 +14,7 @@ import type { AttachmentType } from '../types/Attachment';
import type { BytesToStrings } from '../types/Util'; import type { BytesToStrings } from '../types/Util';
import type { QualifiedAddressStringType } from '../types/QualifiedAddress'; import type { QualifiedAddressStringType } from '../types/QualifiedAddress';
import type { StoryDistributionIdString } from '../types/StoryDistributionId'; import type { StoryDistributionIdString } from '../types/StoryDistributionId';
import type { AciString, ServiceIdString } from '../types/ServiceId'; import type { AciString, PniString, ServiceIdString } from '../types/ServiceId';
import type { BadgeType } from '../badges/types'; import type { BadgeType } from '../badges/types';
import type { RemoveAllConfiguration } from '../types/RemoveAllConfiguration'; import type { RemoveAllConfiguration } from '../types/RemoveAllConfiguration';
import type { LoggerType } from '../types/Logging'; import type { LoggerType } from '../types/Logging';
@ -126,7 +126,7 @@ export type KyberPreKeyType = {
isConfirmed: boolean; isConfirmed: boolean;
isLastResort: boolean; isLastResort: boolean;
keyId: number; keyId: number;
ourUuid: ServiceIdString; ourServiceId: ServiceIdString;
}; };
export type StoredKyberPreKeyType = KyberPreKeyType & { export type StoredKyberPreKeyType = KyberPreKeyType & {
data: string; data: string;
@ -136,7 +136,7 @@ export type PreKeyType = {
createdAt: number; createdAt: number;
keyId: number; keyId: number;
ourUuid: ServiceIdString; ourServiceId: ServiceIdString;
privateKey: Uint8Array; privateKey: Uint8Array;
publicKey: Uint8Array; publicKey: Uint8Array;
}; };
@ -152,7 +152,7 @@ export type ServerSearchResultMessageType = {
ftsSnippet: string | null; ftsSnippet: string | null;
// Otherwise, a matching mention will be returned // Otherwise, a matching mention will be returned
mentionUuid: string | null; mentionAci: string | null;
mentionStart: number | null; mentionStart: number | null;
mentionLength: number | null; mentionLength: number | null;
}; };
@ -178,7 +178,7 @@ export type SentMessagesType = Array<string>;
// These two are for test only // These two are for test only
export type SentRecipientsDBType = { export type SentRecipientsDBType = {
payloadId: number; payloadId: number;
recipientUuid: string; recipientServiceId: ServiceIdString;
deviceId: number; deviceId: number;
}; };
export type SentMessageDBType = { export type SentMessageDBType = {
@ -199,8 +199,8 @@ export type SenderKeyType = {
export type SenderKeyIdType = SenderKeyType['id']; export type SenderKeyIdType = SenderKeyType['id'];
export type SessionType = { export type SessionType = {
id: QualifiedAddressStringType; id: QualifiedAddressStringType;
ourUuid: ServiceIdString; ourServiceId: ServiceIdString;
uuid: ServiceIdString; serviceId: ServiceIdString;
conversationId: string; conversationId: string;
deviceId: number; deviceId: number;
record: string; record: string;
@ -210,7 +210,7 @@ export type SessionIdType = SessionType['id'];
export type SignedPreKeyType = { export type SignedPreKeyType = {
confirmed: boolean; confirmed: boolean;
created_at: number; created_at: number;
ourUuid: ServiceIdString; ourServiceId: ServiceIdString;
id: `${ServiceIdString}:${number}`; id: `${ServiceIdString}:${number}`;
keyId: number; keyId: number;
privateKey: Uint8Array; privateKey: Uint8Array;
@ -219,7 +219,7 @@ export type SignedPreKeyType = {
export type StoredSignedPreKeyType = { export type StoredSignedPreKeyType = {
confirmed: boolean; confirmed: boolean;
created_at: number; created_at: number;
ourUuid: ServiceIdString; ourServiceId: ServiceIdString;
id: `${ServiceIdString}:${number}`; id: `${ServiceIdString}:${number}`;
keyId: number; keyId: number;
privateKey: string; privateKey: string;
@ -305,10 +305,10 @@ export type UnprocessedType = {
messageAgeSec?: number; messageAgeSec?: number;
source?: string; source?: string;
sourceUuid?: ServiceIdString; sourceServiceId?: ServiceIdString;
sourceDevice?: number; sourceDevice?: number;
destinationUuid?: ServiceIdString; destinationServiceId?: ServiceIdString;
updatedPni?: ServiceIdString; updatedPni?: PniString;
serverGuid?: string; serverGuid?: string;
serverTimestamp?: number; serverTimestamp?: number;
decrypted?: string; decrypted?: string;
@ -319,7 +319,7 @@ export type UnprocessedType = {
export type UnprocessedUpdateType = { export type UnprocessedUpdateType = {
source?: string; source?: string;
sourceUuid?: ServiceIdString; sourceServiceId?: ServiceIdString;
sourceDevice?: number; sourceDevice?: number;
serverGuid?: string; serverGuid?: string;
serverTimestamp?: number; serverTimestamp?: number;
@ -339,7 +339,7 @@ export type DeleteSentProtoRecipientOptionsType = Readonly<{
}>; }>;
export type DeleteSentProtoRecipientResultType = Readonly<{ export type DeleteSentProtoRecipientResultType = Readonly<{
successfulPhoneNumberShares: ReadonlyArray<string>; successfulPhoneNumberShares: ReadonlyArray<ServiceIdString>;
}>; }>;
export type StoryDistributionType = Readonly<{ export type StoryDistributionType = Readonly<{
@ -353,7 +353,7 @@ export type StoryDistributionType = Readonly<{
StorageServiceFieldsType; StorageServiceFieldsType;
export type StoryDistributionMemberType = Readonly<{ export type StoryDistributionMemberType = Readonly<{
listId: StoryDistributionIdString; listId: StoryDistributionIdString;
uuid: ServiceIdString; serviceId: ServiceIdString;
}>; }>;
export type StoryDistributionWithMembersType = Readonly< export type StoryDistributionWithMembersType = Readonly<
{ {
@ -370,7 +370,7 @@ export type StoryReadType = Readonly<{
export type ReactionResultType = Pick< export type ReactionResultType = Pick<
ReactionType, ReactionType,
'targetAuthorUuid' | 'targetTimestamp' | 'messageId' 'targetAuthorAci' | 'targetTimestamp' | 'messageId'
> & { rowid: number }; > & { rowid: number };
export type GetUnreadByConversationAndMarkReadResultType = Array< export type GetUnreadByConversationAndMarkReadResultType = Array<
@ -378,7 +378,7 @@ export type GetUnreadByConversationAndMarkReadResultType = Array<
MessageType, MessageType,
| 'id' | 'id'
| 'source' | 'source'
| 'sourceUuid' | 'sourceServiceId'
| 'sent_at' | 'sent_at'
| 'type' | 'type'
| 'readStatus' | 'readStatus'
@ -593,7 +593,7 @@ export type DataInterface = {
_removeAllReactions: () => Promise<void>; _removeAllReactions: () => Promise<void>;
getMessageBySender: (options: { getMessageBySender: (options: {
source?: string; source?: string;
sourceUuid?: ServiceIdString; sourceServiceId?: ServiceIdString;
sourceDevice?: number; sourceDevice?: number;
sent_at: number; sent_at: number;
}) => Promise<MessageType | undefined>; }) => Promise<MessageType | undefined>;
@ -618,7 +618,7 @@ export type DataInterface = {
// getOlderMessagesByConversation is JSON on server, full message on Client // getOlderMessagesByConversation is JSON on server, full message on Client
getAllStories: (options: { getAllStories: (options: {
conversationId?: string; conversationId?: string;
sourceUuid?: ServiceIdString; sourceServiceId?: ServiceIdString;
}) => Promise<GetAllStoriesResultType>; }) => Promise<GetAllStoriesResultType>;
// getNewerMessagesByConversation is JSON on server, full message on Client // getNewerMessagesByConversation is JSON on server, full message on Client
getMessageMetricsForConversation: (options: { getMessageMetricsForConversation: (options: {
@ -838,12 +838,12 @@ export type ServerInterface = DataInterface & {
query, query,
conversationId, conversationId,
options, options,
contactUuidsMatchingQuery, contactServiceIdsMatchingQuery,
}: { }: {
query: string; query: string;
conversationId?: string; conversationId?: string;
options?: { limit?: number }; options?: { limit?: number };
contactUuidsMatchingQuery?: Array<string>; contactServiceIdsMatchingQuery?: Array<ServiceIdString>;
}) => Promise<Array<ServerSearchResultMessageType>>; }) => Promise<Array<ServerSearchResultMessageType>>;
getRecentStoryReplies( getRecentStoryReplies(
@ -938,12 +938,12 @@ export type ClientExclusiveInterface = {
query, query,
conversationId, conversationId,
options, options,
contactUuidsMatchingQuery, contactServiceIdsMatchingQuery,
}: { }: {
query: string; query: string;
conversationId?: string; conversationId?: string;
options?: { limit?: number }; options?: { limit?: number };
contactUuidsMatchingQuery?: Array<string>; contactServiceIdsMatchingQuery?: Array<ServiceIdString>;
}) => Promise<Array<ClientSearchResultMessageType>>; }) => Promise<Array<ClientSearchResultMessageType>>;
getRecentStoryReplies( getRecentStoryReplies(

View file

@ -716,8 +716,10 @@ async function removeKyberPreKeysByServiceId(
serviceId: ServiceIdString serviceId: ServiceIdString
): Promise<void> { ): Promise<void> {
const db = getInstance(); const db = getInstance();
db.prepare<Query>('DELETE FROM kyberPreKeys WHERE ourUuid IS $uuid;').run({ db.prepare<Query>(
uuid: serviceId, 'DELETE FROM kyberPreKeys WHERE ourServiceId IS $serviceId;'
).run({
serviceId,
}); });
} }
async function removeAllKyberPreKeys(): Promise<void> { async function removeAllKyberPreKeys(): Promise<void> {
@ -748,8 +750,10 @@ async function removePreKeysByServiceId(
serviceId: ServiceIdString serviceId: ServiceIdString
): Promise<void> { ): Promise<void> {
const db = getInstance(); const db = getInstance();
db.prepare<Query>('DELETE FROM preKeys WHERE ourUuid IS $uuid;').run({ db.prepare<Query>(
uuid: serviceId, 'DELETE FROM preKeys WHERE ourServiceId IS $serviceId;'
).run({
serviceId,
}); });
} }
async function removeAllPreKeys(): Promise<void> { async function removeAllPreKeys(): Promise<void> {
@ -784,8 +788,10 @@ async function removeSignedPreKeysByServiceId(
serviceId: ServiceIdString serviceId: ServiceIdString
): Promise<void> { ): Promise<void> {
const db = getInstance(); const db = getInstance();
db.prepare<Query>('DELETE FROM signedPreKeys WHERE ourUuid IS $uuid;').run({ db.prepare<Query>(
uuid: serviceId, 'DELETE FROM signedPreKeys WHERE ourServiceId IS $serviceId;'
).run({
serviceId,
}); });
} }
async function removeAllSignedPreKeys(): Promise<void> { async function removeAllSignedPreKeys(): Promise<void> {
@ -942,11 +948,11 @@ async function insertSentProto(
` `
INSERT INTO sendLogRecipients ( INSERT INTO sendLogRecipients (
payloadId, payloadId,
recipientUuid, recipientServiceId,
deviceId deviceId
) VALUES ( ) VALUES (
$id, $id,
$recipientUuid, $recipientServiceId,
$deviceId $deviceId
); );
` `
@ -963,7 +969,7 @@ async function insertSentProto(
for (const deviceId of deviceIds) { for (const deviceId of deviceIds) {
recipientStatement.run({ recipientStatement.run({
id, id,
recipientUuid: recipientServiceId, recipientServiceId,
deviceId, deviceId,
}); });
} }
@ -1043,11 +1049,11 @@ async function insertProtoRecipients({
` `
INSERT INTO sendLogRecipients ( INSERT INTO sendLogRecipients (
payloadId, payloadId,
recipientUuid, recipientServiceId,
deviceId deviceId
) VALUES ( ) VALUES (
$id, $id,
$recipientUuid, $recipientServiceId,
$deviceId $deviceId
); );
` `
@ -1056,7 +1062,7 @@ async function insertProtoRecipients({
for (const deviceId of deviceIds) { for (const deviceId of deviceIds) {
statement.run({ statement.run({
id, id,
recipientUuid: recipientServiceId, recipientServiceId,
deviceId, deviceId,
}); });
} }
@ -1076,7 +1082,7 @@ async function deleteSentProtoRecipient(
// returned row. // returned row.
return db.transaction(() => { return db.transaction(() => {
const successfulPhoneNumberShares = new Array<string>(); const successfulPhoneNumberShares = new Array<ServiceIdString>();
for (const item of items) { for (const item of items) {
const { timestamp, recipientServiceId, deviceId } = item; const { timestamp, recipientServiceId, deviceId } = item;
@ -1091,10 +1097,10 @@ async function deleteSentProtoRecipient(
ON sendLogRecipients.payloadId = sendLogPayloads.id ON sendLogRecipients.payloadId = sendLogPayloads.id
WHERE WHERE
sendLogPayloads.timestamp = $timestamp AND sendLogPayloads.timestamp = $timestamp AND
sendLogRecipients.recipientUuid = $recipientUuid AND sendLogRecipients.recipientServiceId = $recipientServiceId AND
sendLogRecipients.deviceId = $deviceId; sendLogRecipients.deviceId = $deviceId;
` `
).all({ timestamp, recipientUuid: recipientServiceId, deviceId }); ).all({ timestamp, recipientServiceId, deviceId });
if (!rows.length) { if (!rows.length) {
continue; continue;
} }
@ -1114,20 +1120,20 @@ async function deleteSentProtoRecipient(
DELETE FROM sendLogRecipients DELETE FROM sendLogRecipients
WHERE WHERE
payloadId = $id AND payloadId = $id AND
recipientUuid = $recipientUuid AND recipientServiceId = $recipientServiceId AND
deviceId = $deviceId; deviceId = $deviceId;
` `
).run({ id, recipientUuid: recipientServiceId, deviceId }); ).run({ id, recipientServiceId, deviceId });
// 3. See how many more recipient devices there were for this payload. // 3. See how many more recipient devices there were for this payload.
const remainingDevices = prepare( const remainingDevices = prepare(
db, db,
` `
SELECT count(1) FROM sendLogRecipients SELECT count(1) FROM sendLogRecipients
WHERE payloadId = $id AND recipientUuid = $recipientUuid; WHERE payloadId = $id AND recipientServiceId = $recipientServiceId;
`, `,
{ pluck: true } { pluck: true }
).get({ id, recipientUuid: recipientServiceId }); ).get({ id, recipientServiceId });
// 4. If there are no remaining devices for this recipient and we included // 4. If there are no remaining devices for this recipient and we included
// the pni signature in the proto - return the recipient to the caller. // the pni signature in the proto - return the recipient to the caller.
@ -1203,12 +1209,12 @@ async function getSentProtoByRecipient({
LEFT JOIN sendLogMessageIds ON sendLogMessageIds.payloadId = sendLogPayloads.id LEFT JOIN sendLogMessageIds ON sendLogMessageIds.payloadId = sendLogPayloads.id
WHERE WHERE
sendLogPayloads.timestamp = $timestamp AND sendLogPayloads.timestamp = $timestamp AND
sendLogRecipients.recipientUuid = $recipientUuid sendLogRecipients.recipientServiceId = $recipientServiceId
GROUP BY sendLogPayloads.id; GROUP BY sendLogPayloads.id;
` `
).get({ ).get({
timestamp, timestamp,
recipientUuid: recipientServiceId, recipientServiceId,
}); });
if (!row) { if (!row) {
@ -1265,7 +1271,7 @@ async function _getAllSentProtoMessageIds(): Promise<Array<SentMessageDBType>> {
const SESSIONS_TABLE = 'sessions'; const SESSIONS_TABLE = 'sessions';
function createOrUpdateSessionSync(data: SessionType): void { function createOrUpdateSessionSync(data: SessionType): void {
const db = getInstance(); const db = getInstance();
const { id, conversationId, ourUuid, uuid } = data; const { id, conversationId, ourServiceId, serviceId } = data;
if (!id) { if (!id) {
throw new Error( throw new Error(
'createOrUpdateSession: Provided data did not have a truthy id' 'createOrUpdateSession: Provided data did not have a truthy id'
@ -1283,22 +1289,22 @@ function createOrUpdateSessionSync(data: SessionType): void {
INSERT OR REPLACE INTO sessions ( INSERT OR REPLACE INTO sessions (
id, id,
conversationId, conversationId,
ourUuid, ourServiceId,
uuid, serviceId,
json json
) values ( ) values (
$id, $id,
$conversationId, $conversationId,
$ourUuid, $ourServiceId,
$uuid, $serviceId,
$json $json
) )
` `
).run({ ).run({
id, id,
conversationId, conversationId,
ourUuid, ourServiceId,
uuid, serviceId,
json: objectToJSON(data), json: objectToJSON(data),
}); });
} }
@ -1370,10 +1376,10 @@ async function removeSessionsByServiceId(
db.prepare<Query>( db.prepare<Query>(
` `
DELETE FROM sessions DELETE FROM sessions
WHERE uuid = $uuid; WHERE serviceId = $serviceId;
` `
).run({ ).run({
uuid: serviceId, serviceId,
}); });
} }
async function removeAllSessions(): Promise<void> { async function removeAllSessions(): Promise<void> {
@ -1390,7 +1396,7 @@ async function getConversationCount(): Promise<number> {
function getConversationMembersList({ members, membersV2 }: ConversationType) { function getConversationMembersList({ members, membersV2 }: ConversationType) {
if (membersV2) { if (membersV2) {
return membersV2.map((item: GroupV2MemberType) => item.uuid).join(' '); return membersV2.map((item: GroupV2MemberType) => item.aci).join(' ');
} }
if (members) { if (members) {
return members.join(' '); return members.join(' ');
@ -1412,7 +1418,7 @@ function saveConversationSync(
profileName, profileName,
profileLastFetchedAt, profileLastFetchedAt,
type, type,
uuid, serviceId,
} = data; } = data;
const membersList = getConversationMembersList(data); const membersList = getConversationMembersList(data);
@ -1424,7 +1430,7 @@ function saveConversationSync(
json, json,
e164, e164,
uuid, serviceId,
groupId, groupId,
active_at, active_at,
@ -1440,7 +1446,7 @@ function saveConversationSync(
$json, $json,
$e164, $e164,
$uuid, $serviceId,
$groupId, $groupId,
$active_at, $active_at,
@ -1460,7 +1466,7 @@ function saveConversationSync(
), ),
e164: e164 || null, e164: e164 || null,
uuid: uuid || null, serviceId: serviceId || null,
groupId: groupId || null, groupId: groupId || null,
active_at: active_at || null, active_at: active_at || null,
@ -1506,7 +1512,7 @@ function updateConversationSync(
profileFamilyName, profileFamilyName,
profileLastFetchedAt, profileLastFetchedAt,
e164, e164,
uuid, serviceId,
} = data; } = data;
const membersList = getConversationMembersList(data); const membersList = getConversationMembersList(data);
@ -1517,7 +1523,7 @@ function updateConversationSync(
json = $json, json = $json,
e164 = $e164, e164 = $e164,
uuid = $uuid, serviceId = $serviceId,
active_at = $active_at, active_at = $active_at,
type = $type, type = $type,
@ -1536,7 +1542,7 @@ function updateConversationSync(
), ),
e164: e164 || null, e164: e164 || null,
uuid: uuid || null, serviceId: serviceId || null,
active_at: active_at || null, active_at: active_at || null,
type, type,
@ -1668,12 +1674,12 @@ async function getAllGroupsInvolvingServiceId(
SELECT json, profileLastFetchedAt SELECT json, profileLastFetchedAt
FROM conversations WHERE FROM conversations WHERE
type = 'group' AND type = 'group' AND
members LIKE $uuid members LIKE $serviceId
ORDER BY id ASC; ORDER BY id ASC;
` `
) )
.all({ .all({
uuid: `%${serviceId}%`, serviceId: `%${serviceId}%`,
}); });
return rows.map(row => rowToConversation(row)); return rows.map(row => rowToConversation(row));
@ -1683,12 +1689,12 @@ async function searchMessages({
query, query,
options, options,
conversationId, conversationId,
contactUuidsMatchingQuery, contactServiceIdsMatchingQuery,
}: { }: {
query: string; query: string;
options?: { limit?: number }; options?: { limit?: number };
conversationId?: string; conversationId?: string;
contactUuidsMatchingQuery?: Array<string>; contactServiceIdsMatchingQuery?: Array<ServiceIdString>;
}): Promise<Array<ServerSearchResultMessageType>> { }): Promise<Array<ServerSearchResultMessageType>> {
const { limit = conversationId ? 100 : 500 } = options ?? {}; const { limit = conversationId ? 100 : 500 } = options ?? {};
@ -1781,12 +1787,12 @@ async function searchMessages({
let result: Array<ServerSearchResultMessageType>; let result: Array<ServerSearchResultMessageType>;
if (!contactUuidsMatchingQuery?.length) { if (!contactServiceIdsMatchingQuery?.length) {
const [sqlQuery, params] = sql`${ftsFragment};`; const [sqlQuery, params] = sql`${ftsFragment};`;
result = db.prepare(sqlQuery).all(params); result = db.prepare(sqlQuery).all(params);
} else { } else {
// If contactUuidsMatchingQuery is not empty, we due an OUTER JOIN between: // If contactServiceIdsMatchingQuery is not empty, we due an OUTER JOIN between:
// 1) the messages that mention at least one of contactUuidsMatchingQuery, and // 1) the messages that mention at least one of contactServiceIdsMatchingQuery, and
// 2) the messages that match all the search terms via FTS // 2) the messages that match all the search terms via FTS
// //
// Note: this groups the results by rowid, so even if one message mentions multiple // Note: this groups the results by rowid, so even if one message mentions multiple
@ -1798,15 +1804,15 @@ async function searchMessages({
COALESCE(messages.sent_at, ftsResults.sent_at) as sent_at, COALESCE(messages.sent_at, ftsResults.sent_at) as sent_at,
COALESCE(messages.received_at, ftsResults.received_at) as received_at, COALESCE(messages.received_at, ftsResults.received_at) as received_at,
ftsResults.ftsSnippet, ftsResults.ftsSnippet,
mentionUuid, mentionAci,
start as mentionStart, start as mentionStart,
length as mentionLength length as mentionLength
FROM mentions FROM mentions
INNER JOIN messages INNER JOIN messages
ON ON
messages.id = mentions.messageId messages.id = mentions.messageId
AND mentions.mentionUuid IN ( AND mentions.mentionAci IN (
${sqlJoin(contactUuidsMatchingQuery, ', ')} ${sqlJoin(contactServiceIdsMatchingQuery, ', ')}
) )
AND ${ AND ${
conversationId conversationId
@ -1944,7 +1950,7 @@ function saveMessageSync(
sent_at, sent_at,
serverGuid, serverGuid,
source, source,
sourceUuid, sourceServiceId,
sourceDevice, sourceDevice,
storyId, storyId,
callId, callId,
@ -2002,7 +2008,7 @@ function saveMessageSync(
serverGuid: serverGuid || null, serverGuid: serverGuid || null,
sent_at: sent_at || null, sent_at: sent_at || null,
source: source || null, source: source || null,
sourceUuid: sourceUuid || null, sourceServiceId: sourceServiceId || null,
sourceDevice: sourceDevice || null, sourceDevice: sourceDevice || null,
storyId: storyId || null, storyId: storyId || null,
callId: callId || null, callId: callId || null,
@ -2035,7 +2041,7 @@ function saveMessageSync(
serverGuid = $serverGuid, serverGuid = $serverGuid,
sent_at = $sent_at, sent_at = $sent_at,
source = $source, source = $source,
sourceUuid = $sourceUuid, sourceServiceId = $sourceServiceId,
sourceDevice = $sourceDevice, sourceDevice = $sourceDevice,
storyId = $storyId, storyId = $storyId,
callId = $callId, callId = $callId,
@ -2081,7 +2087,7 @@ function saveMessageSync(
serverGuid, serverGuid,
sent_at, sent_at,
source, source,
sourceUuid, sourceServiceId,
sourceDevice, sourceDevice,
storyId, storyId,
callId, callId,
@ -2108,7 +2114,7 @@ function saveMessageSync(
$serverGuid, $serverGuid,
$sent_at, $sent_at,
$source, $source,
$sourceUuid, $sourceServiceId,
$sourceDevice, $sourceDevice,
$storyId, $storyId,
$callId, $callId,
@ -2247,12 +2253,12 @@ async function getAllMessageIds(): Promise<Array<string>> {
async function getMessageBySender({ async function getMessageBySender({
source, source,
sourceUuid, sourceServiceId,
sourceDevice, sourceDevice,
sent_at, sent_at,
}: { }: {
source?: string; source?: string;
sourceUuid?: ServiceIdString; sourceServiceId?: ServiceIdString;
sourceDevice?: number; sourceDevice?: number;
sent_at: number; sent_at: number;
}): Promise<MessageType | undefined> { }): Promise<MessageType | undefined> {
@ -2261,14 +2267,14 @@ async function getMessageBySender({
db, db,
` `
SELECT json FROM messages WHERE SELECT json FROM messages WHERE
(source = $source OR sourceUuid = $sourceUuid) AND (source = $source OR sourceServiceId = $sourceServiceId) AND
sourceDevice = $sourceDevice AND sourceDevice = $sourceDevice AND
sent_at = $sent_at sent_at = $sent_at
LIMIT 2; LIMIT 2;
` `
).all({ ).all({
source: source || null, source: source || null,
sourceUuid: sourceUuid || null, sourceServiceId: sourceServiceId || null,
sourceDevice: sourceDevice || null, sourceDevice: sourceDevice || null,
sent_at, sent_at,
}); });
@ -2277,7 +2283,7 @@ async function getMessageBySender({
log.warn('getMessageBySender: More than one message found for', { log.warn('getMessageBySender: More than one message found for', {
sent_at, sent_at,
source, source,
sourceUuid, sourceServiceId,
sourceDevice, sourceDevice,
}); });
} }
@ -2392,7 +2398,7 @@ async function getUnreadByConversationAndMarkRead({
'id', 'id',
'sent_at', 'sent_at',
'source', 'source',
'sourceUuid', 'sourceServiceId',
'type', 'type',
]), ]),
}; };
@ -2415,7 +2421,7 @@ async function getUnreadReactionsAndMarkRead({
const unreadMessages: Array<ReactionResultType> = db const unreadMessages: Array<ReactionResultType> = db
.prepare<Query>( .prepare<Query>(
` `
SELECT reactions.rowid, targetAuthorUuid, targetTimestamp, messageId SELECT reactions.rowid, targetAuthorAci, targetTimestamp, messageId
FROM reactions FROM reactions
INDEXED BY reactions_unread INDEXED BY reactions_unread
JOIN messages on messages.id IS reactions.messageId JOIN messages on messages.id IS reactions.messageId
@ -2460,7 +2466,7 @@ async function markReactionAsRead(
SELECT * SELECT *
FROM reactions FROM reactions
WHERE WHERE
targetAuthorUuid = $targetAuthorUuid AND targetAuthorAci = $targetAuthorAci AND
targetTimestamp = $targetTimestamp AND targetTimestamp = $targetTimestamp AND
unread = 1 unread = 1
ORDER BY rowId DESC ORDER BY rowId DESC
@ -2468,7 +2474,7 @@ async function markReactionAsRead(
` `
) )
.get({ .get({
targetAuthorUuid: targetAuthorServiceId, targetAuthorAci: targetAuthorServiceId,
targetTimestamp, targetTimestamp,
}); });
@ -2476,11 +2482,11 @@ async function markReactionAsRead(
` `
UPDATE reactions SET UPDATE reactions SET
unread = 0 WHERE unread = 0 WHERE
targetAuthorUuid = $targetAuthorUuid AND targetAuthorAci = $targetAuthorAci AND
targetTimestamp = $targetTimestamp; targetTimestamp = $targetTimestamp;
` `
).run({ ).run({
targetAuthorUuid: targetAuthorServiceId, targetAuthorAci: targetAuthorServiceId,
targetTimestamp, targetTimestamp,
}); });
@ -2494,7 +2500,7 @@ async function addReaction({
fromId, fromId,
messageId, messageId,
messageReceivedAt, messageReceivedAt,
targetAuthorUuid, targetAuthorAci,
targetTimestamp, targetTimestamp,
}: ReactionType): Promise<void> { }: ReactionType): Promise<void> {
const db = getInstance(); const db = getInstance();
@ -2506,7 +2512,7 @@ async function addReaction({
fromId, fromId,
messageId, messageId,
messageReceivedAt, messageReceivedAt,
targetAuthorUuid, targetAuthorAci,
targetTimestamp, targetTimestamp,
unread unread
) VALUES ( ) VALUES (
@ -2515,7 +2521,7 @@ async function addReaction({
$fromId, $fromId,
$messageId, $messageId,
$messageReceivedAt, $messageReceivedAt,
$targetAuthorUuid, $targetAuthorAci,
$targetTimestamp, $targetTimestamp,
$unread $unread
);` );`
@ -2526,7 +2532,7 @@ async function addReaction({
fromId, fromId,
messageId, messageId,
messageReceivedAt, messageReceivedAt,
targetAuthorUuid, targetAuthorAci,
targetTimestamp, targetTimestamp,
unread: 1, unread: 1,
}); });
@ -2549,13 +2555,13 @@ async function removeReactionFromConversation({
`DELETE FROM reactions WHERE `DELETE FROM reactions WHERE
emoji = $emoji AND emoji = $emoji AND
fromId = $fromId AND fromId = $fromId AND
targetAuthorUuid = $targetAuthorUuid AND targetAuthorAci = $targetAuthorAci AND
targetTimestamp = $targetTimestamp;` targetTimestamp = $targetTimestamp;`
) )
.run({ .run({
emoji, emoji,
fromId, fromId,
targetAuthorUuid: targetAuthorServiceId, targetAuthorAci: targetAuthorServiceId,
targetTimestamp, targetTimestamp,
}); });
} }
@ -2725,10 +2731,10 @@ async function getOlderMessagesByConversation(
async function getAllStories({ async function getAllStories({
conversationId, conversationId,
sourceUuid, sourceServiceId,
}: { }: {
conversationId?: string; conversationId?: string;
sourceUuid?: ServiceIdString; sourceServiceId?: ServiceIdString;
}): Promise<GetAllStoriesResultType> { }): Promise<GetAllStoriesResultType> {
const db = getInstance(); const db = getInstance();
const rows: ReadonlyArray<{ const rows: ReadonlyArray<{
@ -2756,13 +2762,13 @@ async function getAllStories({
WHERE WHERE
type IS 'story' AND type IS 'story' AND
($conversationId IS NULL OR conversationId IS $conversationId) AND ($conversationId IS NULL OR conversationId IS $conversationId) AND
($sourceUuid IS NULL OR sourceUuid IS $sourceUuid) ($sourceServiceId IS NULL OR sourceServiceId IS $sourceServiceId)
ORDER BY received_at ASC, sent_at ASC; ORDER BY received_at ASC, sent_at ASC;
` `
) )
.all({ .all({
conversationId: conversationId || null, conversationId: conversationId || null,
sourceUuid: sourceUuid || null, sourceServiceId: sourceServiceId || null,
}); });
return rows.map(row => ({ return rows.map(row => ({
@ -3396,7 +3402,7 @@ function getCallHistoryGroupDataSync(
const [createTempTable] = sql` const [createTempTable] = sql`
CREATE TEMP TABLE temp_callHistory_filtered_conversations ( CREATE TEMP TABLE temp_callHistory_filtered_conversations (
id TEXT, id TEXT,
uuid TEXT, serviceId TEXT,
groupId TEXT groupId TEXT
); );
`; `;
@ -3411,8 +3417,8 @@ function getCallHistoryGroupDataSync(
const [insertQuery, insertParams] = sql` const [insertQuery, insertParams] = sql`
INSERT INTO temp_callHistory_filtered_conversations INSERT INTO temp_callHistory_filtered_conversations
(id, uuid, groupId) (id, serviceId, groupId)
SELECT id, uuid, groupId SELECT id, serviceId, groupId
FROM conversations FROM conversations
WHERE conversations.id IN (${idList}); WHERE conversations.id IN (${idList});
`; `;
@ -3423,11 +3429,11 @@ function getCallHistoryGroupDataSync(
const innerJoin = const innerJoin =
conversationIds != null conversationIds != null
? // peerId can be a conversation id (legacy), a uuid, or a groupId ? // peerId can be a conversation id (legacy), a serviceId, or a groupId
sqlFragment` sqlFragment`
INNER JOIN temp_callHistory_filtered_conversations ON ( INNER JOIN temp_callHistory_filtered_conversations ON (
temp_callHistory_filtered_conversations.id IS c.peerId temp_callHistory_filtered_conversations.id IS c.peerId
OR temp_callHistory_filtered_conversations.uuid IS c.peerId OR temp_callHistory_filtered_conversations.serviceId IS c.peerId
OR temp_callHistory_filtered_conversations.groupId IS c.peerId OR temp_callHistory_filtered_conversations.groupId IS c.peerId
) )
` `
@ -3849,7 +3855,7 @@ function saveUnprocessedSync(data: UnprocessedType): string {
attempts, attempts,
envelope, envelope,
source, source,
sourceUuid, sourceServiceId,
sourceDevice, sourceDevice,
serverGuid, serverGuid,
serverTimestamp, serverTimestamp,
@ -3872,7 +3878,7 @@ function saveUnprocessedSync(data: UnprocessedType): string {
attempts, attempts,
envelope, envelope,
source, source,
sourceUuid, sourceServiceId,
sourceDevice, sourceDevice,
serverGuid, serverGuid,
serverTimestamp, serverTimestamp,
@ -3887,7 +3893,7 @@ function saveUnprocessedSync(data: UnprocessedType): string {
$attempts, $attempts,
$envelope, $envelope,
$source, $source,
$sourceUuid, $sourceServiceId,
$sourceDevice, $sourceDevice,
$serverGuid, $serverGuid,
$serverTimestamp, $serverTimestamp,
@ -3904,7 +3910,7 @@ function saveUnprocessedSync(data: UnprocessedType): string {
attempts, attempts,
envelope: envelope || null, envelope: envelope || null,
source: source || null, source: source || null,
sourceUuid: sourceUuid || null, sourceServiceId: sourceServiceId || null,
sourceDevice: sourceDevice || null, sourceDevice: sourceDevice || null,
serverGuid: serverGuid || null, serverGuid: serverGuid || null,
serverTimestamp: serverTimestamp || null, serverTimestamp: serverTimestamp || null,
@ -3923,7 +3929,7 @@ function updateUnprocessedWithDataSync(
const db = getInstance(); const db = getInstance();
const { const {
source, source,
sourceUuid, sourceServiceId,
sourceDevice, sourceDevice,
serverGuid, serverGuid,
serverTimestamp, serverTimestamp,
@ -3935,7 +3941,7 @@ function updateUnprocessedWithDataSync(
` `
UPDATE unprocessed SET UPDATE unprocessed SET
source = $source, source = $source,
sourceUuid = $sourceUuid, sourceServiceId = $sourceServiceId,
sourceDevice = $sourceDevice, sourceDevice = $sourceDevice,
serverGuid = $serverGuid, serverGuid = $serverGuid,
serverTimestamp = $serverTimestamp, serverTimestamp = $serverTimestamp,
@ -3945,7 +3951,7 @@ function updateUnprocessedWithDataSync(
).run({ ).run({
id, id,
source: source || null, source: source || null,
sourceUuid: sourceUuid || null, sourceServiceId: sourceServiceId || null,
sourceDevice: sourceDevice || null, sourceDevice: sourceDevice || null,
serverGuid: serverGuid || null, serverGuid: serverGuid || null,
serverTimestamp: serverTimestamp || null, serverTimestamp: serverTimestamp || null,
@ -5238,18 +5244,18 @@ async function createNewStoryDistribution(
` `
INSERT OR REPLACE INTO storyDistributionMembers ( INSERT OR REPLACE INTO storyDistributionMembers (
listId, listId,
uuid serviceId
) VALUES ( ) VALUES (
$listId, $listId,
$uuid $serviceId
); );
` `
); );
for (const uuid of members) { for (const serviceId of members) {
memberInsertStatement.run({ memberInsertStatement.run({
listId, listId,
uuid, serviceId,
}); });
} }
})(); })();
@ -5264,7 +5270,7 @@ async function getAllStoryDistributionsWithMembers(): Promise<
return allDistributions.map(list => ({ return allDistributions.map(list => ({
...list, ...list,
members: (byListId[list.id] || []).map(member => member.uuid), members: (byListId[list.id] || []).map(member => member.serviceId),
})); }));
} }
async function getStoryDistributionWithMembers( async function getStoryDistributionWithMembers(
@ -5291,7 +5297,7 @@ async function getStoryDistributionWithMembers(
return { return {
...hydrateStoryDistribution(storyDistribution), ...hydrateStoryDistribution(storyDistribution),
members: members.map(({ uuid }) => uuid), members: members.map(({ serviceId }) => serviceId),
}; };
} }
function modifyStoryDistributionSync( function modifyStoryDistributionSync(
@ -5341,29 +5347,33 @@ function modifyStoryDistributionMembersSync(
` `
INSERT OR REPLACE INTO storyDistributionMembers ( INSERT OR REPLACE INTO storyDistributionMembers (
listId, listId,
uuid serviceId
) VALUES ( ) VALUES (
$listId, $listId,
$uuid $serviceId
); );
` `
); );
for (const uuid of toAdd) { for (const serviceId of toAdd) {
memberInsertStatement.run({ memberInsertStatement.run({
listId, listId,
uuid, serviceId,
}); });
} }
batchMultiVarQuery(db, toRemove, (uuids: ReadonlyArray<ServiceIdString>) => { batchMultiVarQuery(
db.prepare<ArrayQuery>( db,
` toRemove,
(serviceIds: ReadonlyArray<ServiceIdString>) => {
const serviceIdSet = sqlJoin(serviceIds, '?');
const [sqlQuery, sqlParams] = sql`
DELETE FROM storyDistributionMembers DELETE FROM storyDistributionMembers
WHERE listId = ? AND uuid IN ( ${uuids.map(() => '?').join(', ')} ); WHERE listId = ${listId} AND serviceId IN (${serviceIdSet});
` `;
).run([listId, ...uuids]); db.prepare(sqlQuery).run(sqlParams);
}); }
);
} }
async function modifyStoryDistributionWithMembers( async function modifyStoryDistributionWithMembers(
distribution: StoryDistributionType, distribution: StoryDistributionType,
@ -6372,7 +6382,7 @@ async function getUnreadEditedMessagesAndMarkRead({
'id', 'id',
'sent_at', 'sent_at',
'source', 'source',
'sourceUuid', 'sourceServiceId',
'type', 'type',
]), ]),
// Use the edited message timestamp // Use the edited message timestamp

View file

@ -16,7 +16,22 @@ import {
objectToJSON, objectToJSON,
} from '../util'; } from '../util';
import type { EmptyQuery, Query } from '../util'; import type { EmptyQuery, Query } from '../util';
import type { MessageType, ConversationType } from '../Interface';
type MessageType = Readonly<{
id: string;
sourceUuid: string;
groupV2Change?: {
from?: string;
details: Array<{ type: string }>;
};
invitedGV2Members?: Array<{ uuid: string }>;
}>;
type ConversationType = Readonly<{
id: string;
members: Array<string>;
membersV2: Array<{ uuid: string }>;
}>;
export default function updateToSchemaVersion43( export default function updateToSchemaVersion43(
currentVersion: number, currentVersion: number,

View file

@ -4,10 +4,8 @@
import type { Database } from '@signalapp/better-sqlite3'; import type { Database } from '@signalapp/better-sqlite3';
import type { LoggerType } from '../../types/Logging'; import type { LoggerType } from '../../types/Logging';
import type { ServiceIdString } from '../../types/ServiceId';
import { jsonToObject } from '../util'; import { jsonToObject } from '../util';
import type { EmptyQuery } from '../util'; import type { EmptyQuery } from '../util';
import type { ConversationType } from '../Interface';
export default function updateToSchemaVersion53( export default function updateToSchemaVersion53(
currentVersion: number, currentVersion: number,
@ -21,7 +19,13 @@ export default function updateToSchemaVersion53(
type LegacyConversationType = { type LegacyConversationType = {
id: string; id: string;
groupId: string; groupId: string;
bannedMembersV2?: Array<ServiceIdString>; bannedMembersV2?: Array<string>;
};
type ConversationType = {
id: string;
groupId: string;
bannedMembersV2?: Array<{ uuid: string; timestamp: number }>;
}; };
const updateConversationStmt = db.prepare( const updateConversationStmt = db.prepare(

File diff suppressed because it is too large Load diff

View file

@ -63,6 +63,7 @@ import updateToSchemaVersion84 from './84-all-mentions';
import updateToSchemaVersion85 from './85-add-kyber-keys'; import updateToSchemaVersion85 from './85-add-kyber-keys';
import updateToSchemaVersion86 from './86-story-replies-index'; import updateToSchemaVersion86 from './86-story-replies-index';
import updateToSchemaVersion87 from './87-calls-history-table'; import updateToSchemaVersion87 from './87-calls-history-table';
import updateToSchemaVersion88 from './88-service-ids';
function updateToSchemaVersion1( function updateToSchemaVersion1(
currentVersion: number, currentVersion: number,
@ -1996,6 +1997,7 @@ export const SCHEMA_VERSIONS = [
updateToSchemaVersion85, updateToSchemaVersion85,
updateToSchemaVersion86, updateToSchemaVersion86,
updateToSchemaVersion87, updateToSchemaVersion87,
updateToSchemaVersion88,
]; ];
export function updateSchema(db: Database, logger: LoggerType): void { export function updateSchema(db: Database, logger: LoggerType): void {

View file

@ -62,9 +62,9 @@ function checkForAccount(
} }
const conversation = window.ConversationController.get(phoneNumber); const conversation = window.ConversationController.get(phoneNumber);
if (conversation && conversation.get('uuid')) { if (conversation && conversation.getServiceId()) {
log.info(`checkForAccount: found ${phoneNumber} in existing contacts`); log.info(`checkForAccount: found ${phoneNumber} in existing contacts`);
const serviceId = conversation.get('uuid'); const serviceId = conversation.getServiceId();
dispatch({ dispatch({
type: 'accounts/UPDATE', type: 'accounts/UPDATE',
@ -93,8 +93,10 @@ function checkForAccount(
log.info(`checkForAccount: looking ${phoneNumber} up on server`); log.info(`checkForAccount: looking ${phoneNumber} up on server`);
try { try {
const uuidLookup = await getServiceIdsForE164s(server, [phoneNumber]); const serviceIdLookup = await getServiceIdsForE164s(server, [
const maybePair = uuidLookup.get(phoneNumber); phoneNumber,
]);
const maybePair = serviceIdLookup.get(phoneNumber);
if (maybePair) { if (maybePair) {
const { conversation: maybeMerged } = const { conversation: maybeMerged } =
@ -104,7 +106,7 @@ function checkForAccount(
e164: phoneNumber, e164: phoneNumber,
reason: 'checkForAccount', reason: 'checkForAccount',
}); });
serviceId = maybeMerged.get('uuid'); serviceId = maybeMerged.getServiceId();
} }
} catch (error) { } catch (error) {
log.error('checkForAccount:', Errors.toLogFormat(error)); log.error('checkForAccount:', Errors.toLogFormat(error));

View file

@ -936,7 +936,7 @@ function keyChanged(
if (activeCall.callMode === CallMode.Group) { if (activeCall.callMode === CallMode.Group) {
const acisChanged = new Set(activeCallState.safetyNumberChangedAcis); const acisChanged = new Set(activeCallState.safetyNumberChangedAcis);
// Iterate over each participant to ensure that the uuid passed in // Iterate over each participant to ensure that the service id passed in
// matches one of the participants in the group call. // matches one of the participants in the group call.
activeCall.remoteParticipants.forEach(participant => { activeCall.remoteParticipants.forEach(participant => {
if (participant.aci === payload.aci) { if (participant.aci === payload.aci) {

View file

@ -35,6 +35,7 @@ import {
REMOVE_PREVIEW as REMOVE_LINK_PREVIEW, REMOVE_PREVIEW as REMOVE_LINK_PREVIEW,
} from './linkPreviews'; } from './linkPreviews';
import { LinkPreviewSourceType } from '../../types/LinkPreview'; import { LinkPreviewSourceType } from '../../types/LinkPreview';
import type { AciString } from '../../types/ServiceId';
import { completeRecording } from './audioRecorder'; import { completeRecording } from './audioRecorder';
import { RecordingState } from '../../types/AudioRecorder'; import { RecordingState } from '../../types/AudioRecorder';
import { SHOW_TOAST } from './toast'; import { SHOW_TOAST } from './toast';
@ -526,7 +527,7 @@ function sendEditedMessage(
conversationId: string, conversationId: string,
options: WithPreSendChecksOptions & { options: WithPreSendChecksOptions & {
targetMessageId: string; targetMessageId: string;
quoteAuthorUuid?: string; quoteAuthorAci?: AciString;
quoteSentAt?: number; quoteSentAt?: number;
} }
): ThunkAction< ): ThunkAction<
@ -545,7 +546,7 @@ function sendEditedMessage(
message = '', message = '',
bodyRanges, bodyRanges,
quoteSentAt, quoteSentAt,
quoteAuthorUuid, quoteAuthorAci,
targetMessageId, targetMessageId,
} = options; } = options;
@ -559,7 +560,7 @@ function sendEditedMessage(
body: message, body: message,
bodyRanges, bodyRanges,
preview: getLinkPreviewForSend(message), preview: getLinkPreviewForSend(message),
quoteAuthorUuid, quoteAuthorAci,
quoteSentAt, quoteSentAt,
targetMessageId, targetMessageId,
}); });

View file

@ -219,7 +219,7 @@ export type DraftPreviewType = ReadonlyDeep<{
export type ConversationType = ReadonlyDeep< export type ConversationType = ReadonlyDeep<
{ {
id: string; id: string;
uuid?: ServiceIdString; serviceId?: ServiceIdString;
pni?: PniString; pni?: PniString;
e164?: string; e164?: string;
name?: string; name?: string;
@ -274,15 +274,15 @@ export type ConversationType = ReadonlyDeep<
announcementsOnlyReady?: boolean; announcementsOnlyReady?: boolean;
expireTimer?: DurationInSeconds; expireTimer?: DurationInSeconds;
memberships?: ReadonlyArray<{ memberships?: ReadonlyArray<{
uuid: AciString; aci: AciString;
isAdmin: boolean; isAdmin: boolean;
}>; }>;
pendingMemberships?: ReadonlyArray<{ pendingMemberships?: ReadonlyArray<{
uuid: ServiceIdString; serviceId: ServiceIdString;
addedByUserId?: AciString; addedByUserId?: AciString;
}>; }>;
pendingApprovalMemberships?: ReadonlyArray<{ pendingApprovalMemberships?: ReadonlyArray<{
uuid: AciString; aci: AciString;
}>; }>;
bannedMemberships?: ReadonlyArray<ServiceIdString>; bannedMemberships?: ReadonlyArray<ServiceIdString>;
muteExpiresAt?: number; muteExpiresAt?: number;
@ -474,7 +474,7 @@ export type ConversationsStateType = Readonly<{
invitedServiceIdsForNewlyCreatedGroup?: ReadonlyArray<ServiceIdString>; invitedServiceIdsForNewlyCreatedGroup?: ReadonlyArray<ServiceIdString>;
conversationLookup: ConversationLookupType; conversationLookup: ConversationLookupType;
conversationsByE164: ConversationLookupType; conversationsByE164: ConversationLookupType;
conversationsByUuid: ConversationLookupType; conversationsByServiceId: ConversationLookupType;
conversationsByGroupId: ConversationLookupType; conversationsByGroupId: ConversationLookupType;
conversationsByUsername: ConversationLookupType; conversationsByUsername: ConversationLookupType;
selectedConversationId?: string; selectedConversationId?: string;
@ -576,7 +576,7 @@ export type CancelVerificationDataByConversationActionType = ReadonlyDeep<{
type ClearGroupCreationErrorActionType = ReadonlyDeep<{ type ClearGroupCreationErrorActionType = ReadonlyDeep<{
type: 'CLEAR_GROUP_CREATION_ERROR'; type: 'CLEAR_GROUP_CREATION_ERROR';
}>; }>;
type ClearInvitedUuidsForNewlyCreatedGroupActionType = ReadonlyDeep<{ type ClearInvitedServiceIdsForNewlyCreatedGroupActionType = ReadonlyDeep<{
type: 'CLEAR_INVITED_SERVICE_IDS_FOR_NEWLY_CREATED_GROUP'; type: 'CLEAR_INVITED_SERVICE_IDS_FOR_NEWLY_CREATED_GROUP';
}>; }>;
type ClearVerificationDataByConversationActionType = ReadonlyDeep<{ type ClearVerificationDataByConversationActionType = ReadonlyDeep<{
@ -944,7 +944,7 @@ export type ConversationActionType =
| CancelVerificationDataByConversationActionType | CancelVerificationDataByConversationActionType
| ClearCancelledVerificationActionType | ClearCancelledVerificationActionType
| ClearGroupCreationErrorActionType | ClearGroupCreationErrorActionType
| ClearInvitedUuidsForNewlyCreatedGroupActionType | ClearInvitedServiceIdsForNewlyCreatedGroupActionType
| ClearTargetedMessageActionType | ClearTargetedMessageActionType
| ClearUnreadMetricsActionType | ClearUnreadMetricsActionType
| ClearVerificationDataByConversationActionType | ClearVerificationDataByConversationActionType
@ -1022,7 +1022,7 @@ export const actions = {
changeHasGroupLink, changeHasGroupLink,
clearCancelledConversationVerification, clearCancelledConversationVerification,
clearGroupCreationError, clearGroupCreationError,
clearInvitedUuidsForNewlyCreatedGroup, clearInvitedServiceIdsForNewlyCreatedGroup,
clearTargetedMessage, clearTargetedMessage,
clearUnreadMetrics, clearUnreadMetrics,
closeContactSpoofingReview, closeContactSpoofingReview,
@ -1863,7 +1863,11 @@ export const markViewed = (messageId: string): void => {
} }
const senderE164 = message.get('source'); const senderE164 = message.get('source');
const senderUuid = message.get('sourceUuid'); const senderAci = message.get('sourceServiceId');
strictAssert(
isAciString(senderAci),
'Message sourceServiceId must be an ACI'
);
const timestamp = getMessageSentTimestamp(message.attributes, { log }); const timestamp = getMessageSentTimestamp(message.attributes, { log });
message.set(messageUpdaterMarkViewed(message.attributes, Date.now())); message.set(messageUpdaterMarkViewed(message.attributes, Date.now()));
@ -1881,7 +1885,7 @@ export const markViewed = (messageId: string): void => {
messageId, messageId,
conversationId, conversationId,
senderE164, senderE164,
senderUuid, senderAci,
timestamp, timestamp,
isDirectConversation: convoAttributes isDirectConversation: convoAttributes
? isDirectConversation(convoAttributes) ? isDirectConversation(convoAttributes)
@ -1898,7 +1902,7 @@ export const markViewed = (messageId: string): void => {
{ {
messageId, messageId,
senderE164, senderE164,
senderUuid, senderAci,
timestamp, timestamp,
}, },
], ],
@ -2578,7 +2582,7 @@ function createGroup(
type: 'CREATE_GROUP_FULFILLED', type: 'CREATE_GROUP_FULFILLED',
payload: { payload: {
invitedServiceIds: (conversation.get('pendingMembersV2') || []).map( invitedServiceIds: (conversation.get('pendingMembersV2') || []).map(
member => member.uuid member => member.serviceId
), ),
}, },
}); });
@ -2706,11 +2710,11 @@ function conversationStoppedByMissingVerification(payload: {
untrustedServiceIds: ReadonlyArray<ServiceIdString>; untrustedServiceIds: ReadonlyArray<ServiceIdString>;
}): ConversationStoppedByMissingVerificationActionType { }): ConversationStoppedByMissingVerificationActionType {
// Fetching profiles to ensure that we have their latest identity key in storage // Fetching profiles to ensure that we have their latest identity key in storage
payload.untrustedServiceIds.forEach(uuid => { payload.untrustedServiceIds.forEach(serviceId => {
const conversation = window.ConversationController.get(uuid); const conversation = window.ConversationController.get(serviceId);
if (!conversation) { if (!conversation) {
log.error( log.error(
`conversationStoppedByMissingVerification: uuid ${uuid} not found!` `conversationStoppedByMissingVerification: serviceId ${serviceId} not found!`
); );
return; return;
} }
@ -3405,8 +3409,8 @@ function loadRecentMediaItems(
message: { message: {
attachments: message.attachments || [], attachments: message.attachments || [],
conversationId: conversationId:
window.ConversationController.get(message.sourceUuid)?.id || window.ConversationController.get(message.sourceServiceId)
message.conversationId, ?.id || message.conversationId,
id: message.id, id: message.id,
received_at: message.received_at, received_at: message.received_at,
received_at_ms: Number(message.received_at_ms), received_at_ms: Number(message.received_at_ms),
@ -3501,7 +3505,7 @@ export function saveAttachmentFromMessage(
}; };
} }
function clearInvitedUuidsForNewlyCreatedGroup(): ClearInvitedUuidsForNewlyCreatedGroupActionType { function clearInvitedServiceIdsForNewlyCreatedGroup(): ClearInvitedServiceIdsForNewlyCreatedGroupActionType {
return { type: 'CLEAR_INVITED_SERVICE_IDS_FOR_NEWLY_CREATED_GROUP' }; return { type: 'CLEAR_INVITED_SERVICE_IDS_FOR_NEWLY_CREATED_GROUP' };
} }
function clearGroupCreationError(): ClearGroupCreationErrorActionType { function clearGroupCreationError(): ClearGroupCreationErrorActionType {
@ -4130,7 +4134,7 @@ export function getEmptyState(): ConversationsStateType {
return { return {
conversationLookup: {}, conversationLookup: {},
conversationsByE164: {}, conversationsByE164: {},
conversationsByUuid: {}, conversationsByServiceId: {},
conversationsByGroupId: {}, conversationsByGroupId: {},
conversationsByUsername: {}, conversationsByUsername: {},
verificationDataByConversation: {}, verificationDataByConversation: {},
@ -4158,13 +4162,13 @@ export function updateConversationLookups(
): Pick< ): Pick<
ConversationsStateType, ConversationsStateType,
| 'conversationsByE164' | 'conversationsByE164'
| 'conversationsByUuid' | 'conversationsByServiceId'
| 'conversationsByGroupId' | 'conversationsByGroupId'
| 'conversationsByUsername' | 'conversationsByUsername'
> { > {
const result = { const result = {
conversationsByE164: state.conversationsByE164, conversationsByE164: state.conversationsByE164,
conversationsByUuid: state.conversationsByUuid, conversationsByServiceId: state.conversationsByServiceId,
conversationsByGroupId: state.conversationsByGroupId, conversationsByGroupId: state.conversationsByGroupId,
conversationsByUsername: state.conversationsByUsername, conversationsByUsername: state.conversationsByUsername,
}; };
@ -4172,11 +4176,17 @@ export function updateConversationLookups(
if (removed && removed.e164) { if (removed && removed.e164) {
result.conversationsByE164 = omit(result.conversationsByE164, removed.e164); result.conversationsByE164 = omit(result.conversationsByE164, removed.e164);
} }
if (removed && removed.uuid) { if (removed && removed.serviceId) {
result.conversationsByUuid = omit(result.conversationsByUuid, removed.uuid); result.conversationsByServiceId = omit(
result.conversationsByServiceId,
removed.serviceId
);
} }
if (removed && removed.pni) { if (removed && removed.pni) {
result.conversationsByUuid = omit(result.conversationsByUuid, removed.pni); result.conversationsByServiceId = omit(
result.conversationsByServiceId,
removed.pni
);
} }
if (removed && removed.groupId) { if (removed && removed.groupId) {
result.conversationsByGroupId = omit( result.conversationsByGroupId = omit(
@ -4197,15 +4207,15 @@ export function updateConversationLookups(
[added.e164]: added, [added.e164]: added,
}; };
} }
if (added && added.uuid) { if (added && added.serviceId) {
result.conversationsByUuid = { result.conversationsByServiceId = {
...result.conversationsByUuid, ...result.conversationsByServiceId,
[added.uuid]: added, [added.serviceId]: added,
}; };
} }
if (added && added.pni) { if (added && added.pni) {
result.conversationsByUuid = { result.conversationsByServiceId = {
...result.conversationsByUuid, ...result.conversationsByServiceId,
[added.pni]: added, [added.pni]: added,
}; };
} }
@ -4285,12 +4295,14 @@ function getVerificationDataForConversation({
}; };
} }
const existingUuids = distributionId const existingServiceIds = distributionId
? existing.byDistributionId?.[distributionId]?.serviceIdsNeedingVerification ? existing.byDistributionId?.[distributionId]?.serviceIdsNeedingVerification
: existing.serviceIdsNeedingVerification; : existing.serviceIdsNeedingVerification;
const serviceIdsNeedingVerification: ReadonlyArray<ServiceIdString> = const serviceIdsNeedingVerification: ReadonlyArray<ServiceIdString> =
Array.from(new Set([...(existingUuids || []), ...untrustedServiceIds])); Array.from(
new Set([...(existingServiceIds || []), ...untrustedServiceIds])
);
return { return {
[conversationId]: { [conversationId]: {
@ -4800,7 +4812,9 @@ export function reducer(
membersToRemove, membersToRemove,
membersToAdd, membersToAdd,
} = action.payload; } = action.payload;
const removedUuids = new Set(isBlockList ? membersToAdd : membersToRemove); const removedServiceIds = new Set(
isBlockList ? membersToAdd : membersToRemove
);
const nextVerificationData = visitListsInVerificationData( const nextVerificationData = visitListsInVerificationData(
state.verificationDataByConversation, state.verificationDataByConversation,
@ -4808,7 +4822,7 @@ export function reducer(
if (listId === id) { if (listId === id) {
const serviceIdsNeedingVerification = const serviceIdsNeedingVerification =
data.serviceIdsNeedingVerification.filter( data.serviceIdsNeedingVerification.filter(
uuid => !removedUuids.has(uuid) serviceId => !removedServiceIds.has(serviceId)
); );
if (!serviceIdsNeedingVerification.length) { if (!serviceIdsNeedingVerification.length) {
@ -4857,7 +4871,7 @@ export function reducer(
}; };
} }
if (action.type === HIDE_MY_STORIES_FROM) { if (action.type === HIDE_MY_STORIES_FROM) {
const removedUuids = new Set(action.payload); const removedServiceIds = new Set(action.payload);
const nextVerificationData = visitListsInVerificationData( const nextVerificationData = visitListsInVerificationData(
state.verificationDataByConversation, state.verificationDataByConversation,
@ -4865,7 +4879,7 @@ export function reducer(
if (MY_STORY_ID === id) { if (MY_STORY_ID === id) {
const serviceIdsNeedingVerification = const serviceIdsNeedingVerification =
data.serviceIdsNeedingVerification.filter( data.serviceIdsNeedingVerification.filter(
uuid => !removedUuids.has(uuid) serviceId => !removedServiceIds.has(serviceId)
); );
if (!serviceIdsNeedingVerification.length) { if (!serviceIdsNeedingVerification.length) {
@ -4893,15 +4907,15 @@ export function reducer(
} }
if (action.type === VIEWERS_CHANGED) { if (action.type === VIEWERS_CHANGED) {
const { listId, memberServiceIds } = action.payload; const { listId, memberServiceIds } = action.payload;
const newUuids = new Set(memberServiceIds); const newServiceIds = new Set(memberServiceIds);
const nextVerificationData = visitListsInVerificationData( const nextVerificationData = visitListsInVerificationData(
state.verificationDataByConversation, state.verificationDataByConversation,
(id, data): DistributionVerificationData | undefined => { (id, data): DistributionVerificationData | undefined => {
if (listId === id) { if (listId === id) {
const serviceIdsNeedingVerification = const serviceIdsNeedingVerification =
data.serviceIdsNeedingVerification.filter(uuid => data.serviceIdsNeedingVerification.filter(serviceId =>
newUuids.has(uuid) newServiceIds.has(serviceId)
); );
if (!serviceIdsNeedingVerification.length) { if (!serviceIdsNeedingVerification.length) {
@ -5928,7 +5942,7 @@ export function reducer(
if (!composer) { if (!composer) {
assertDev( assertDev(
false, false,
'Setting compose uuid fetch state with the composer closed is a no-op' 'Setting compose serviceId fetch state with the composer closed is a no-op'
); );
return state; return state;
} }
@ -5938,7 +5952,7 @@ export function reducer(
) { ) {
assertDev( assertDev(
false, false,
'Setting compose uuid fetch state at this step is a no-op' 'Setting compose serviceId fetch state at this step is a no-op'
); );
return state; return state;
} }

View file

@ -508,7 +508,7 @@ function showGV2MigrationDialog(
}); });
const invitedMemberIds = pendingMembersV2.map( const invitedMemberIds = pendingMembersV2.map(
(item: GroupV2PendingMemberType) => item.uuid (item: GroupV2PendingMemberType) => item.serviceId
); );
dispatch({ dispatch({

View file

@ -264,7 +264,7 @@ function showLightbox(opts: {
const authorId = const authorId =
window.ConversationController.lookupOrCreate({ window.ConversationController.lookupOrCreate({
uuid: message.get('sourceUuid'), serviceId: message.get('sourceServiceId'),
e164: message.get('source'), e164: message.get('source'),
reason: 'conversation_view.showLightBox', reason: 'conversation_view.showLightBox',
})?.id || message.get('conversationId'); })?.id || message.get('conversationId');

Some files were not shown because too many files have changed in this diff Show more