Retain protections on gv1 records that match gv2 ids
This commit is contained in:
parent
5c8cb6b89b
commit
1264e6da2b
3 changed files with 36 additions and 71 deletions
|
@ -3725,7 +3725,9 @@ export class ConversationModel extends window.Backbone.Model<
|
||||||
|
|
||||||
if (Boolean(before) !== Boolean(after)) {
|
if (Boolean(before) !== Boolean(after)) {
|
||||||
if (after) {
|
if (after) {
|
||||||
this.unpin();
|
// we're capturing a storage sync below so
|
||||||
|
// we don't need to capture it twice
|
||||||
|
this.unpin({ stopStorageSync: true });
|
||||||
}
|
}
|
||||||
this.captureChange('isArchived');
|
this.captureChange('isArchived');
|
||||||
}
|
}
|
||||||
|
@ -5105,6 +5107,10 @@ export class ConversationModel extends window.Backbone.Model<
|
||||||
}
|
}
|
||||||
|
|
||||||
pin(): void {
|
pin(): void {
|
||||||
|
if (this.get('isPinned')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
window.log.info('pinning', this.idForLogging());
|
window.log.info('pinning', this.idForLogging());
|
||||||
const pinnedConversationIds = new Set(
|
const pinnedConversationIds = new Set(
|
||||||
window.storage.get<Array<string>>('pinnedConversationIds', [])
|
window.storage.get<Array<string>>('pinnedConversationIds', [])
|
||||||
|
@ -5115,14 +5121,18 @@ export class ConversationModel extends window.Backbone.Model<
|
||||||
this.writePinnedConversations([...pinnedConversationIds]);
|
this.writePinnedConversations([...pinnedConversationIds]);
|
||||||
|
|
||||||
this.set('isPinned', true);
|
this.set('isPinned', true);
|
||||||
window.Signal.Data.updateConversation(this.attributes);
|
|
||||||
|
|
||||||
if (this.get('isArchived')) {
|
if (this.get('isArchived')) {
|
||||||
this.setArchived(false);
|
this.set({ isArchived: false });
|
||||||
}
|
}
|
||||||
|
window.Signal.Data.updateConversation(this.attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
unpin({ stopStorageSync = false } = {}): void {
|
||||||
|
if (!this.get('isPinned')) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unpin(): void {
|
|
||||||
window.log.info('un-pinning', this.idForLogging());
|
window.log.info('un-pinning', this.idForLogging());
|
||||||
|
|
||||||
const pinnedConversationIds = new Set(
|
const pinnedConversationIds = new Set(
|
||||||
|
@ -5131,7 +5141,9 @@ export class ConversationModel extends window.Backbone.Model<
|
||||||
|
|
||||||
pinnedConversationIds.delete(this.id);
|
pinnedConversationIds.delete(this.id);
|
||||||
|
|
||||||
|
if (!stopStorageSync) {
|
||||||
this.writePinnedConversations([...pinnedConversationIds]);
|
this.writePinnedConversations([...pinnedConversationIds]);
|
||||||
|
}
|
||||||
|
|
||||||
this.set('isPinned', false);
|
this.set('isPinned', false);
|
||||||
window.Signal.Data.updateConversation(this.attributes);
|
window.Signal.Data.updateConversation(this.attributes);
|
||||||
|
|
|
@ -131,8 +131,6 @@ async function generateManifest(
|
||||||
|
|
||||||
await window.ConversationController.checkForConflicts();
|
await window.ConversationController.checkForConflicts();
|
||||||
|
|
||||||
await repairUnknownAndErroredRecords();
|
|
||||||
|
|
||||||
const ITEM_TYPE = window.textsecure.protobuf.ManifestRecord.Identifier.Type;
|
const ITEM_TYPE = window.textsecure.protobuf.ManifestRecord.Identifier.Type;
|
||||||
|
|
||||||
const conversationsToUpdate = [];
|
const conversationsToUpdate = [];
|
||||||
|
@ -351,54 +349,6 @@ async function generateManifest(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function repairUnknownAndErroredRecords() {
|
|
||||||
const unknownRecordsArray: ReadonlyArray<UnknownRecord> =
|
|
||||||
window.storage.get('storage-service-unknown-records') || [];
|
|
||||||
|
|
||||||
const recordsWithErrors: ReadonlyArray<UnknownRecord> =
|
|
||||||
window.storage.get('storage-service-error-records') || [];
|
|
||||||
|
|
||||||
const remoteRecords = unknownRecordsArray.concat(recordsWithErrors);
|
|
||||||
|
|
||||||
// No repair necessary
|
|
||||||
if (remoteRecords.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process unknown and records with records from the past sync to see
|
|
||||||
// if they can be merged
|
|
||||||
const remoteRecordsMap: Map<string, RemoteRecord> = new Map();
|
|
||||||
remoteRecords.forEach(record => {
|
|
||||||
remoteRecordsMap.set(record.storageID, record);
|
|
||||||
});
|
|
||||||
|
|
||||||
window.log.info(
|
|
||||||
'storageService.repairUnknownAndErroredRecords: found ' +
|
|
||||||
`${unknownRecordsArray.length} unknown records and ` +
|
|
||||||
`${recordsWithErrors.length} errored records, attempting repair`
|
|
||||||
);
|
|
||||||
const conflictCount = await processRemoteRecords(remoteRecordsMap);
|
|
||||||
if (conflictCount !== 0) {
|
|
||||||
window.log.info(
|
|
||||||
'storageService.repairUnknownAndErroredRecords: fixed ' +
|
|
||||||
`${conflictCount} conflicts`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const newUnknownCount = (
|
|
||||||
window.storage.get('storage-service-unknown-records') || []
|
|
||||||
).length;
|
|
||||||
const newErroredCount = (
|
|
||||||
window.storage.get('storage-service-error-records') || []
|
|
||||||
).length;
|
|
||||||
|
|
||||||
window.log.info(
|
|
||||||
'storageService.repairUnknownAndErroredRecords: ' +
|
|
||||||
`${newUnknownCount} unknown records and ` +
|
|
||||||
`${newErroredCount} errored records after repair`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function uploadManifest(
|
async function uploadManifest(
|
||||||
version: number,
|
version: number,
|
||||||
{
|
{
|
||||||
|
@ -647,8 +597,9 @@ async function mergeRecord(
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
hasError = true;
|
hasError = true;
|
||||||
window.log.error(
|
window.log.error(
|
||||||
'storageService.mergeRecord: merging record failed',
|
'storageService.mergeRecord: Error with',
|
||||||
err && err.stack ? err.stack : String(err)
|
storageID,
|
||||||
|
itemType
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,14 +642,6 @@ async function processManifest(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const recordsWithErrors: ReadonlyArray<UnknownRecord> =
|
|
||||||
window.storage.get('storage-service-error-records') || [];
|
|
||||||
|
|
||||||
// Do not fetch any records that we failed to merge in the previous fetch
|
|
||||||
recordsWithErrors.forEach((record: UnknownRecord) => {
|
|
||||||
localKeys.push(record.storageID);
|
|
||||||
});
|
|
||||||
|
|
||||||
window.log.info(
|
window.log.info(
|
||||||
'storageService.processManifest: local keys:',
|
'storageService.processManifest: local keys:',
|
||||||
localKeys.length
|
localKeys.length
|
||||||
|
@ -708,10 +651,6 @@ async function processManifest(
|
||||||
'storageService.processManifest: incl. unknown records:',
|
'storageService.processManifest: incl. unknown records:',
|
||||||
unknownRecordsArray.length
|
unknownRecordsArray.length
|
||||||
);
|
);
|
||||||
window.log.info(
|
|
||||||
'storageService.processManifest: incl. records with errors:',
|
|
||||||
recordsWithErrors.length
|
|
||||||
);
|
|
||||||
|
|
||||||
const remoteKeys = Array.from(remoteKeysTypeMap.keys());
|
const remoteKeys = Array.from(remoteKeysTypeMap.keys());
|
||||||
|
|
||||||
|
@ -1062,6 +1001,9 @@ async function upload(fromSync = false): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromSync) {
|
if (!fromSync) {
|
||||||
|
// Syncing before we upload so that we repair any unknown records and
|
||||||
|
// records with errors as well as ensure that we have the latest up to date
|
||||||
|
// manifest.
|
||||||
await sync();
|
await sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -388,7 +388,20 @@ export async function mergeGroupV1Record(
|
||||||
// Attempt to fetch an existing group pertaining to the `groupId` or create
|
// Attempt to fetch an existing group pertaining to the `groupId` or create
|
||||||
// a new group and populate it with the attributes from the record.
|
// a new group and populate it with the attributes from the record.
|
||||||
let conversation = window.ConversationController.get(groupId);
|
let conversation = window.ConversationController.get(groupId);
|
||||||
|
|
||||||
|
// Because ConversationController.get retrieves all types of records we
|
||||||
|
// may sometimes have a situation where we get a record of groupv1 type
|
||||||
|
// where the binary representation of its ID matches a v2 record in memory.
|
||||||
|
// Here we ensure that the record we're about to process is GV1 otherwise
|
||||||
|
// we drop the update.
|
||||||
|
if (conversation && !conversation.isGroupV1()) {
|
||||||
|
throw new Error(`Record has group type mismatch ${conversation.debugID()}`);
|
||||||
|
}
|
||||||
|
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
|
// It's possible this group was migrated to a GV2 if so we attempt to
|
||||||
|
// retrieve the master key and find the conversation locally. If we
|
||||||
|
// are successful then we continue setting and applying state.
|
||||||
const masterKeyBuffer = await deriveMasterKeyFromGroupV1(groupId);
|
const masterKeyBuffer = await deriveMasterKeyFromGroupV1(groupId);
|
||||||
const fields = deriveGroupFields(masterKeyBuffer);
|
const fields = deriveGroupFields(masterKeyBuffer);
|
||||||
const derivedGroupV2Id = arrayBufferToBase64(fields.id);
|
const derivedGroupV2Id = arrayBufferToBase64(fields.id);
|
||||||
|
@ -415,8 +428,6 @@ export async function mergeGroupV1Record(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we receive a group V1 record, remote data should take precendence
|
|
||||||
// even if the group is actually V2 on our end.
|
|
||||||
conversation.set({
|
conversation.set({
|
||||||
isArchived: Boolean(groupV1Record.archived),
|
isArchived: Boolean(groupV1Record.archived),
|
||||||
markedUnread: Boolean(groupV1Record.markedUnread),
|
markedUnread: Boolean(groupV1Record.markedUnread),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue