diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html index ce8fe08d0b..d9cd9e8843 100644 --- a/.storybook/preview-head.html +++ b/.storybook/preview-head.html @@ -56,7 +56,7 @@ }; window.ConversationController = window.ConversationController || {}; - window.ConversationController.isSignalConversation = () => false; + window.ConversationController.isSignalConversationId = () => false; window.ConversationController.onConvoMessageMount = noop; window.getPreferredSystemLocales = () => ['en']; window.getResolvedMessagesLocaleDirection = () => 'ltr'; diff --git a/package.json b/package.json index 84316073ce..cceb9715bc 100644 --- a/package.json +++ b/package.json @@ -92,8 +92,9 @@ "@react-aria/utils": "3.16.0", "@react-spring/web": "9.5.5", "@signalapp/better-sqlite3": "8.4.3", - "@signalapp/libsignal-client": "0.29.1", + "@signalapp/libsignal-client": "0.30.2", "@signalapp/ringrtc": "2.30.0", + "@signalapp/windows-dummy-keystroke": "1.0.0", "@types/fabric": "4.5.3", "backbone": "1.4.0", "blob-util": "2.0.2", @@ -180,7 +181,6 @@ "uuid": "3.3.2", "uuid-browser": "3.1.0", "websocket": "1.0.34", - "@signalapp/windows-dummy-keystroke": "1.0.0", "zod": "3.21.4" }, "devDependencies": { @@ -195,7 +195,7 @@ "@electron/fuses": "1.5.0", "@formatjs/intl": "2.6.7", "@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-actions": "6.5.6", "@storybook/addon-controls": "6.5.6", diff --git a/protos/Groups.proto b/protos/Groups.proto index c2acb6dec3..1101a238b5 100644 --- a/protos/Groups.proto +++ b/protos/Groups.proto @@ -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 repeated AddMemberAction addMembers = 3; // Members added repeated DeleteMemberAction deleteMembers = 4; // Members deleted diff --git a/protos/SignalStorage.proto b/protos/SignalStorage.proto index 155e0e108a..d130a181dc 100644 --- a/protos/SignalStorage.proto +++ b/protos/SignalStorage.proto @@ -136,7 +136,7 @@ message AccountRecord { message PinnedConversation { message Contact { - optional string uuid = 1; + optional string serviceId = 1; optional string e164 = 2; } diff --git a/ts/CI/benchmarkConversationOpen.ts b/ts/CI/benchmarkConversationOpen.ts index b620e62d90..e3f8aabcc0 100644 --- a/ts/CI/benchmarkConversationOpen.ts +++ b/ts/CI/benchmarkConversationOpen.ts @@ -70,7 +70,9 @@ export async function populateConversationWithMessages({ schemaVersion: window.Signal.Types.Message.CURRENT_SCHEMA_VERSION, received_at: incrementMessageCounter(), readStatus: isUnread ? ReadStatus.Unread : ReadStatus.Read, - sourceUuid: isIncoming ? conversation.getCheckedServiceId('CI') : ourAci, + sourceServiceId: isIncoming + ? conversation.getCheckedServiceId('CI') + : ourAci, ...(isIncoming ? {} : { diff --git a/ts/ConversationController.ts b/ts/ConversationController.ts index ad8117226c..1c44e8e040 100644 --- a/ts/ConversationController.ts +++ b/ts/ConversationController.ts @@ -22,11 +22,12 @@ import { maybeDeriveGroupV2Id } from './groups'; import { assertDev, strictAssert } from './util/assert'; import { drop } from './util/drop'; import { isGroupV1, isGroupV2 } from './util/whatTypeOfConversation'; -import type { ServiceIdString } from './types/ServiceId'; +import type { ServiceIdString, AciString, PniString } from './types/ServiceId'; import { isServiceIdString, normalizeAci, normalizePni, + normalizeServiceId, } from './types/ServiceId'; import { sleep } from './util/sleep'; import { isNotNil } from './util/isNotNil'; @@ -40,7 +41,7 @@ import { countAllConversationsUnreadStats } from './util/countUnreadStats'; type ConvoMatchType = | { - key: 'uuid' | 'pni'; + key: 'serviceId' | 'pni'; value: ServiceIdString | undefined; match: ConversationModel | undefined; } @@ -55,7 +56,7 @@ const { hasOwnProperty } = Object.prototype; function applyChangeToConversation( conversation: ConversationModel, suggestedChange: Partial< - Pick + Pick > ) { const change = { ...suggestedChange }; @@ -65,29 +66,29 @@ function applyChangeToConversation( change.pni = undefined; } - // If we have a PNI but not an ACI, then the PNI will go in the UUID field - // Tricky: We need a special check here, because the PNI can be in the uuid slot + // 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 serviceId slot if ( change.pni && - !change.uuid && - (!conversation.get('uuid') || - conversation.get('uuid') === conversation.get('pni')) + !change.serviceId && + (!conversation.getServiceId() || + 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 ( - !change.uuid && + !change.serviceId && hasOwnProperty.call(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')) { - conversation.updateUuid(change.uuid); + if (hasOwnProperty.call(change, 'serviceId')) { + conversation.updateServiceId(change.serviceId); } if (hasOwnProperty.call(change, 'e164')) { conversation.updateE164(change.e164); @@ -289,7 +290,7 @@ export class ConversationController { if (type === 'group') { conversation = this._conversations.add({ id, - uuid: undefined, + serviceId: undefined, e164: undefined, groupId: identifier, type, @@ -299,7 +300,7 @@ export class ConversationController { } else if (isServiceIdString(identifier)) { conversation = this._conversations.add({ id, - uuid: identifier, + serviceId: identifier, e164: undefined, groupId: undefined, type, @@ -309,7 +310,7 @@ export class ConversationController { } else { conversation = this._conversations.add({ id, - uuid: undefined, + serviceId: undefined, e164: identifier, groupId: undefined, type, @@ -455,12 +456,8 @@ export class ConversationController { return conversation; } - isSignalConversation(uuidOrId: string): boolean { - if (uuidOrId === SIGNAL_ACI) { - return true; - } - - return this._signalConversationId === uuidOrId; + isSignalConversationId(conversationId: string): boolean { + return this._signalConversationId === conversationId; } areWePrimaryDevice(): boolean { @@ -469,7 +466,7 @@ export class ConversationController { 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({ aci: providedAci, e164, @@ -478,9 +475,9 @@ export class ConversationController { fromPniSignature, mergeOldAndNew = safeCombineConversations, }: { - aci?: string; + aci?: AciString; e164?: string; - pni?: string; + pni?: PniString; reason: string; fromPniSignature?: boolean; mergeOldAndNew?: (options: SafeCombineConversationsParams) => Promise; @@ -500,10 +497,9 @@ export class ConversationController { } const logId = `maybeMergeContacts/${reason}/${dataProvided.join(',')}`; - const aci = - providedAci && providedAci !== providedPni - ? normalizeAci(providedAci, 'maybeMergeContacts.aci') - : undefined; + const aci = providedAci + ? normalizeAci(providedAci, 'maybeMergeContacts.aci') + : undefined; const pni = providedPni ? normalizePni(providedPni, 'maybeMergeContacts.pni') : undefined; @@ -517,7 +513,7 @@ export class ConversationController { const matches: Array = [ { - key: 'uuid', + key: 'serviceId', value: aci, match: window.ConversationController.get(aci), }, @@ -568,26 +564,26 @@ export class ConversationController { ); 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 ( !targetConversation && - unused.key === 'uuid' && + unused.key === 'serviceId' && match.get(unused.key) === pni ) { 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()}` ); 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 ( !targetConversation && - unused.key === 'uuid' && - match.get(unused.key) === match.get('pni') + unused.key === 'serviceId' && + match.get(unused.key) === match.getPni() ) { 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()}` ); targetConversation = match; @@ -640,20 +636,21 @@ export class ConversationController { ); const change: Pick< Partial, - 'uuid' | 'e164' | 'pni' + 'serviceId' | 'e164' | 'pni' > = { [key]: undefined, }; - // When the PNI is being used in the uuid field alone, we need to clear it - if ((key === 'pni' || key === 'e164') && match.get('uuid') === pni) { - change.uuid = undefined; + // When the PNI is being used in the serviceId field alone, we need to clear it + if ((key === 'pni' || key === 'e164') && match.getServiceId() === pni) { + change.serviceId = undefined; } applyChangeToConversation(match, change); - // Note: The PNI check here is just to be bulletproof; if we know a UUID is a PNI, - // then that should be put in the UUID field as well! + // Note: The PNI check here is just to be bulletproof; if we know a + // serviceId is a PNI, then that should be put in the serviceId field + // as well! const willMerge = - !match.get('uuid') && !match.get('e164') && !match.get('pni'); + !match.getServiceId() && !match.get('e164') && !match.getPni(); applyChangeToConversation(targetConversation, { [key]: value, @@ -705,7 +702,7 @@ export class ConversationController { 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 - // uuid slot if we have no ACI. + // serviceId slot if we have no ACI. const identifier = aci || pni || e164; 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; * otherwise will return whatever is found. */ lookupOrCreate({ e164, - uuid, + serviceId, reason, }: { e164?: string | null; - uuid?: string | null; + serviceId?: ServiceIdString | null; reason: string; }): ConversationModel | undefined { - const normalizedUuid = uuid ? uuid.toLowerCase() : undefined; - const identifier = normalizedUuid || e164; + const normalizedServiceId = serviceId + ? normalizeServiceId(serviceId, 'ConversationController.lookupOrCreate') + : undefined; + const identifier = normalizedServiceId || e164; - if ((!e164 && !uuid) || !identifier) { + if ((!e164 && !serviceId) || !identifier) { log.warn( - `lookupOrCreate: Called with neither e164 nor uuid! reason: ${reason}` + `lookupOrCreate: Called with neither e164 nor serviceId! reason: ${reason}` ); return undefined; } const convoE164 = this.get(e164); - const convoUuid = this.get(normalizedUuid); + const convoServiceId = this.get(normalizedServiceId); // 1. Handle no match at all - if (!convoE164 && !convoUuid) { + if (!convoE164 && !convoServiceId) { log.info('lookupOrCreate: Creating new contact, no matches found'); const newConvo = this.getOrCreate(identifier, 'private'); - // `identifier` would resolve to uuid if we had both, so fix up e164 - if (normalizedUuid && e164) { + // `identifier` would resolve to serviceId if we had both, so fix up e164 + if (normalizedServiceId && e164) { newConvo.updateE164(e164); } return newConvo; } - // 2. Handle match on only UUID - if (!convoE164 && convoUuid) { - return convoUuid; + // 2. Handle match on only service id + if (!convoE164 && convoServiceId) { + return convoServiceId; } // 3. Handle match on only E164 - if (convoE164 && !convoUuid) { + if (convoE164 && !convoServiceId) { return convoE164; } // 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. - if (!convoE164 || !convoUuid) { + if (!convoE164 || !convoServiceId) { 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 - if (convoE164 === convoUuid) { - return convoUuid; + if (convoE164 === convoServiceId) { + 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( - `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 { @@ -795,7 +794,7 @@ export class ConversationController { // run on `_combineConversationsQueue` queue and we don't want deadlocks. private async doCheckForConflicts(): Promise { log.info('checkForConflicts: starting...'); - const byUuid = Object.create(null); + const byServiceId = Object.create(null); const byE164 = Object.create(null); const byGroupV2Id = Object.create(null); // 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' ); - const uuid = conversation.get('uuid'); - const pni = conversation.get('pni'); + const serviceId = conversation.getServiceId(); + const pni = conversation.getPni(); const e164 = conversation.get('e164'); - if (uuid) { - const existing = byUuid[uuid]; + if (serviceId) { + const existing = byServiceId[serviceId]; if (!existing) { - byUuid[uuid] = conversation; + byServiceId[serviceId] = conversation; } 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 if (conversation.get('e164')) { @@ -831,7 +832,7 @@ export class ConversationController { current: conversation, obsolete: existing, }); - byUuid[uuid] = conversation; + byServiceId[serviceId] = conversation; } else { // Keep existing - note that this applies if neither had an e164 // eslint-disable-next-line no-await-in-loop @@ -844,28 +845,28 @@ export class ConversationController { } if (pni) { - const existing = byUuid[pni]; + const existing = byServiceId[pni]; if (!existing) { - byUuid[pni] = conversation; + byServiceId[pni] = 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. assertDev( - pni === uuid, - 'checkForConflicts: expected PNI to be equal to UUID' + pni === serviceId, + 'checkForConflicts: expected PNI to be equal to serviceId' ); } else { log.warn(`checkForConflicts: Found conflict with pni ${pni}`); // 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 // eslint-disable-next-line no-await-in-loop await this.doCombineConversations({ current: conversation, obsolete: existing, }); - byUuid[pni] = conversation; + byServiceId[pni] = conversation; } else { // Keep existing - note that this applies if neither had an e164 // eslint-disable-next-line no-await-in-loop @@ -882,15 +883,15 @@ export class ConversationController { if (!existing) { byE164[e164] = conversation; } else { - // If we have two contacts with the same e164 but different truthy UUIDs, then - // we'll delete the e164 on the older one + // If we have two contacts with the same e164 but different truthy + // service ids, then we'll delete the e164 on the older one if ( - conversation.get('uuid') && - existing.get('uuid') && - conversation.get('uuid') !== existing.get('uuid') + conversation.getServiceId() && + existing.getServiceId() && + conversation.getServiceId() !== existing.getServiceId() ) { 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 }); @@ -903,8 +904,8 @@ export class ConversationController { log.warn(`checkForConflicts: Found conflict with e164 ${e164}`); - // Keep the newer one if it has a UUID, otherwise keep existing - if (conversation.get('uuid')) { + // Keep the newer one if it has a service id, otherwise keep existing + if (conversation.getServiceId()) { // Keep new one // eslint-disable-next-line no-await-in-loop await this.doCombineConversations({ @@ -913,7 +914,7 @@ export class ConversationController { }); byE164[e164] = conversation; } 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 await this.doCombineConversations({ current: existing, @@ -1073,7 +1074,7 @@ export class ConversationController { } 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( obsoleteId ); @@ -1301,9 +1302,9 @@ export class ConversationController { async _forgetE164(e164: string): Promise { const { server } = window.textsecure; 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}`); @@ -1382,14 +1383,16 @@ export class ConversationController { 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 uuid = conversation.get('uuid'); - if (e164 && isServiceIdString(e164) && uuid) { + const serviceId = conversation.getServiceId(); + if (e164 && isServiceIdString(e164) && serviceId) { conversation.set({ e164: undefined }); updateConversation(conversation.attributes); - log.info(`Cleaning up conversation(${uuid}) with invalid e164`); + log.info( + `Cleaning up conversation(${serviceId}) with invalid e164` + ); } } catch (error) { log.error( diff --git a/ts/SignalProtocolStore.ts b/ts/SignalProtocolStore.ts index ad28044c83..8697ff048d 100644 --- a/ts/SignalProtocolStore.ts +++ b/ts/SignalProtocolStore.ts @@ -423,7 +423,8 @@ export class SignalProtocolStore extends EventEmitter { .map(item => item.fromDB) .filter( 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, isLastResort: key.isLastResort, keyId: key.keyId, - ourUuid: ourServiceId, + ourServiceId, }; toSave.push(kyberPreKey); @@ -589,7 +590,7 @@ export class SignalProtocolStore extends EventEmitter { const entries = Array.from(this.preKeys.values()); return entries .map(item => item.fromDB) - .filter(item => item.ourUuid === ourServiceId); + .filter(item => item.ourServiceId === ourServiceId); } async storePreKeys( @@ -613,7 +614,7 @@ export class SignalProtocolStore extends EventEmitter { const preKey = { id, keyId: key.keyId, - ourUuid: ourServiceId, + ourServiceId, publicKey: key.keyPair.pubKey, privateKey: key.keyPair.privKey, createdAt: now, @@ -705,7 +706,7 @@ export class SignalProtocolStore extends EventEmitter { const entries = Array.from(this.signedPreKeys.values()); return entries - .filter(({ fromDB }) => fromDB.ourUuid === ourServiceId) + .filter(({ fromDB }) => fromDB.ourServiceId === ourServiceId) .map(entry => { const preKey = entry.fromDB; return { @@ -760,7 +761,7 @@ export class SignalProtocolStore extends EventEmitter { const fromDB = { id, - ourUuid: ourServiceId, + ourServiceId, keyId, publicKey: keyPair.pubKey, privateKey: keyPair.privKey, @@ -1335,7 +1336,7 @@ export class SignalProtocolStore extends EventEmitter { throw new Error('_maybeMigrateSession: Unknown session version type!'); } - const ourServiceId = session.ourUuid; + const { ourServiceId } = session; const keyPair = this.getIdentityKeyPair(ourServiceId); if (!keyPair) { @@ -1384,7 +1385,7 @@ export class SignalProtocolStore extends EventEmitter { const { serviceId, deviceId } = qualifiedAddress; const conversation = window.ConversationController.lookupOrCreate({ - uuid: serviceId, + serviceId, reason: 'SignalProtocolStore.storeSession', }); strictAssert( @@ -1397,9 +1398,9 @@ export class SignalProtocolStore extends EventEmitter { const fromDB = { id, version: 2, - ourUuid: qualifiedAddress.ourServiceId, + ourServiceId: qualifiedAddress.ourServiceId, conversationId: conversation.id, - uuid: serviceId, + serviceId, deviceId, record: record.serialize().toString('base64'), }; @@ -1448,7 +1449,8 @@ export class SignalProtocolStore extends EventEmitter { const allSessions = this._getAllSessions(); const entries = allSessions.filter( ({ fromDB }) => - fromDB.ourUuid === ourServiceId && serviceIdSet.has(fromDB.uuid) + fromDB.ourServiceId === ourServiceId && + serviceIdSet.has(fromDB.serviceId) ); const openEntries: Array< | undefined @@ -1485,15 +1487,15 @@ export class SignalProtocolStore extends EventEmitter { } const { entry, record } = item; - const { uuid } = entry.fromDB; - serviceIdSet.delete(uuid); + const { serviceId } = entry.fromDB; + serviceIdSet.delete(serviceId); const id = entry.fromDB.deviceId; const registrationId = record.remoteRegistrationId(); return { - serviceId: uuid, + serviceId, id, registrationId, }; @@ -1601,7 +1603,7 @@ export class SignalProtocolStore extends EventEmitter { for (let i = 0, max = entries.length; i < max; i += 1) { const entry = entries[i]; - if (entry.fromDB.uuid === serviceId) { + if (entry.fromDB.serviceId === serviceId) { this.sessions.delete(entry.fromDB.id); this.pendingSessions.delete(entry.fromDB.id); } @@ -1675,7 +1677,8 @@ export class SignalProtocolStore extends EventEmitter { const allEntries = this._getAllSessions(); const entries = allEntries.filter( entry => - entry.fromDB.uuid === serviceId && entry.fromDB.deviceId !== deviceId + entry.fromDB.serviceId === serviceId && + entry.fromDB.deviceId !== deviceId ); await Promise.all( @@ -1696,7 +1699,7 @@ export class SignalProtocolStore extends EventEmitter { const allEntries = this._getAllSessions(); const entries = allEntries.filter( - entry => entry.fromDB.uuid === serviceId + entry => entry.fromDB.serviceId === serviceId ); await Promise.all( @@ -1743,7 +1746,7 @@ export class SignalProtocolStore extends EventEmitter { // First, fetch this conversation const conversation = window.ConversationController.lookupOrCreate({ - uuid: serviceId, + serviceId, reason: 'SignalProtocolStore.lightSessionReset', }); assertDev(conversation, `lightSessionReset/${id}: missing conversation`); @@ -2584,7 +2587,7 @@ export class SignalProtocolStore extends EventEmitter { isConfirmed: true, isLastResort: true, keyId: lastResortKyberPreKey.id(), - ourUuid: pni, + ourServiceId: pni, }, ]) : undefined, diff --git a/ts/background.ts b/ts/background.ts index 137118f0a9..2aee3b0345 100644 --- a/ts/background.ts +++ b/ts/background.ts @@ -1081,7 +1081,7 @@ export async function startApp(): Promise { `retryPlaceholders/interval: Found ${expired.length} expired items` ); expired.forEach(item => { - const { conversationId, senderUuid, sentAt } = item; + const { conversationId, senderAci, sentAt } = item; const conversation = window.ConversationController.get(conversationId); if (conversation) { @@ -1092,7 +1092,7 @@ export async function startApp(): Promise { conversation.addDeliveryIssue({ receivedAt, receivedAtCounter, - senderUuid, + senderAci, sentAt, }) ) @@ -2469,7 +2469,7 @@ export async function startApp(): Promise { remove: reaction.remove, source: ReactionSource.FromSomeoneElse, storyReactionMessage: message, - targetAuthorUuid: targetAuthorAci, + targetAuthorAci, targetTimestamp: reaction.targetTimestamp, timestamp, }; @@ -2679,7 +2679,7 @@ export async function startApp(): Promise { serverTimestamp: data.serverTimestamp, source: window.textsecure.storage.user.getNumber(), sourceDevice: data.device, - sourceUuid: window.textsecure.storage.user.getAci(), + sourceServiceId: window.textsecure.storage.user.getAci(), timestamp, type: data.message.isStory ? 'story' : 'outgoing', storyDistributionListId: data.storyDistributionListId, @@ -2755,8 +2755,8 @@ export async function startApp(): Promise { const { data, confirm } = event; const source = window.textsecure.storage.user.getNumber(); - const sourceUuid = window.textsecure.storage.user.getAci(); - strictAssert(source && sourceUuid, 'Missing user number and uuid'); + const sourceServiceId = window.textsecure.storage.user.getAci(); + strictAssert(source && sourceServiceId, 'Missing user number and uuid'); const messageDescriptor = getMessageDescriptor({ ...data, @@ -2804,7 +2804,7 @@ export async function startApp(): Promise { remove: reaction.remove, source: ReactionSource.FromSync, storyReactionMessage: message, - targetAuthorUuid: targetAuthorAci, + targetAuthorAci, targetTimestamp: reaction.targetTimestamp, timestamp, }; @@ -2900,7 +2900,7 @@ export async function startApp(): Promise { serverTimestamp: data.serverTimestamp, source: data.source, sourceDevice: data.sourceDevice, - sourceUuid: data.sourceAci, + sourceServiceId: data.sourceAci, timestamp: data.timestamp, type: data.message.isStory ? 'story' : 'incoming', unidentifiedDeliveryReceived: data.unidentifiedDeliveryReceived, @@ -3174,7 +3174,7 @@ export async function startApp(): Promise { wasSentEncrypted, } = event.receipt; const sourceConversation = window.ConversationController.lookupOrCreate({ - uuid: sourceServiceId, + serviceId: sourceServiceId, e164: source, reason: `onReadOrViewReceipt(${envelopeTimestamp})`, }); @@ -3305,7 +3305,7 @@ export async function startApp(): Promise { ev.confirm(); const sourceConversation = window.ConversationController.lookupOrCreate({ - uuid: sourceServiceId, + serviceId: sourceServiceId, e164: source, reason: `onDeliveryReceipt(${envelopeTimestamp})`, }); diff --git a/ts/components/AddUserToAnotherGroupModal.tsx b/ts/components/AddUserToAnotherGroupModal.tsx index 4468bf5787..bc929b133d 100644 --- a/ts/components/AddUserToAnotherGroupModal.tsx +++ b/ts/components/AddUserToAnotherGroupModal.tsx @@ -26,7 +26,7 @@ import { SizeObserver } from '../hooks/useSizeObserver'; type OwnProps = { i18n: LocalizerType; theme: ThemeType; - contact: Pick; + contact: Pick; candidateConversations: ReadonlyArray; regionCode: string | undefined; }; @@ -119,11 +119,12 @@ export function AddUserToAnotherGroupModal({ let disabledReason; - if (memberships.some(c => c.uuid === contact.uuid)) { + if (memberships.some(c => c.aci === contact.serviceId)) { disabledReason = DisabledReason.AlreadyMember; } else if ( - pendingApprovalMemberships.some(c => c.uuid === contact.uuid) || - pendingMemberships.some(c => c.uuid === contact.uuid) + pendingApprovalMemberships.some(c => c.aci === contact.serviceId) || + pendingMemberships.some(c => c.serviceId === contact.serviceId) || + pendingMemberships.some(c => c.serviceId === contact.pni) ) { disabledReason = DisabledReason.Pending; } diff --git a/ts/components/CallManager.stories.tsx b/ts/components/CallManager.stories.tsx index d7a77e5cac..4a176796a3 100644 --- a/ts/components/CallManager.stories.tsx +++ b/ts/components/CallManager.stories.tsx @@ -90,7 +90,7 @@ const createProps = (storyProps: Partial = {}): PropsType => ({ ), title: text('Caller Title', 'Morty Smith'), }), - uuid: generateAci(), + serviceId: generateAci(), }, notifyForCall: action('notify-for-call'), openSystemPreferencesAction: action('open-system-preferences-action'), diff --git a/ts/components/CallManager.tsx b/ts/components/CallManager.tsx index 0d94e6a377..6453eb7c9f 100644 --- a/ts/components/CallManager.tsx +++ b/ts/components/CallManager.tsx @@ -274,7 +274,7 @@ function ActiveCallManager({ ) : null} @@ -359,7 +359,7 @@ function ActiveCallManager({ ) : null} diff --git a/ts/components/CallScreen.stories.tsx b/ts/components/CallScreen.stories.tsx index c9a8fed3c0..d65c45c568 100644 --- a/ts/components/CallScreen.stories.tsx +++ b/ts/components/CallScreen.stories.tsx @@ -23,7 +23,7 @@ import { setupI18n } from '../util/setupI18n'; import { missingCaseError } from '../util/missingCaseError'; import { getDefaultConversation, - getDefaultConversationWithUuid, + getDefaultConversationWithServiceId, } from '../test-both/helpers/getDefaultConversation'; import { fakeGetGroupCallVideoFrameSource } from '../test-both/helpers/fakeGetGroupCallVideoFrameSource'; import enMessages from '../../_locales/en/messages.json'; @@ -175,7 +175,7 @@ const createProps = ( name: 'Morty Smith', profileName: 'Morty Smith', title: 'Morty Smith', - uuid: generateAci(), + serviceId: generateAci(), }), openSystemPreferencesAction: action('open-system-preferences-action'), setGroupCallVideoRequest: action('set-group-call-video-request'), @@ -312,7 +312,7 @@ export function GroupCall1(): JSX.Element { videoAspectRatio: 1.3, ...getDefaultConversation({ isBlocked: false, - uuid: generateAci(), + serviceId: generateAci(), title: 'Tyler', }), }, @@ -334,7 +334,7 @@ const allRemoteParticipants = times(MAX_PARTICIPANTS).map(index => ({ presenting: false, sharingScreen: false, videoAspectRatio: 1.3, - ...getDefaultConversationWithUuid({ + ...getDefaultConversationWithServiceId({ isBlocked: index === 10 || index === MAX_PARTICIPANTS - 1, title: `Participant ${index + 1}`, }), @@ -380,7 +380,7 @@ export function GroupCallReconnecting(): JSX.Element { ...getDefaultConversation({ isBlocked: false, title: 'Tyler', - uuid: generateAci(), + serviceId: generateAci(), }), }, ], diff --git a/ts/components/CallingLobby.stories.tsx b/ts/components/CallingLobby.stories.tsx index f844627bc7..645218b6d9 100644 --- a/ts/components/CallingLobby.stories.tsx +++ b/ts/components/CallingLobby.stories.tsx @@ -16,7 +16,7 @@ import { generateAci } from '../types/ServiceId'; import enMessages from '../../_locales/en/messages.json'; import { getDefaultConversation, - getDefaultConversationWithUuid, + getDefaultConversationWithServiceId, } from '../test-both/helpers/getDefaultConversation'; const i18n = setupI18n('en', enMessages); @@ -67,7 +67,7 @@ const createProps = (overrideProps: Partial = {}): PropsType => { getDefaultConversation({ color: AvatarColors[0], id: generateUuid(), - uuid: generateAci(), + serviceId: generateAci(), }), onCallCanceled: action('on-call-canceled'), onJoinCall: action('on-join-call'), @@ -87,7 +87,7 @@ const createProps = (overrideProps: Partial = {}): PropsType => { }; const fakePeekedParticipant = (conversationProps: Partial) => - getDefaultConversationWithUuid({ + getDefaultConversationWithServiceId({ ...conversationProps, }); @@ -118,7 +118,7 @@ export function NoCameraLocalAvatar(): JSX.Element { avatarPath: '/fixtures/kitten-4-112-112.jpg', color: AvatarColors[0], id: generateUuid(), - uuid: generateAci(), + serviceId: generateAci(), }), }); return ; @@ -168,14 +168,14 @@ GroupCall1PeekedParticipant.story = { }; export function GroupCall1PeekedParticipantSelf(): JSX.Element { - const uuid = generateAci(); + const serviceId = generateAci(); const props = createProps({ isGroupCall: true, me: getDefaultConversation({ id: generateUuid(), - uuid, + serviceId, }), - peekedParticipants: [fakePeekedParticipant({ title: 'Ash', uuid })], + peekedParticipants: [fakePeekedParticipant({ title: 'Ash', serviceId })], }); return ; } diff --git a/ts/components/CallingLobby.tsx b/ts/components/CallingLobby.tsx index 9b4f9b068f..48431b8639 100644 --- a/ts/components/CallingLobby.tsx +++ b/ts/components/CallingLobby.tsx @@ -49,7 +49,9 @@ export type PropsType = { isGroupCall: boolean; isGroupCallOutboundRingEnabled: boolean; isCallFull?: boolean; - me: Readonly>; + me: Readonly< + Pick + >; onCallCanceled: () => void; onJoinCall: () => void; outgoingRing: boolean; diff --git a/ts/components/CallingParticipantsList.stories.tsx b/ts/components/CallingParticipantsList.stories.tsx index 3477589b20..07cc512d26 100644 --- a/ts/components/CallingParticipantsList.stories.tsx +++ b/ts/components/CallingParticipantsList.stories.tsx @@ -9,7 +9,8 @@ import type { PropsType } from './CallingParticipantsList'; import { CallingParticipantsList } from './CallingParticipantsList'; import { AvatarColors } from '../types/Colors'; 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 enMessages from '../../_locales/en/messages.json'; @@ -25,7 +26,7 @@ function createParticipant( presenting: Boolean(participantProps.presenting), sharingScreen: Boolean(participantProps.sharingScreen), videoAspectRatio: 1.3, - ...getDefaultConversationWithUuid({ + ...getDefaultConversationWithServiceId({ avatarPath: participantProps.avatarPath, color: sample(AvatarColors), isBlocked: Boolean(participantProps.isBlocked), @@ -39,7 +40,7 @@ function createParticipant( const createProps = (overrideProps: Partial = {}): PropsType => ({ i18n, onClose: action('on-close'), - ourUuid: 'cf085e6a-e70b-41ec-a310-c198248af13f', + ourServiceId: generateAci(), participants: overrideProps.participants || [], }); diff --git a/ts/components/CallingParticipantsList.tsx b/ts/components/CallingParticipantsList.tsx index b44778198e..a575cb3ec9 100644 --- a/ts/components/CallingParticipantsList.tsx +++ b/ts/components/CallingParticipantsList.tsx @@ -11,6 +11,7 @@ import { Avatar, AvatarSize } from './Avatar'; import { ContactName } from './conversation/ContactName'; import { InContactsIcon } from './InContactsIcon'; import type { LocalizerType } from '../types/Util'; +import type { ServiceIdString } from '../types/ServiceId'; import { sortByTitle } from '../util/sortByTitle'; import type { ConversationType } from '../state/ducks/conversations'; import { isInSystemContacts } from '../util/isInSystemContacts'; @@ -25,7 +26,7 @@ type ParticipantType = ConversationType & { export type PropsType = { readonly i18n: LocalizerType; readonly onClose: () => void; - readonly ourUuid: string | undefined; + readonly ourServiceId: ServiceIdString | undefined; readonly participants: Array; }; @@ -33,7 +34,7 @@ export const CallingParticipantsList = React.memo( function CallingParticipantsListInner({ i18n, onClose, - ourUuid, + ourServiceId, participants, }: PropsType) { const [root, setRoot] = React.useState(null); @@ -101,9 +102,9 @@ export const CallingParticipantsList = React.memo( (participant: ParticipantType, index: number) => (
  • @@ -122,7 +123,8 @@ export const CallingParticipantsList = React.memo( sharedGroupNames={participant.sharedGroupNames} size={AvatarSize.THIRTY_TWO} /> - {ourUuid && participant.uuid === ourUuid ? ( + {ourServiceId && + participant.serviceId === ourServiceId ? ( {i18n('icu:you')} diff --git a/ts/components/CallingPreCallInfo.tsx b/ts/components/CallingPreCallInfo.tsx index 1dff078197..72992f33fd 100644 --- a/ts/components/CallingPreCallInfo.tsx +++ b/ts/components/CallingPreCallInfo.tsx @@ -30,14 +30,14 @@ type PropsType = { | 'unblurredAvatarPath' >; i18n: LocalizerType; - me: Pick; + me: Pick; ringMode: RingMode; // The following should only be set for group conversations. groupMembers?: Array>; isCallFull?: boolean; peekedParticipants?: Array< - Pick + Pick >; }; @@ -61,7 +61,7 @@ export function CallingPreCallInfo({ // device. let hasYou = false; const participantNames = peekedParticipants.map(participant => { - if (participant.uuid === me.uuid) { + if (participant.serviceId === me.serviceId) { hasYou = true; return i18n('icu:you'); } diff --git a/ts/components/CompositionArea.tsx b/ts/components/CompositionArea.tsx index 4127002a8a..1a7661fd36 100644 --- a/ts/components/CompositionArea.tsx +++ b/ts/components/CompositionArea.tsx @@ -36,6 +36,7 @@ import type { InMemoryAttachmentDraftType, } from '../types/Attachment'; import { isImageAttachment, isVoiceMessage } from '../types/Attachment'; +import type { AciString } from '../types/ServiceId'; import { AudioCapture } from './conversation/AudioCapture'; import { CompositionUpload } from './CompositionUpload'; import type { @@ -87,7 +88,6 @@ export type OwnProps = Readonly<{ conversationId: string; discardEditMessage: (id: string) => unknown; draftEditMessage?: DraftEditMessageType; - uuid?: string; draftAttachments: ReadonlyArray; errorDialogAudioRecorderType?: ErrorDialogAudioRecorderType; errorRecording: (e: ErrorDialogAudioRecorderType) => unknown; @@ -131,7 +131,7 @@ export type OwnProps = Readonly<{ options: { bodyRanges?: DraftBodyRanges; message?: string; - quoteAuthorUuid?: string; + quoteAuthorAci?: AciString; quoteSentAt?: number; targetMessageId: string; } @@ -153,7 +153,7 @@ export type OwnProps = Readonly<{ 'i18n' | 'onClick' | 'onClose' | 'withContentAbove' | 'isCompose' > >; - quotedMessageAuthorUuid?: string; + quotedMessageAuthorAci?: AciString; quotedMessageSentAt?: number; removeAttachment: (conversationId: string, filePath: string) => unknown; @@ -256,7 +256,7 @@ export function CompositionArea({ // Quote quotedMessageId, quotedMessageProps, - quotedMessageAuthorUuid, + quotedMessageAuthorAci, quotedMessageSentAt, scrollToMessage, // MediaQualitySelector @@ -356,7 +356,7 @@ export function CompositionArea({ message, // sent timestamp for the quote quoteSentAt: quotedMessageSentAt, - quoteAuthorUuid: quotedMessageAuthorUuid, + quoteAuthorAci: quotedMessageAuthorAci, targetMessageId: editedMessageId, }); } else { @@ -374,7 +374,7 @@ export function CompositionArea({ draftAttachments, editedMessageId, quotedMessageSentAt, - quotedMessageAuthorUuid, + quotedMessageAuthorAci, sendEditedMessage, sendMultiMediaMessage, setLarge, diff --git a/ts/components/CompositionInput.stories.tsx b/ts/components/CompositionInput.stories.tsx index 9833cbfa3d..e9b57d1dc0 100644 --- a/ts/components/CompositionInput.stories.tsx +++ b/ts/components/CompositionInput.stories.tsx @@ -138,7 +138,7 @@ export function Mentions(): JSX.Element { { start: 5, length: 1, - mentionUuid: generateAci(), + mentionAci: generateAci(), conversationID: 'k', replacementText: 'Kate Beaton', }, diff --git a/ts/components/CompositionInput.tsx b/ts/components/CompositionInput.tsx index 03cec3fc76..d41eb93b2d 100644 --- a/ts/components/CompositionInput.tsx +++ b/ts/components/CompositionInput.tsx @@ -26,7 +26,7 @@ import { BodyRange, collapseRangeTree, insertRange } from '../types/BodyRange'; import type { LocalizerType, ThemeType } from '../types/Util'; import type { ConversationType } from '../state/ducks/conversations'; import type { PreferredBadgeSelectorType } from '../state/selectors/badges'; -import { isServiceIdString } from '../types/ServiceId'; +import { isAciString } from '../types/ServiceId'; import { MentionBlot } from '../quill/mentions/blot'; import { matchEmojiImage, @@ -678,15 +678,12 @@ export function CompositionInput(props: Props): React.ReactElement { return; } - const currentMemberServiceIds = currentMembers - .map(m => m.uuid) + const currentMemberAcis = currentMembers + .map(m => m.serviceId) .filter(isNotNil) - .filter(isServiceIdString); + .filter(isAciString); - const newDelta = getDeltaToRemoveStaleMentions( - ops, - currentMemberServiceIds - ); + const newDelta = getDeltaToRemoveStaleMentions(ops, currentMemberAcis); // eslint-disable-next-line @typescript-eslint/no-explicit-any quill.updateContents(newDelta as any); diff --git a/ts/components/ConversationList.tsx b/ts/components/ConversationList.tsx index 29e6575488..7c9e658b12 100644 --- a/ts/components/ConversationList.tsx +++ b/ts/components/ConversationList.tsx @@ -374,7 +374,7 @@ export function ConversationList({ 'unblurredAvatarPath', 'unreadCount', 'unreadMentionsCount', - 'uuid', + 'serviceId', ]); const { badges, title, unreadCount, lastMessage } = itemProps; result = ( diff --git a/ts/components/GroupCallOverflowArea.stories.tsx b/ts/components/GroupCallOverflowArea.stories.tsx index 2640282eb0..79927e3a67 100644 --- a/ts/components/GroupCallOverflowArea.stories.tsx +++ b/ts/components/GroupCallOverflowArea.stories.tsx @@ -8,7 +8,7 @@ import { action } from '@storybook/addon-actions'; import { GroupCallOverflowArea } from './GroupCallOverflowArea'; 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 { FRAME_BUFFER_SIZE } from '../calling/constants'; import enMessages from '../../_locales/en/messages.json'; @@ -24,7 +24,7 @@ const allRemoteParticipants = times(MAX_PARTICIPANTS).map(index => ({ presenting: false, sharingScreen: false, videoAspectRatio: 1.3, - ...getDefaultConversationWithUuid({ + ...getDefaultConversationWithServiceId({ isBlocked: index === 10 || index === MAX_PARTICIPANTS - 1, title: `Participant ${index + 1}`, }), diff --git a/ts/components/GroupCallRemoteParticipant.stories.tsx b/ts/components/GroupCallRemoteParticipant.stories.tsx index 7114f28d67..1abd6b4621 100644 --- a/ts/components/GroupCallRemoteParticipant.stories.tsx +++ b/ts/components/GroupCallRemoteParticipant.stories.tsx @@ -61,7 +61,7 @@ const createProps = ( isBlocked: Boolean(isBlocked), title: '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, diff --git a/ts/components/SafetyNumberChangeDialog.tsx b/ts/components/SafetyNumberChangeDialog.tsx index 7df12edadc..0aa4410aa8 100644 --- a/ts/components/SafetyNumberChangeDialog.tsx +++ b/ts/components/SafetyNumberChangeDialog.tsx @@ -310,7 +310,9 @@ function ContactSection({ } 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 = distributionId === MY_STORY_ID ? i18n('icu:Stories__mine') @@ -322,17 +324,17 @@ function ContactSection({
    {sectionName}
    - {distributionId && removeFromStory && uuids.length > 1 && ( + {distributionId && removeFromStory && serviceIds.length > 1 && ( { - removeFromStory(distributionId, uuids); + removeFromStory(distributionId, serviceIds); }} /> )} @@ -443,7 +445,7 @@ function ContactRow({ shouldShowNumber: boolean; theme: ThemeType; }>) { - const { uuid } = contact; + const { serviceId } = contact; return (
  • @@ -493,14 +495,14 @@ function ContactRow({ ) : null} - {distributionId && removeFromStory && uuid ? ( + {distributionId && removeFromStory && serviceId ? ( removeFromStory(distributionId, [uuid])} + removeFromStory={() => removeFromStory(distributionId, [serviceId])} verifyContact={() => setSelectedContact(contact)} /> ) : ( diff --git a/ts/components/SendStoryModal.tsx b/ts/components/SendStoryModal.tsx index b89ca1b0b0..5f1eeccd13 100644 --- a/ts/components/SendStoryModal.tsx +++ b/ts/components/SendStoryModal.tsx @@ -59,7 +59,7 @@ export type PropsType = { onDeleteList: (listId: StoryDistributionIdString) => unknown; onDistributionListCreated: ( name: string, - viewerUuids: Array + viewerServiceIds: Array ) => Promise; onSelectedStoryList: (options: { conversationId: string; @@ -107,15 +107,15 @@ function getListMemberServiceIds( signalConnections: Array ): Array { const memberServiceIds = list.members - .map(({ uuid }) => uuid) + .map(({ serviceId }) => serviceId) .filter(isNotNil); if (list.id === MY_STORY_ID && list.isBlockList) { - const excludeUuids = new Set(memberServiceIds); + const excludeServiceIds = new Set(memberServiceIds); return signalConnections - .map(conversation => conversation.uuid) + .map(conversation => conversation.serviceId) .filter(isNotNil) - .filter(uuid => !excludeUuids.has(uuid)); + .filter(serviceId => !excludeServiceIds.has(serviceId)); } return memberServiceIds; @@ -242,7 +242,7 @@ export function SendStoryModal({ return distributionLists.find(list => list.id === 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 // to select the privacy settings. const ogMyStories = useMemo( @@ -310,18 +310,18 @@ export function SendStoryModal({