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.isSignalConversation = () => false;
window.ConversationController.isSignalConversationId = () => false;
window.ConversationController.onConvoMessageMount = noop;
window.getPreferredSystemLocales = () => ['en'];
window.getResolvedMessagesLocaleDirection = () => 'ltr';

View file

@ -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",

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
repeated AddMemberAction addMembers = 3; // Members added
repeated DeleteMemberAction deleteMembers = 4; // Members deleted

View file

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

View file

@ -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
? {}
: {

View file

@ -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<ConversationAttributesType, 'uuid' | 'e164' | 'pni'>
Pick<ConversationAttributesType, 'serviceId' | 'e164' | 'pni'>
>
) {
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<void>;
@ -500,8 +497,7 @@ export class ConversationController {
}
const logId = `maybeMergeContacts/${reason}/${dataProvided.join(',')}`;
const aci =
providedAci && providedAci !== providedPni
const aci = providedAci
? normalizeAci(providedAci, 'maybeMergeContacts.aci')
: undefined;
const pni = providedPni
@ -517,7 +513,7 @@ export class ConversationController {
const matches: Array<ConvoMatchType> = [
{
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<ConversationAttributesType>,
'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<void> {
@ -795,7 +794,7 @@ export class ConversationController {
// run on `_combineConversationsQueue` queue and we don't want deadlocks.
private async doCheckForConflicts(): Promise<void> {
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<void> {
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(

View file

@ -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,

View file

@ -1081,7 +1081,7 @@ export async function startApp(): Promise<void> {
`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<void> {
conversation.addDeliveryIssue({
receivedAt,
receivedAtCounter,
senderUuid,
senderAci,
sentAt,
})
)
@ -2469,7 +2469,7 @@ export async function startApp(): Promise<void> {
remove: reaction.remove,
source: ReactionSource.FromSomeoneElse,
storyReactionMessage: message,
targetAuthorUuid: targetAuthorAci,
targetAuthorAci,
targetTimestamp: reaction.targetTimestamp,
timestamp,
};
@ -2679,7 +2679,7 @@ export async function startApp(): Promise<void> {
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<void> {
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<void> {
remove: reaction.remove,
source: ReactionSource.FromSync,
storyReactionMessage: message,
targetAuthorUuid: targetAuthorAci,
targetAuthorAci,
targetTimestamp: reaction.targetTimestamp,
timestamp,
};
@ -2900,7 +2900,7 @@ export async function startApp(): Promise<void> {
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<void> {
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<void> {
ev.confirm();
const sourceConversation = window.ConversationController.lookupOrCreate({
uuid: sourceServiceId,
serviceId: sourceServiceId,
e164: source,
reason: `onDeliveryReceipt(${envelopeTimestamp})`,
});

View file

@ -26,7 +26,7 @@ import { SizeObserver } from '../hooks/useSizeObserver';
type OwnProps = {
i18n: LocalizerType;
theme: ThemeType;
contact: Pick<ConversationType, 'id' | 'title' | 'uuid'>;
contact: Pick<ConversationType, 'id' | 'title' | 'serviceId' | 'pni'>;
candidateConversations: ReadonlyArray<ConversationType>;
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;
}

View file

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

View file

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

View file

@ -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(),
}),
},
],

View file

@ -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> = {}): 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> = {}): PropsType => {
};
const fakePeekedParticipant = (conversationProps: Partial<ConversationType>) =>
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 <CallingLobby {...props} />;
@ -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 <CallingLobby {...props} />;
}

View file

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

View file

@ -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> = {}): PropsType => ({
i18n,
onClose: action('on-close'),
ourUuid: 'cf085e6a-e70b-41ec-a310-c198248af13f',
ourServiceId: generateAci(),
participants: overrideProps.participants || [],
});

View file

@ -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<ParticipantType>;
};
@ -33,7 +34,7 @@ export const CallingParticipantsList = React.memo(
function CallingParticipantsListInner({
i18n,
onClose,
ourUuid,
ourServiceId,
participants,
}: PropsType) {
const [root, setRoot] = React.useState<HTMLElement | null>(null);
@ -101,9 +102,9 @@ export const CallingParticipantsList = React.memo(
(participant: ParticipantType, index: number) => (
<li
className="module-calling-participants-list__contact"
// It's tempting to use `participant.uuid` as the `key` here, but that
// can result in duplicate keys for participants who have joined on
// multiple devices.
// It's tempting to use `participant.serviceId` as the `key`
// here, but that can result in duplicate keys for
// participants who have joined on multiple devices.
key={index}
>
<div>
@ -122,7 +123,8 @@ export const CallingParticipantsList = React.memo(
sharedGroupNames={participant.sharedGroupNames}
size={AvatarSize.THIRTY_TWO}
/>
{ourUuid && participant.uuid === ourUuid ? (
{ourServiceId &&
participant.serviceId === ourServiceId ? (
<span className="module-calling-participants-list__name">
{i18n('icu:you')}
</span>

View file

@ -30,14 +30,14 @@ type PropsType = {
| 'unblurredAvatarPath'
>;
i18n: LocalizerType;
me: Pick<ConversationType, 'id' | 'uuid'>;
me: Pick<ConversationType, 'id' | 'serviceId'>;
ringMode: RingMode;
// The following should only be set for group conversations.
groupMembers?: Array<Pick<ConversationType, 'id' | 'firstName' | 'title'>>;
isCallFull?: boolean;
peekedParticipants?: Array<
Pick<ConversationType, 'firstName' | 'title' | 'uuid'>
Pick<ConversationType, 'firstName' | 'title' | 'serviceId'>
>;
};
@ -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');
}

View file

@ -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<AttachmentDraftType>;
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,

View file

@ -138,7 +138,7 @@ export function Mentions(): JSX.Element {
{
start: 5,
length: 1,
mentionUuid: generateAci(),
mentionAci: generateAci(),
conversationID: 'k',
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 { 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);

View file

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

View file

@ -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}`,
}),

View file

@ -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,

View file

@ -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({
<div className="module-SafetyNumberChangeDialog__row__story-name">
{sectionName}
</div>
{distributionId && removeFromStory && uuids.length > 1 && (
{distributionId && removeFromStory && serviceIds.length > 1 && (
<SectionButtonWithMenu
ariaLabel={i18n('icu:safetyNumberChangeDialog__actions-story', {
story: sectionName,
})}
i18n={i18n}
memberCount={uuids.length}
memberCount={serviceIds.length}
storyName={sectionName}
theme={theme}
removeFromStory={() => {
removeFromStory(distributionId, uuids);
removeFromStory(distributionId, serviceIds);
}}
/>
)}
@ -443,7 +445,7 @@ function ContactRow({
shouldShowNumber: boolean;
theme: ThemeType;
}>) {
const { uuid } = contact;
const { serviceId } = contact;
return (
<li className="module-SafetyNumberChangeDialog__row" key={contact.id}>
@ -493,14 +495,14 @@ function ContactRow({
</div>
) : null}
</div>
{distributionId && removeFromStory && uuid ? (
{distributionId && removeFromStory && serviceId ? (
<RowButtonWithMenu
ariaLabel={i18n('icu:safetyNumberChangeDialog__actions-contact', {
contact: contact.title,
})}
i18n={i18n}
theme={theme}
removeFromStory={() => removeFromStory(distributionId, [uuid])}
removeFromStory={() => removeFromStory(distributionId, [serviceId])}
verifyContact={() => setSelectedContact(contact)}
/>
) : (

View file

@ -59,7 +59,7 @@ export type PropsType = {
onDeleteList: (listId: StoryDistributionIdString) => unknown;
onDistributionListCreated: (
name: string,
viewerUuids: Array<ServiceIdString>
viewerServiceIds: Array<ServiceIdString>
) => Promise<StoryDistributionIdString>;
onSelectedStoryList: (options: {
conversationId: string;
@ -107,15 +107,15 @@ function getListMemberServiceIds(
signalConnections: Array<ConversationType>
): Array<ServiceIdString> {
const memberServiceIds = list.members
.map(({ uuid }) => uuid)
.map(({ serviceId }) => serviceId)
.filter(isNotNil);
if (list.id === MY_STORY_ID && list.isBlockList) {
const excludeUuids = new Set<string>(memberServiceIds);
const excludeServiceIds = new Set<ServiceIdString>(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({
</Button>
<Button
onClick={() => {
const uuids = stagedMyStories.members
.map(convo => convo.uuid)
const serviceIds = stagedMyStories.members
.map(convo => convo.serviceId)
.filter(isNotNil);
if (stagedMyStories.isBlockList) {
if (stagedMyStories.members.length) {
onHideMyStoriesFrom(uuids);
onHideMyStoriesFrom(serviceIds);
} else {
setMyStoriesToAllSignalConnections();
}
} else {
onViewersUpdated(MY_STORY_ID, uuids);
onViewersUpdated(MY_STORY_ID, serviceIds);
}
setSelectedContacts([]);
@ -425,10 +425,10 @@ export function SendStoryModal({
candidateConversations={candidateConversations}
getPreferredBadge={getPreferredBadge}
i18n={i18n}
onCreateList={async (name, uuids) => {
onCreateList={async (name, serviceIds) => {
const newDistributionListId = await onDistributionListCreated(
name,
uuids
serviceIds
);
setSelectedContacts([]);
@ -438,19 +438,19 @@ export function SendStoryModal({
setPage(Page.SendStory);
}}
onViewersUpdated={uuids => {
onViewersUpdated={serviceIds => {
if (listIdToEdit && page === Page.AddViewer) {
onViewersUpdated(listIdToEdit, uuids);
onViewersUpdated(listIdToEdit, serviceIds);
setPage(Page.EditingDistributionList);
} else if (page === Page.ChooseViewers) {
setPage(Page.NameStory);
} else if (listIdToEdit && page === Page.HideStoryFrom) {
onHideMyStoriesFrom(uuids);
onHideMyStoriesFrom(serviceIds);
setPage(Page.SendStory);
} else if (page === Page.HideStoryFrom || page === Page.AddViewer) {
const uuidsSet = new Set(uuids);
const serviceIdSet = new Set(serviceIds);
const members = candidateConversations.filter(convo =>
convo.uuid ? uuidsSet.has(convo.uuid) : false
convo.serviceId ? serviceIdSet.has(convo.serviceId) : false
);
setStagedMyStories(myStories => ({
...myStories,
@ -800,7 +800,7 @@ export function SendStoryModal({
onSelectedStoryList({
conversationId: group.id,
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 },
toggleSignalConnectionsModal: { action: true },
setStoriesDisabled: { action: true },
getConversationByUuid: {
getConversationByServiceId: {
defaultValue: () => getDefaultGroup(),
},
},

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -292,7 +292,8 @@ function getConfirmationMessage({
}
const inviter = members.find(
({ uuid }) => uuid === firstPendingMembership.metadata.addedByUserId
({ serviceId }) =>
serviceId === firstPendingMembership.metadata.addedByUserId
);
if (inviter === undefined) {
@ -412,13 +413,16 @@ function MembersPendingProfileKey({
groupedPendingMemberships;
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)
.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 {
member,
pendingMemberships: otherPendingMembershipGroups[member.uuid],
pendingMemberships: otherPendingMembershipGroups[member.serviceId],
};
});

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

@ -5,6 +5,7 @@ import { assertDev } from '../../util/assert';
import { isDirectConversation } from '../../util/whatTypeOfConversation';
import * as log from '../../logging/log';
import type { ConversationAttributesType } from '../../model-types.d';
import { isAciString } from '../../types/ServiceId';
import type { reportSpamJobQueue } from '../reportSpamJobQueue';
export async function addReportSpamJob({
@ -13,7 +14,10 @@ export async function addReportSpamJob({
jobQueue,
}: Readonly<{
conversation: Readonly<
Pick<ConversationAttributesType, 'id' | 'type' | 'uuid' | 'reportingToken'>
Pick<
ConversationAttributesType,
'id' | 'type' | 'serviceId' | 'reportingToken'
>
>;
getMessageServerGuidsForSpam: (
conversationId: string
@ -25,10 +29,10 @@ export async function addReportSpamJob({
'addReportSpamJob: cannot report spam for non-direct conversations'
);
const { uuid } = conversation;
if (!uuid) {
const { serviceId: aci } = conversation;
if (!aci || !isAciString(aci)) {
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;
}
@ -44,5 +48,5 @@ export async function addReportSpamJob({
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,
destinationServiceId,
storyMessageRecipients: updatedStoryRecipients?.map(
({ destinationUuid: legacyDestinationUuid, ...rest }) => {
({ destinationServiceId: legacyDestinationUuid, ...rest }) => {
return {
// The field was renamed.
legacyDestinationUuid,

View file

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

View file

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

View file

@ -26,7 +26,6 @@ import { drop } from '../../util/drop';
import { strictAssert } from '../../util/assert';
import type { DecryptionErrorEventData } from '../../textsecure/messageReceiverEvents';
import type { LoggerType } from '../../types/Logging';
import { isAciString } from '../../types/ServiceId';
import { startAutomaticSessionReset } from '../../util/handleRetry';
function failoverToLocalReset(
@ -49,9 +48,8 @@ export async function sendResendRequest(
timeRemaining,
log,
}: ConversationQueueJobBundle,
{ senderUuid: senderAci, ...restOfData }: ResendRequestJobData
{ senderAci, ...restOfData }: ResendRequestJobData
): Promise<void> {
strictAssert(isAciString(senderAci), 'senderUuid is not an ACI');
const data = {
...restOfData,
senderAci,
@ -90,9 +88,8 @@ export async function sendResendRequest(
// 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.
const senderUuid = conversation.get('uuid');
if (!senderUuid) {
log.error('conversation was missing a uuid, cancelling job.');
if (conversation.getAci() !== senderAci) {
log.error('conversation was missing a aci, cancelling job.');
failoverToLocalReset(log, data);
return;
}
@ -113,7 +110,7 @@ export async function sendResendRequest(
await handleMessageSend(
messaging.sendMessageProtoAndWait({
timestamp,
recipients: [senderUuid],
recipients: [senderAci],
proto: plaintext,
contentHint: ContentHint.DEFAULT,
groupId,
@ -141,7 +138,7 @@ export async function sendResendRequest(
receivedAt: receivedAtDate,
receivedAtCounter,
sentAt: timestamp,
senderUuid,
senderAci,
wasOpened,
});
@ -162,7 +159,7 @@ export async function sendResendRequest(
await conversation.addDeliveryIssue({
receivedAt: receivedAtDate,
receivedAtCounter,
senderUuid,
senderAci,
sentAt: timestamp,
});
})

View file

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

View file

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

View file

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

View file

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

View file

@ -67,7 +67,7 @@ export class SingleProtoJobQueue extends JobQueue<SingleProtoJobData> {
const {
contentHint,
identifier,
serviceId,
isSyncMessage,
messageIds = [],
protoBase64,
@ -75,14 +75,12 @@ export class SingleProtoJobQueue extends JobQueue<SingleProtoJobData> {
urgent,
} = data;
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) {
throw new Error(
`Failed to get conversation for identifier ${identifier}`
);
throw new Error(`Failed to get conversation for serviceId ${serviceId}`);
}
if (!isConversationAccepted(conversation.attributes)) {
@ -103,13 +101,6 @@ export class SingleProtoJobQueue extends JobQueue<SingleProtoJobData> {
);
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 options = await getSendOptions(conversation.attributes, {

View file

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

View file

@ -23,7 +23,7 @@ import {
import type { DeleteSentProtoRecipientOptionsType } from '../sql/Interface';
import dataInterface from '../sql/Client';
import * as log from '../logging/log';
import { getSourceUuid } from '../messages/helpers';
import { getSourceServiceId } from '../messages/helpers';
import { queueUpdateMessage } from '../util/messageBatcher';
import { getMessageSentTimestamp } from '../util/getMessageSentTimestamp';
@ -61,8 +61,8 @@ const deleteSentProtoBatcher = createWaitBatcher({
items
);
for (const uuid of successfulPhoneNumberShares) {
const convo = window.ConversationController.get(uuid);
for (const serviceId of successfulPhoneNumberShares) {
const convo = window.ConversationController.get(serviceId);
if (!convo) {
continue;
}
@ -158,8 +158,8 @@ export class MessageReceipts extends Collection<MessageReceiptModel> {
}
const ourAci = window.textsecure.storage.user.getCheckedAci();
const sourceUuid = getSourceUuid(message.attributes);
if (ourAci !== sourceUuid) {
const sourceServiceId = getSourceServiceId(message.attributes);
if (ourAci !== sourceServiceId) {
return [];
}
@ -327,7 +327,7 @@ export class MessageReceipts extends Collection<MessageReceiptModel> {
]);
} else {
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')) {
const syncByUuid = this.findWhere({
threadAci: conversation.get('uuid'),
if (conversation.getServiceId()) {
const syncByAci = this.findWhere({
threadAci: conversation.getServiceId(),
});
if (syncByUuid) {
if (syncByAci) {
log.info(
`Found early message request response for UUID ${conversation.idForLogging()}`
`Found early message request response for aci ${conversation.idForLogging()}`
);
this.remove(syncByUuid);
return syncByUuid;
this.remove(syncByAci);
return syncByAci;
}
}
@ -88,7 +88,7 @@ export class MessageRequests extends Collection<MessageRequestModel> {
if (!conversation && (threadE164 || threadAci)) {
conversation = window.ConversationController.lookupOrCreate({
e164: threadE164,
uuid: threadAci,
serviceId: threadAci,
reason: 'MessageRequests.onResponse',
});
}

View file

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

View file

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

View file

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

View file

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

View file

@ -111,16 +111,16 @@ export function getPaymentEventDescription(
export function isQuoteAMatch(
message: MessageAttributesType | null | undefined,
conversationId: string,
quote: Pick<QuotedMessageType, 'id' | 'authorUuid' | 'author'>
quote: Pick<QuotedMessageType, 'id' | 'authorAci' | 'author'>
): message is MessageAttributesType {
if (!message) {
return false;
}
const { authorUuid, id } = quote;
const { authorAci, id } = quote;
const authorConversation = window.ConversationController.lookupOrCreate({
e164: 'author' in quote ? quote.author : undefined,
uuid: authorUuid,
serviceId: authorAci,
reason: 'helpers.isQuoteAMatch',
});
@ -137,18 +137,18 @@ export function isQuoteAMatch(
}
export function getContactId(
message: Pick<MessageAttributesType, 'type' | 'source' | 'sourceUuid'>
message: Pick<MessageAttributesType, 'type' | 'source' | 'sourceServiceId'>
): string | undefined {
const source = getSource(message);
const sourceUuid = getSourceUuid(message);
const sourceServiceId = getSourceServiceId(message);
if (!source && !sourceUuid) {
if (!source && !sourceServiceId) {
return window.ConversationController.getOurConversationId();
}
const conversation = window.ConversationController.lookupOrCreate({
e164: source,
uuid: sourceUuid,
serviceId: sourceServiceId,
reason: 'helpers.getContactId',
});
return conversation?.id;
@ -191,15 +191,15 @@ export function getSourceDevice(
return sourceDevice || window.textsecure.storage.user.getDeviceId();
}
export function getSourceUuid(
message: Pick<MessageAttributesType, 'type' | 'sourceUuid'>
export function getSourceServiceId(
message: Pick<MessageAttributesType, 'type' | 'sourceServiceId'>
): ServiceIdString | undefined {
if (isIncoming(message) || isStory(message)) {
return message.sourceUuid;
return message.sourceServiceId;
}
if (!isOutgoing(message)) {
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 = {
id: number;
identifier: string;
serviceId: ServiceIdString;
registrationId: number;
};
@ -69,7 +69,7 @@ export type CustomError = Error & {
export type GroupMigrationType = {
areWeInvited: boolean;
droppedMemberIds: Array<string>;
invitedMembers: Array<GroupV2PendingMemberType>;
invitedMembers: Array<LegacyMigrationPendingMemberType>;
};
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
// new messages, but old messages might have this attribute.
author?: string;
authorUuid?: string;
authorAci?: AciString;
bodyRanges?: ReadonlyArray<RawBodyRange>;
id: number;
isGiftBadge?: boolean;
@ -98,17 +98,10 @@ export type QuotedMessageType = {
type StoryReplyContextType = {
attachment?: AttachmentType;
authorUuid?: string;
authorAci?: AciString;
messageId: string;
};
export type RetryOptions = Readonly<{
type: 'session-reset';
uuid: string;
e164: string;
now: number;
}>;
export type GroupV1Update = {
avatarUpdated?: boolean;
joined?: Array<string>;
@ -119,7 +112,7 @@ export type GroupV1Update = {
export type MessageReactionType = {
emoji: undefined | string;
fromId: string;
targetAuthorUuid: AciString;
targetAuthorAci: AciString;
targetTimestamp: number;
timestamp: number;
isSentByConversationId?: Record<string, boolean>;
@ -169,7 +162,6 @@ export type MessageAttributesType = {
quote?: QuotedMessageType;
reactions?: ReadonlyArray<MessageReactionType>;
requiredProtocolVersion?: number;
retryOptions?: RetryOptions;
sourceDevice?: number;
storyDistributionListId?: StoryDistributionIdString;
storyId?: string;
@ -210,7 +202,7 @@ export type MessageAttributesType = {
conversationId: string;
storyReaction?: {
emoji: string;
targetAuthorUuid: AciString;
targetAuthorAci: AciString;
targetTimestamp: number;
};
giftBadge?: {
@ -225,7 +217,7 @@ export type MessageAttributesType = {
expireTimer?: DurationInSeconds;
fromSync?: unknown;
source?: string;
sourceUuid?: ServiceIdString;
sourceServiceId?: ServiceIdString;
};
conversationMerge?: {
renderInfo: ConversationRenderInfoType;
@ -249,12 +241,12 @@ export type MessageAttributesType = {
serverGuid?: string;
serverTimestamp?: number;
source?: string;
sourceUuid?: ServiceIdString;
sourceServiceId?: ServiceIdString;
timestamp: number;
// Backwards-compatibility with prerelease data schema
invitedGV2Members?: Array<GroupV2PendingMemberType>;
invitedGV2Members?: Array<LegacyMigrationPendingMemberType>;
droppedGV2MemberIds?: Array<string>;
sendHQImages?: boolean;
@ -283,7 +275,7 @@ export type ConversationLastProfileType = Readonly<{
export type ValidateConversationType = Pick<
ConversationAttributesType,
'e164' | 'uuid' | 'type' | 'groupId'
'e164' | 'serviceId' | 'type' | 'groupId'
>;
export type DraftEditMessageType = {
@ -378,7 +370,7 @@ export type ConversationAttributesType = {
version: number;
// Private core info
uuid?: ServiceIdString;
serviceId?: ServiceIdString;
pni?: PniString;
e164?: string;
@ -470,7 +462,7 @@ export type ConversationRenderInfoType = Pick<
>;
export type GroupV2MemberType = {
uuid: AciString;
aci: AciString;
role: MemberRoleEnum;
joinedAtVersion: number;
@ -481,20 +473,27 @@ export type GroupV2MemberType = {
approvedByAdmin?: boolean;
};
export type LegacyMigrationPendingMemberType = {
addedByUserId?: string;
uuid: string;
timestamp: number;
role: MemberRoleEnum;
};
export type GroupV2PendingMemberType = {
addedByUserId?: AciString;
uuid: ServiceIdString;
serviceId: ServiceIdString;
timestamp: number;
role: MemberRoleEnum;
};
export type GroupV2BannedMemberType = {
uuid: ServiceIdString;
serviceId: ServiceIdString;
timestamp: number;
};
export type GroupV2PendingAdminApprovalType = {
uuid: AciString;
aci: AciString;
timestamp: number;
};
@ -517,7 +516,7 @@ export type ReactionAttributesType = {
// Necessary to put 1:1 story replies into the right conversation - not the same
// conversation as the target message!
storyReactionMessage?: MessageModel;
targetAuthorUuid: AciString;
targetAuthorAci: AciString;
targetTimestamp: number;
timestamp: number;
};

View file

@ -82,7 +82,6 @@ import type { DraftBodyRanges } from '../types/BodyRange';
import { BodyRange } from '../types/BodyRange';
import { migrateColor } from '../util/migrateColor';
import { isNotNil } from '../util/isNotNil';
import { resolveSenderKeyDevice } from '../util/resolveSenderKeyDevice';
import {
NotificationType,
notificationService,
@ -304,15 +303,16 @@ export class ConversationModel extends window.Backbone
// Note that we intentionally don't use `initialize()` method because it
// isn't compatible with esnext output of esbuild.
const uuid = this.get('uuid');
const serviceId = this.getServiceId();
const normalizedServiceId =
uuid && normalizeServiceId(uuid, 'ConversationModel.initialize');
if (uuid && normalizedServiceId !== uuid) {
serviceId &&
normalizeServiceId(serviceId, 'ConversationModel.initialize');
if (serviceId && normalizedServiceId !== serviceId) {
log.warn(
'ConversationModel.initialize: normalizing serviceId from ' +
`${uuid} to ${normalizedServiceId}`
`${serviceId} to ${normalizedServiceId}`
);
this.set('uuid', normalizedServiceId);
this.set('serviceId', normalizedServiceId);
}
if (isValidE164(attributes.id, false)) {
@ -805,8 +805,8 @@ export class ConversationModel extends window.Backbone
}
const e164 = this.get('e164');
const pni = this.get('pni');
const aci = this.get('uuid');
const pni = this.getPni();
const aci = this.getServiceId();
if (e164 && pni && aci && pni !== aci) {
this.updateE164(undefined);
this.updatePni(undefined);
@ -878,9 +878,9 @@ export class ConversationModel extends window.Backbone
let blocked = false;
const wasBlocked = this.isBlocked();
const uuid = this.get('uuid');
if (uuid) {
drop(window.storage.blocked.addBlockedUuid(uuid));
const serviceId = this.getServiceId();
if (serviceId) {
drop(window.storage.blocked.addBlockedServiceId(serviceId));
blocked = true;
}
@ -910,9 +910,9 @@ export class ConversationModel extends window.Backbone
let unblocked = false;
const wasBlocked = this.isBlocked();
const uuid = this.get('uuid');
if (uuid) {
drop(window.storage.blocked.removeBlockedUuid(uuid));
const serviceId = this.getServiceId();
if (serviceId) {
drop(window.storage.blocked.removeBlockedServiceId(serviceId));
unblocked = true;
}
@ -977,10 +977,10 @@ export class ConversationModel extends window.Backbone
});
window.reduxActions?.stories.removeAllContactStories(this.id);
const uuid = this.get('uuid');
if (uuid) {
const serviceId = this.getServiceId();
if (serviceId) {
window.reduxActions?.storyDistributionLists.removeMemberFromAllDistributionLists(
uuid
serviceId
);
}
@ -1162,7 +1162,7 @@ export class ConversationModel extends window.Backbone
);
}
if (!this.get('uuid')) {
if (!this.getServiceId()) {
return;
}
@ -1353,12 +1353,12 @@ export class ConversationModel extends window.Backbone
}
async onNewMessage(message: MessageModel): Promise<void> {
const uuid = message.get('sourceUuid');
const serviceId = message.get('sourceServiceId');
const e164 = message.get('source');
const sourceDevice = message.get('sourceDevice');
const source = window.ConversationController.lookupOrCreate({
uuid,
serviceId,
e164,
reason: 'ConversationModel.onNewMessage',
});
@ -1855,27 +1855,29 @@ export class ConversationModel extends window.Backbone
this.captureChange('updateE164');
}
updateUuid(uuid?: ServiceIdString): void {
const oldValue = this.get('uuid');
if (uuid === oldValue) {
updateServiceId(serviceId?: ServiceIdString): void {
const oldValue = this.getServiceId();
if (serviceId === oldValue) {
return;
}
this.set(
'uuid',
uuid ? normalizeServiceId(uuid, 'Conversation.updateUuid') : undefined
'serviceId',
serviceId
? normalizeServiceId(serviceId, 'Conversation.updateServiceId')
: undefined
);
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
// for the case where we need to do old and new PNI comparisons. We'll wait
// 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));
}
this.captureChange('updateUuid');
this.captureChange('updateServiceId');
}
trackPreviousIdentityKey(publicKey: Uint8Array): void {
@ -1902,7 +1904,7 @@ export class ConversationModel extends window.Backbone
}
updatePni(pni?: PniString): void {
const oldValue = this.get('pni');
const oldValue = this.getPni();
if (pni === oldValue) {
return;
}
@ -1913,9 +1915,9 @@ export class ConversationModel extends window.Backbone
);
const pniIsPrimaryId =
!this.get('uuid') ||
this.get('uuid') === oldValue ||
this.get('uuid') === pni;
!this.getServiceId() ||
this.getServiceId() === oldValue ||
this.getServiceId() === pni;
const haveSentMessage = Boolean(
this.get('profileSharing') || this.get('sentMessageCount')
);
@ -1958,9 +1960,9 @@ export class ConversationModel extends window.Backbone
drop(window.textsecure.storage.protocol.removeIdentityKey(oldValue));
}
if (pni && !this.get('uuid')) {
if (pni && !this.getServiceId()) {
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,
conversationId: this.get('id'),
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,
conversationId,
senderE164: m.source,
senderUuid: m.sourceUuid,
senderAci,
timestamp: getMessageSentTimestamp(m, { log }),
isDirectConversation: isDirectConversation(this.attributes),
})),
};
}),
});
}
@ -2266,7 +2273,7 @@ export class ConversationModel extends window.Backbone
this.set({
pendingAdminApprovalV2: [
{
uuid: ourAci,
aci: ourAci,
timestamp: Date.now(),
},
],
@ -2828,23 +2835,23 @@ export class ConversationModel extends window.Backbone
async addDeliveryIssue({
receivedAt,
receivedAtCounter,
senderUuid,
senderAci,
sentAt,
}: {
receivedAt: number;
receivedAtCounter: number;
senderUuid: string;
senderAci: AciString;
sentAt: number;
}): Promise<void> {
log.info(`addDeliveryIssue: adding for ${this.idForLogging()}`, {
sentAt,
senderUuid,
senderAci,
});
const message = {
conversationId: this.id,
type: 'delivery-issue',
sourceUuid: senderUuid,
sourceServiceId: senderAci,
sent_at: receivedAt,
received_at: receivedAtCounter,
received_at_ms: receivedAt,
@ -2945,15 +2952,11 @@ export class ConversationModel extends window.Backbone
if (senderKeyInfo) {
const updatedSenderKeyInfo = {
...senderKeyInfo,
memberDevices: senderKeyInfo.memberDevices
.map(resolveSenderKeyDevice)
.filter(isNotNil)
.filter(({ serviceId: memberServiceId }) => {
memberDevices: senderKeyInfo.memberDevices.filter(
({ serviceId: memberServiceId }) => {
return memberServiceId !== keyChangedId;
})
.map(({ serviceId: memberServiceId, ...rest }) => {
return { identifier: memberServiceId, ...rest };
}),
}
),
};
this.set('senderKeyInfo', updatedSenderKeyInfo);
@ -3267,7 +3270,7 @@ export class ConversationModel extends window.Backbone
newValue: string
): Promise<void> {
const sourceServiceId = this.getCheckedServiceId(
'Change number notification without uuid'
'Change number notification without service id'
);
const { storage } = window.textsecure;
@ -3299,7 +3302,7 @@ export class ConversationModel extends window.Backbone
return convo.addNotification('change-number-notification', {
readStatus: ReadStatus.Read,
seenStatus: SeenStatus.Unseen,
sourceUuid: sourceServiceId,
sourceServiceId,
});
})
);
@ -3379,7 +3382,7 @@ export class ConversationModel extends window.Backbone
}
const members = this.get('membersV2') || [];
const member = members.find(x => x.uuid === serviceId);
const member = members.find(x => x.aci === serviceId);
if (!member) {
return false;
}
@ -3390,7 +3393,7 @@ export class ConversationModel extends window.Backbone
}
getServiceId(): ServiceIdString | undefined {
return this.get('uuid');
return this.get('serviceId');
}
getCheckedServiceId(reason: string): ServiceIdString {
@ -3400,7 +3403,7 @@ export class ConversationModel extends window.Backbone
}
getAci(): AciString | undefined {
const value = this.get('uuid');
const value = this.getServiceId();
if (value && isAciString(value)) {
return value;
}
@ -4483,7 +4486,7 @@ export class ConversationModel extends window.Backbone
await Promise.all(
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;
}
const uuid = this.get('uuid');
if (!uuid) {
const serviceId = this.getServiceId();
if (!serviceId) {
return;
}
@ -4663,7 +4666,7 @@ export class ConversationModel extends window.Backbone
return lastProfile.profileKeyVersion;
}
const profileKeyVersion = deriveProfileKeyVersion(profileKey, uuid);
const profileKeyVersion = deriveProfileKeyVersion(profileKey, serviceId);
if (!profileKeyVersion) {
log.warn(
'deriveProfileKeyVersion: Failed to derive profile key version, ' +
@ -4733,7 +4736,7 @@ export class ConversationModel extends window.Backbone
hasMember(serviceId: ServiceIdString): boolean {
const members = this.getMembers();
return members.some(member => member.get('uuid') === serviceId);
return members.some(member => member.getServiceId() === serviceId);
}
fetchContacts(): void {
@ -4818,7 +4821,7 @@ export class ConversationModel extends window.Backbone
}
// Set of items to captureChanges on:
// [-] uuid
// [-] serviceId
// [-] e164
// [X] profileKey
// [-] identityKey
@ -4912,14 +4915,14 @@ export class ConversationModel extends window.Backbone
const ourAci = window.textsecure.storage.user.getCheckedAci();
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 => {
if (!BodyRange.isMention(bodyRange)) {
return false;
}
return ourUuids.has(
normalizeServiceId(bodyRange.mentionUuid, 'notify: mentionsMe check')
return ourServiceIds.has(
normalizeServiceId(bodyRange.mentionAci, 'notify: mentionsMe check')
);
});
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`,
* `_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.
*/
initialize() {
@ -5294,8 +5297,8 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
if (idProp === 'e164') {
delete this._byE164[oldValue];
}
if (idProp === 'uuid') {
delete this._byUuid[oldValue];
if (idProp === 'serviceId') {
delete this._byServiceId[oldValue];
}
if (idProp === 'pni') {
delete this._byPni[oldValue];
@ -5308,11 +5311,11 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
if (e164) {
this._byE164[e164] = model;
}
const uuid = model.get('uuid');
if (uuid) {
this._byUuid[uuid] = model;
const serviceId = model.getServiceId();
if (serviceId) {
this._byServiceId[serviceId] = model;
}
const pni = model.get('pni');
const pni = model.getPni();
if (pni) {
this._byPni[pni] = model;
}
@ -5340,28 +5343,28 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
if (e164) {
const existing = this._byE164[e164];
// Prefer the contact with both e164 and uuid
if (!existing || (existing && !existing.get('uuid'))) {
// Prefer the contact with both e164 and serviceId
if (!existing || (existing && !existing.getServiceId())) {
this._byE164[e164] = model;
}
}
const uuid = model.get('uuid');
if (uuid) {
const existing = this._byUuid[uuid];
const serviceId = model.getServiceId();
if (serviceId) {
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'))) {
this._byUuid[uuid] = model;
this._byServiceId[serviceId] = model;
}
}
const pni = model.get('pni');
const pni = model.getPni();
if (pni) {
const existing = this._byPni[pni];
// Prefer the contact with both uuid and pni
if (!existing || (existing && !existing.get('uuid'))) {
// Prefer the contact with both serviceId and pni
if (!existing || (existing && !existing.getServiceId())) {
this._byPni[pni] = model;
}
}
@ -5375,7 +5378,7 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
eraseLookups() {
this._byE164 = Object.create(null);
this._byUuid = Object.create(null);
this._byServiceId = Object.create(null);
this._byPni = 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
* 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
* window.Backbone implementation.
*/
@ -5435,7 +5438,7 @@ window.Whisper.ConversationCollection = window.Backbone.Collection.extend({
return (
this._byE164[id] ||
this._byE164[`+${id}`] ||
this._byUuid[id] ||
this._byServiceId[id] ||
this._byPni[id] ||
this._byGroupId[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 { ServiceIdString } from '../types/ServiceId';
import { normalizeServiceId } from '../types/ServiceId';
import { isAciString, normalizeServiceId } from '../types/ServiceId';
import * as reactionUtil from '../reactions/util';
import * as Stickers from '../types/Stickers';
import * as Errors from '../types/errors';
@ -133,7 +133,7 @@ import { cleanupMessage, deleteMessageData } from '../util/cleanup';
import {
getContact,
getSource,
getSourceUuid,
getSourceServiceId,
isCustomError,
messageHasPaymentEvent,
isQuoteAMatch,
@ -294,13 +294,13 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
getSenderIdentifier(): string {
const sentAt = this.get('sent_at');
const source = this.get('source');
const sourceUuid = this.get('sourceUuid');
const sourceServiceId = this.get('sourceServiceId');
const sourceDevice = this.get('sourceDevice');
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const conversation = window.ConversationController.lookupOrCreate({
e164: source,
uuid: sourceUuid,
serviceId: sourceServiceId,
reason: 'MessageModel.getSenderIdentifier',
})!;
@ -372,7 +372,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
attachment: undefined,
// 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.
authorUuid: conversation?.get('uuid'),
authorAci: conversation?.getAci(),
// No messageId, referenced story not found!
messageId: '',
},
@ -389,10 +389,12 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
attachment = undefined;
}
const { sourceServiceId: authorAci } = message;
strictAssert(isAciString(authorAci), 'Story message from pni');
this.set({
storyReplyContext: {
attachment,
authorUuid: message.sourceUuid,
authorAci,
messageId: message.id,
},
});
@ -510,7 +512,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
if (messageHasPaymentEvent(attributes)) {
const sender = findAndFormatContact(attributes.sourceUuid);
const sender = findAndFormatContact(attributes.sourceServiceId);
const conversation = findAndFormatContact(attributes.conversationId);
return {
text: getPaymentEventNotificationText(
@ -850,7 +852,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if (
attributes.type === 'incoming' &&
attributes.storyReaction.targetAuthorUuid === ourAci
attributes.storyReaction.targetAuthorAci === ourAci
) {
return window.i18n('icu:Quote__story-reaction-notification--incoming', {
emoji: attributes.storyReaction.emoji,
@ -990,11 +992,11 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if (!fromSync) {
const senderE164 = getSource(this.attributes);
const senderUuid = getSourceUuid(this.attributes);
const senderAci = getSourceServiceId(this.attributes);
const timestamp = this.get('sent_at');
if (senderUuid === undefined) {
throw new Error('markViewOnceMessageViewed: senderUuid is undefined');
if (senderAci === undefined || !isAciString(senderAci)) {
throw new Error('markViewOnceMessageViewed: senderAci is undefined');
}
if (window.ConversationController.areWePrimaryDevice()) {
@ -1009,7 +1011,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
viewOnceOpens: [
{
senderE164,
senderUuid,
senderAci,
timestamp,
},
],
@ -1050,8 +1052,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
return;
}
const { authorUuid, author, id: sentAt, referencedMessageNotFound } = quote;
const contact = window.ConversationController.get(authorUuid || author);
const { authorAci, author, id: sentAt, referencedMessageNotFound } = quote;
const contact = window.ConversationController.get(authorAci || author);
// Is the quote really without a reference? Check with our in memory store
// first to make sure it's not there.
@ -1289,12 +1291,15 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if (!isIncoming(this.attributes)) {
return null;
}
const sourceUuid = this.get('sourceUuid');
if (!sourceUuid) {
const sourceServiceId = this.get('sourceServiceId');
if (!sourceServiceId) {
return null;
}
return window.ConversationController.getOrCreate(sourceUuid, 'private');
return window.ConversationController.getOrCreate(
sourceServiceId,
'private'
);
}
async retrySend(): Promise<void> {
@ -1318,7 +1323,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
currentConversationRecipients = new Set(
storyDistribution.members
.map(uuid => window.ConversationController.get(uuid)?.id)
.map(serviceId => window.ConversationController.get(serviceId)?.id)
.filter(isNotNil)
);
} else {
@ -1947,9 +1952,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
strictAssert(id, 'Quote must have an id');
const result: QuotedMessageType = {
...omit(quote, 'authorAci'),
...quote,
authorUuid: quote.authorAci,
id,
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
const message = this;
const source = message.get('source');
const sourceUuid = message.get('sourceUuid');
const sourceServiceId = message.get('sourceServiceId');
const type = message.get('type');
const conversationId = message.get('conversationId');
@ -2210,7 +2214,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const destinationConversation =
window.ConversationController.lookupOrCreate({
uuid: destinationServiceId,
serviceId: destinationServiceId,
e164: destination || undefined,
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
const sender = window.ConversationController.lookupOrCreate({
e164: source,
uuid: sourceUuid,
serviceId: sourceServiceId,
reason: 'handleDataMessage',
})!;
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.
const isBlocked =
(source && window.storage.blocked.isBlocked(source)) ||
(sourceUuid && window.storage.blocked.isUuidBlocked(sourceUuid));
(sourceServiceId &&
window.storage.blocked.isServiceIdBlocked(sourceServiceId));
if (isBlocked) {
log.info(
`${idLog}: Dropping message from blocked sender. hasGroupV2Prop: ${hasGroupV2Prop}`
@ -2371,7 +2376,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
type === 'incoming' &&
!isDirectConversation(conversation.attributes) &&
hasGroupV2Prop &&
(!areWeMember || (sourceUuid && !conversation.hasMember(sourceUuid)))
(!areWeMember ||
(sourceServiceId && !conversation.hasMember(sourceServiceId)))
) {
log.warn(
`${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.
drop(
window.Whisper.deliveryReceiptQueue.add(() => {
strictAssert(
isAciString(sourceServiceId),
'Incoming message must be from ACI'
);
window.Whisper.deliveryReceiptBatcher.add({
messageId,
conversationId,
senderE164: source,
senderUuid: sourceUuid,
senderAci: sourceServiceId,
timestamp: this.get('sent_at'),
isDirectConversation: isDirectConversation(
conversation.attributes
@ -2456,7 +2466,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const sendState = sendStateByConversationId[sender.id];
const storyQuoteIsFromSelf =
candidateQuote.get('sourceUuid') ===
candidateQuote.get('sourceServiceId') ===
window.storage.user.getCheckedAci();
if (!storyQuoteIsFromSelf) {
@ -2573,7 +2583,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
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({
id: messageId,
@ -2594,9 +2604,9 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if (!BodyRange.isMention(bodyRange)) {
return false;
}
return ourUuids.has(
return ourServiceIds.has(
normalizeServiceId(
bodyRange.mentionUuid,
bodyRange.mentionAci,
'handleDataMessage: mentionsMe check'
)
);
@ -2675,7 +2685,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
message.set({
expirationTimerUpdate: {
source,
sourceUuid,
sourceServiceId,
expireTimer: initialMessage.expireTimer,
},
});
@ -2697,7 +2707,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
// point and these calls will return early.
if (dataMessage.expireTimer) {
void conversation.updateExpirationTimer(dataMessage.expireTimer, {
source: sourceUuid || source,
source: sourceServiceId || source,
receivedAt: message.get('received_at'),
receivedAtMS: message.get('received_at_ms'),
sentAt: message.get('sent_at'),
@ -2710,7 +2720,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
!isEndSession(message.attributes)
) {
void conversation.updateExpirationTimer(undefined, {
source: sourceUuid || source,
source: sourceServiceId || source,
receivedAt: message.get('received_at'),
receivedAtMS: message.get('received_at_ms'),
sentAt: message.get('sent_at'),
@ -2723,7 +2733,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const { profileKey } = initialMessage;
if (
source === window.textsecure.storage.user.getNumber() ||
sourceUuid === window.textsecure.storage.user.getAci()
sourceServiceId === window.textsecure.storage.user.getAci()
) {
conversation.set({ profileSharing: true });
} else if (isDirectConversation(conversation.attributes)) {
@ -2731,7 +2741,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
} else {
const local = window.ConversationController.lookupOrCreate({
e164: source,
uuid: sourceUuid,
serviceId: sourceServiceId,
reason: 'handleDataMessage:setProfileKey',
});
void local?.setProfileKey(profileKey);
@ -2952,7 +2962,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const newReaction: MessageReactionType = {
emoji: reaction.get('remove') ? undefined : reaction.get('emoji'),
fromId: reaction.get('fromId'),
targetAuthorUuid: reaction.get('targetAuthorUuid'),
targetAuthorAci: reaction.get('targetAuthorAci'),
targetTimestamp: reaction.get('targetTimestamp'),
timestamp: reaction.get('timestamp'),
isSentByConversationId: isFromThisDevice
@ -3001,7 +3011,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
storyId: storyMessage.id,
storyReaction: {
emoji: reaction.get('emoji'),
targetAuthorUuid: reaction.get('targetAuthorUuid'),
targetAuthorAci: reaction.get('targetAuthorAci'),
targetTimestamp: reaction.get('targetTimestamp'),
},
});
@ -3097,7 +3107,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
await window.Signal.Data.removeReactionFromConversation({
emoji: reaction.get('emoji'),
fromId: reaction.get('fromId'),
targetAuthorServiceId: reaction.get('targetAuthorUuid'),
targetAuthorServiceId: reaction.get('targetAuthorAci'),
targetTimestamp: reaction.get('targetTimestamp'),
});
} else {
@ -3135,7 +3145,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
fromId: reaction.get('fromId'),
messageId: this.id,
messageReceivedAt: this.get('received_at'),
targetAuthorUuid: reaction.get('targetAuthorUuid'),
targetAuthorAci: reaction.get('targetAuthorAci'),
targetTimestamp: reaction.get('targetTimestamp'),
});
}

View file

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

View file

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

View file

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

View file

@ -5,6 +5,8 @@ import Delta from 'quill-delta';
import type { RefObject } from 'react';
import type { Matcher, AttributeMap } from 'quill';
import { assertDev } from '../../util/assert';
import { isAciString } from '../../types/ServiceId';
import type { MemberRepository } from '../memberRepository';
export const matchMention: (
@ -21,12 +23,14 @@ export const matchMention: (
const { id } = node.dataset;
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(
{
mention: {
title,
uuid: conversation.uuid,
aci,
},
},
attributes
@ -37,15 +41,20 @@ export const matchMention: (
}
if (node.classList.contains('mention-blot')) {
const { uuid } = node.dataset;
const conversation = memberRepository.getMemberByUuid(uuid);
const { aci } = node.dataset;
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(
{
mention: {
title: title || conversation.title,
uuid: conversation.uuid,
aci,
},
},
attributes

View file

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

View file

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

View file

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

View file

@ -369,9 +369,9 @@ export class CallingClass {
RingRTC.handleGroupCallRingUpdate =
this.handleGroupCallRingUpdate.bind(this);
this.attemptToGiveOurUuidToRingRtc();
this.attemptToGiveOurServiceIdToRingRtc();
window.Whisper.events.on('userChanged', () => {
this.attemptToGiveOurUuidToRingRtc();
this.attemptToGiveOurServiceIdToRingRtc();
});
ipcRenderer.on('stop-screen-share', () => {
@ -381,7 +381,7 @@ export class CallingClass {
void this.cleanExpiredGroupCallRingsAndLoop();
}
private attemptToGiveOurUuidToRingRtc(): void {
private attemptToGiveOurServiceIdToRingRtc(): void {
const ourAci = window.textsecure.storage.user.getAci();
if (!ourAci) {
// 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(
member =>
new GroupMemberInfo(
Buffer.from(uuidToBytes(member.uuid)),
Buffer.from(uuidToBytes(member.aci)),
Buffer.from(member.uuidCiphertext)
)
);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -335,7 +335,7 @@ export function toAccountRecord(
if (pinnedConversation.get('type') === 'private') {
pinnedConversationRecord.identifier = 'contact';
pinnedConversationRecord.contact = {
uuid: pinnedConversation.get('uuid'),
serviceId: pinnedConversation.getServiceId(),
e164: pinnedConversation.get('e164'),
};
} 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
if (conversation.get('uuid') !== serviceId) {
if (conversation.getServiceId() !== serviceId) {
log.warn(
`mergeContactRecord: ${conversation.idForLogging()} ` +
`with storageId ${conversation.get('storageID')} ` +
@ -1319,14 +1319,19 @@ export async function mergeAccountRecord(
let conversation: ConversationModel | undefined;
if (contact) {
if (!contact.uuid && !contact.e164) {
if (!contact.serviceId && !contact.e164) {
log.error(
'storageService.mergeAccountRecord: No uuid or e164 on contact'
'storageService.mergeAccountRecord: No serviceId or e164 on contact'
);
return undefined;
}
conversation = window.ConversationController.lookupOrCreate({
uuid: contact.uuid,
serviceId: contact.serviceId
? normalizeServiceId(
contact.serviceId,
'AccountRecord.pin.serviceId'
)
: undefined,
e164: contact.e164,
reason: 'storageService.mergeAccountRecord',
});
@ -1616,13 +1621,13 @@ export async function mergeStoryDistributionListRecord(
const localMembersListSet = new Set(localStoryDistributionList.members);
const toAdd: Array<ServiceIdString> = remoteListMembers.filter(
uuid => !localMembersListSet.has(uuid)
serviceId => !localMembersListSet.has(serviceId)
);
const remoteMemberListSet = new Set(remoteListMembers);
const toRemove: Array<ServiceIdString> =
localStoryDistributionList.members.filter(
uuid => !remoteMemberListSet.has(uuid)
serviceId => !remoteMemberListSet.has(serviceId)
);
details.push('updated');

View file

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

View file

@ -29,7 +29,7 @@ export async function writeProfile(
if (!model) {
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
const {

View file

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

View file

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

View file

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

View file

@ -16,7 +16,22 @@ import {
objectToJSON,
} 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(
currentVersion: number,

View file

@ -4,10 +4,8 @@
import type { Database } from '@signalapp/better-sqlite3';
import type { LoggerType } from '../../types/Logging';
import type { ServiceIdString } from '../../types/ServiceId';
import { jsonToObject } from '../util';
import type { EmptyQuery } from '../util';
import type { ConversationType } from '../Interface';
export default function updateToSchemaVersion53(
currentVersion: number,
@ -21,7 +19,13 @@ export default function updateToSchemaVersion53(
type LegacyConversationType = {
id: 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(

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 updateToSchemaVersion86 from './86-story-replies-index';
import updateToSchemaVersion87 from './87-calls-history-table';
import updateToSchemaVersion88 from './88-service-ids';
function updateToSchemaVersion1(
currentVersion: number,
@ -1996,6 +1997,7 @@ export const SCHEMA_VERSIONS = [
updateToSchemaVersion85,
updateToSchemaVersion86,
updateToSchemaVersion87,
updateToSchemaVersion88,
];
export function updateSchema(db: Database, logger: LoggerType): void {

View file

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

View file

@ -936,7 +936,7 @@ function keyChanged(
if (activeCall.callMode === CallMode.Group) {
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.
activeCall.remoteParticipants.forEach(participant => {
if (participant.aci === payload.aci) {

View file

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

View file

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

View file

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

View file

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

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