A number of additional merging fixes

This commit is contained in:
Scott Nonnenberg 2022-08-10 11:39:04 -07:00 committed by GitHub
parent ccc89545c5
commit 269d170275
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 7 deletions

View file

@ -73,6 +73,7 @@ message ContactRecord {
optional string serviceUuid = 1; optional string serviceUuid = 1;
optional string serviceE164 = 2; optional string serviceE164 = 2;
optional string pni = 15;
optional bytes profileKey = 3; optional bytes profileKey = 3;
optional bytes identityKey = 4; optional bytes identityKey = 4;
optional IdentityState identityState = 5; optional IdentityState identityState = 5;
@ -85,6 +86,7 @@ message ContactRecord {
optional bool markedUnread = 12; optional bool markedUnread = 12;
optional uint64 mutedUntilTimestamp = 13; optional uint64 mutedUntilTimestamp = 13;
optional bool hideStory = 14; optional bool hideStory = 14;
// Next ID: 16
} }
message GroupV1Record { message GroupV1Record {

View file

@ -664,7 +664,6 @@ export class ConversationController {
log.info('checkForConflicts: starting...'); log.info('checkForConflicts: starting...');
const byUuid = Object.create(null); const byUuid = Object.create(null);
const byE164 = Object.create(null); const byE164 = Object.create(null);
const byPni = Object.create(null);
const byGroupV2Id = Object.create(null); const byGroupV2Id = Object.create(null);
// We also want to find duplicate GV1 IDs. You might expect to see a "byGroupV1Id" map // We also want to find duplicate GV1 IDs. You might expect to see a "byGroupV1Id" map
// here. Instead, we check for duplicates on the derived GV2 ID. // here. Instead, we check for duplicates on the derived GV2 ID.
@ -706,18 +705,18 @@ export class ConversationController {
} }
if (pni) { if (pni) {
const existing = byPni[pni]; const existing = byUuid[pni];
if (!existing) { if (!existing) {
byPni[pni] = conversation; byUuid[pni] = conversation;
} else { } else {
log.warn(`checkForConflicts: Found conflict with pni ${pni}`); log.warn(`checkForConflicts: Found conflict with pni ${pni}`);
// Keep the newer one if it has a uuid, otherwise keep existing // Keep the newer one if it has additional data, otherwise keep existing
if (conversation.get('uuid')) { if (conversation.get('e164') || conversation.get('pni')) {
// Keep new one // Keep new one
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
await this.combineConversations(conversation, existing); await this.combineConversations(conversation, existing);
byPni[pni] = conversation; byUuid[pni] = conversation;
} else { } else {
// Keep existing - note that this applies if neither had an e164 // Keep existing - note that this applies if neither had an e164
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
@ -860,10 +859,21 @@ export class ConversationController {
} }
}); });
if (obsolete.get('isPinned')) {
obsolete.unpin();
if (!current.get('isPinned')) {
current.pin();
}
}
const obsoleteId = obsolete.get('id'); const obsoleteId = obsolete.get('id');
const obsoleteUuid = obsolete.getUuid(); const obsoleteUuid = obsolete.getUuid();
const currentId = current.get('id'); const currentId = current.get('id');
log.warn(`${logId}: Combining two conversations...`); log.warn(
`${logId}: Combining two conversations -`,
`old: ${obsolete.idForLogging()} -> new: ${current.idForLogging()}`
);
if (conversationType === 'private' && obsoleteUuid) { if (conversationType === 'private' && obsoleteUuid) {
if (!current.get('profileKey') && obsolete.get('profileKey')) { if (!current.get('profileKey') && obsolete.get('profileKey')) {
@ -956,6 +966,8 @@ export class ConversationController {
this._conversations.remove(obsolete); this._conversations.remove(obsolete);
this._conversations.resetLookups(); this._conversations.resetLookups();
current.captureChange('combineConversations');
log.warn(`${logId}: Complete!`); log.warn(`${logId}: Complete!`);
}); });
} }

View file

@ -1880,6 +1880,7 @@ export class ConversationModel extends window.Backbone
window.Signal.Data.updateConversation(this.attributes); window.Signal.Data.updateConversation(this.attributes);
this.trigger('idUpdated', this, 'e164', oldValue); this.trigger('idUpdated', this, 'e164', oldValue);
this.captureChange('updateE164');
} }
} }
@ -1889,6 +1890,7 @@ export class ConversationModel extends window.Backbone
this.set('uuid', uuid ? UUID.cast(uuid.toLowerCase()) : undefined); this.set('uuid', uuid ? UUID.cast(uuid.toLowerCase()) : undefined);
window.Signal.Data.updateConversation(this.attributes); window.Signal.Data.updateConversation(this.attributes);
this.trigger('idUpdated', this, 'uuid', oldValue); this.trigger('idUpdated', this, 'uuid', oldValue);
this.captureChange('updateUuid');
} }
} }
@ -1908,6 +1910,7 @@ export class ConversationModel extends window.Backbone
window.Signal.Data.updateConversation(this.attributes); window.Signal.Data.updateConversation(this.attributes);
this.trigger('idUpdated', this, 'pni', oldValue); this.trigger('idUpdated', this, 'pni', oldValue);
this.captureChange('updatePni');
} }
} }

View file

@ -137,6 +137,10 @@ export async function toContactRecord(
if (e164) { if (e164) {
contactRecord.serviceE164 = e164; contactRecord.serviceE164 = e164;
} }
const pni = conversation.get('pni');
if (pni) {
contactRecord.pni = pni;
}
const profileKey = conversation.get('profileKey'); const profileKey = conversation.get('profileKey');
if (profileKey) { if (profileKey) {
contactRecord.profileKey = Bytes.fromBase64(String(profileKey)); contactRecord.profileKey = Bytes.fromBase64(String(profileKey));
@ -849,6 +853,7 @@ export async function mergeContactRecord(
const e164 = dropNull(contactRecord.serviceE164); const e164 = dropNull(contactRecord.serviceE164);
const uuid = dropNull(contactRecord.serviceUuid); const uuid = dropNull(contactRecord.serviceUuid);
const pni = dropNull(contactRecord.pni);
// All contacts must have UUID // All contacts must have UUID
if (!uuid) { if (!uuid) {
@ -866,6 +871,7 @@ export async function mergeContactRecord(
const conversation = window.ConversationController.maybeMergeContacts({ const conversation = window.ConversationController.maybeMergeContacts({
aci: uuid, aci: uuid,
e164, e164,
pni,
reason: 'mergeContactRecord', reason: 'mergeContactRecord',
}); });
@ -873,6 +879,20 @@ export async function mergeContactRecord(
throw new Error(`No conversation for ${storageID}`); throw new Error(`No conversation for ${storageID}`);
} }
// We're going to ignore this; it's likely a PNI-only contact we've already merged
if (conversation.get('uuid') !== uuid) {
log.warn(
`mergeContactRecord: ${conversation.idForLogging()} ` +
`with storageId ${conversation.get('storageID')} ` +
`had uuid that didn't match provided uuid ${uuid}`
);
return {
hasConflict: false,
shouldDrop: true,
details: [],
};
}
let needsProfileFetch = false; let needsProfileFetch = false;
if (contactRecord.profileKey && contactRecord.profileKey.length > 0) { if (contactRecord.profileKey && contactRecord.profileKey.length > 0) {
needsProfileFetch = await conversation.setProfileKey( needsProfileFetch = await conversation.setProfileKey(