Export/import verified state

This commit is contained in:
Fedor Indutny 2024-11-12 12:43:52 -08:00 committed by GitHub
parent b517bb817f
commit 104995e980
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 83 additions and 23 deletions

View file

@ -17,7 +17,10 @@ import {
pauseWriteAccess,
resumeWriteAccess,
} from '../../sql/Client';
import type { PageMessagesCursorType } from '../../sql/Interface';
import type {
PageMessagesCursorType,
IdentityKeyType,
} from '../../sql/Interface';
import * as log from '../../logging/log';
import { GiftBadgeStates } from '../../components/conversation/Message';
import { type CustomColorType } from '../../types/Colors';
@ -290,6 +293,13 @@ export class BackupExportStream extends Readable {
stickerPacks: 0,
};
const identityKeys = await DataReader.getAllIdentityKeys();
const identityKeysById = new Map(
identityKeys.map(key => {
return [key.id, key];
})
);
for (const { attributes } of window.ConversationController.getAll()) {
const recipientId = this.getRecipientId({
id: attributes.id,
@ -297,7 +307,11 @@ export class BackupExportStream extends Readable {
e164: attributes.e164,
});
const recipient = this.toRecipient(recipientId, attributes);
const recipient = this.toRecipient(
recipientId,
attributes,
identityKeysById
);
if (recipient === undefined) {
// Can't be backed up.
continue;
@ -804,7 +818,8 @@ export class BackupExportStream extends Readable {
convo: Omit<
ConversationAttributesType,
'id' | 'version' | 'expireTimerVersion'
>
>,
identityKeysById?: ReadonlyMap<IdentityKeyType['id'], IdentityKeyType>
): Backups.IRecipient | undefined {
const res: Backups.IRecipient = {
id: recipientId,
@ -824,6 +839,11 @@ export class BackupExportStream extends Readable {
throw missingCaseError(convo.removalStage);
}
let identityKey: IdentityKeyType | undefined;
if (identityKeysById != null && convo.serviceId != null) {
identityKey = identityKeysById.get(convo.serviceId);
}
res.contact = {
aci:
convo.serviceId && convo.serviceId !== convo.pni
@ -856,6 +876,10 @@ export class BackupExportStream extends Readable {
profileGivenName: convo.profileName,
profileFamilyName: convo.profileFamilyName,
hideStory: convo.hideStory === true,
identityKey: identityKey?.publicKey || null,
// Integer values match so we can use it as is
identityState: identityKey?.verified ?? 0,
};
} else if (isGroupV2(convo) && convo.masterKey) {
let storySendMode: Backups.Group.StorySendMode;
@ -2092,6 +2116,15 @@ export class BackupExportStream extends Readable {
return null;
}
let quoteType: Backups.Quote.Type;
if (quote.isGiftBadge) {
quoteType = Backups.Quote.Type.GIFT_BADGE;
} else if (quote.isViewOnce) {
quoteType = Backups.Quote.Type.VIEW_ONCE;
} else {
quoteType = Backups.Quote.Type.NORMAL;
}
return {
targetSentTimestamp: Long.fromNumber(quote.id),
authorId,
@ -2123,9 +2156,7 @@ export class BackupExportStream extends Readable {
}
)
),
type: quote.isGiftBadge
? Backups.Quote.Type.GIFTBADGE
: Backups.Quote.Type.NORMAL,
type: quoteType,
};
}

View file

@ -14,6 +14,7 @@ import { DataReader, DataWriter } from '../../sql/Client';
import {
AttachmentDownloadSource,
type StoryDistributionWithMembersType,
type IdentityKeyType,
} from '../../sql/Interface';
import * as log from '../../logging/log';
import { GiftBadgeStates } from '../../components/conversation/Message';
@ -209,6 +210,7 @@ export class BackupImportStream extends Writable {
string,
ConversationAttributesType
>();
private readonly identityKeys = new Map<ServiceIdString, IdentityKeyType>();
private readonly saveMessageBatch = new Set<MessageAttributesType>();
private readonly stickerPacks = new Array<StickerPackPointerType>();
private ourConversation?: ConversationAttributesType;
@ -489,10 +491,14 @@ export class BackupImportStream extends Writable {
const saves = Array.from(this.conversations.values());
this.conversations.clear();
const identityKeys = Array.from(this.identityKeys.values());
this.identityKeys.clear();
// Queue writes at the same time to prevent races.
await Promise.all([
DataWriter.saveConversations(saves),
DataWriter.updateConversations(updates),
DataWriter.bulkAddIdentityKeys(identityKeys),
]);
}
@ -817,11 +823,13 @@ export class BackupImportStream extends Writable {
break;
}
const serviceId = aci ?? pni;
const attrs: ConversationAttributesType = {
id: generateUuid(),
type: 'private',
version: 2,
serviceId: aci ?? pni,
serviceId,
pni,
e164,
removalStage,
@ -836,6 +844,17 @@ export class BackupImportStream extends Writable {
expireTimerVersion: 1,
};
if (serviceId != null && Bytes.isNotEmpty(contact.identityKey)) {
this.identityKeys.set(serviceId, {
id: serviceId,
publicKey: contact.identityKey,
verified: contact.identityState || 0,
firstUse: true,
timestamp: this.now,
nonblockingApproval: true,
});
}
if (contact.notRegistered) {
const timestamp = contact.notRegistered.unregisteredTimestamp?.toNumber();
attrs.discoveredUnregisteredAt = timestamp || this.now;
@ -848,7 +867,6 @@ export class BackupImportStream extends Writable {
}
if (contact.blocked) {
const serviceId = aci || pni;
if (serviceId) {
await window.storage.blocked.addBlockedServiceId(serviceId);
}
@ -1671,8 +1689,11 @@ export class BackupImportStream extends Writable {
type: Backups.Quote.Type | null | undefined
): SignalService.DataMessage.Quote.Type {
switch (type) {
case Backups.Quote.Type.GIFTBADGE:
case Backups.Quote.Type.GIFT_BADGE:
return SignalService.DataMessage.Quote.Type.GIFT_BADGE;
case Backups.Quote.Type.VIEW_ONCE:
// No special treatment, we'll compute it once we find the message
return SignalService.DataMessage.Quote.Type.NORMAL;
case Backups.Quote.Type.NORMAL:
case Backups.Quote.Type.UNKNOWN:
case null: