Fix some import cycles

Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
This commit is contained in:
automated-signal
2026-03-27 13:41:39 -05:00
committed by GitHub
parent 0adf48ecf4
commit 028290cb1c
27 changed files with 229 additions and 207 deletions
+2 -1
View File
@@ -51,6 +51,7 @@ import { validateConversation } from './util/validateConversation.dom.js';
import { ConversationModel } from './models/conversations.preload.js';
import { INITIAL_EXPIRE_TIMER_VERSION } from './util/expirationTimer.std.js';
import { missingCaseError } from './util/missingCaseError.std.js';
import { removeConversation } from './util/Conversation.preload.js';
import { signalProtocolStore } from './SignalProtocolStore.preload.js';
import type {
@@ -159,7 +160,6 @@ const { getAllConversations, getMessagesBySentAt } = DataReader;
const {
migrateConversationMessages,
removeConversation,
saveConversation,
updateConversation,
updateConversations,
@@ -370,6 +370,7 @@ export class ConversationController {
conversationsUpdated([conversation.format()]);
}
}
#removeConversation(conversation: ConversationModel): void {
this.#_conversations = without(this.#_conversations, conversation);
this.#removeFromLookup(conversation);
@@ -32,7 +32,7 @@ import { Address } from './types/Address.std.js';
import { QualifiedAddress } from './types/QualifiedAddress.std.js';
import type { ServiceIdString } from './types/ServiceId.std.js';
import { normalizeServiceId } from './types/ServiceId.std.js';
import { signalProtocolStore } from './SignalProtocolStore.preload.js';
import type { SignalProtocolStore } from './SignalProtocolStore.preload.js';
import type { Zone } from './util/Zone.std.js';
@@ -52,17 +52,20 @@ function toQualifiedAddress(
}
export type SessionsOptions = Readonly<{
signalProtocolStore: SignalProtocolStore;
ourServiceId: ServiceIdString;
zone?: Zone;
}>;
export class Sessions extends SessionStore {
readonly #signalProtocolStore: SignalProtocolStore;
readonly #ourServiceId: ServiceIdString;
readonly #zone: Zone | undefined;
constructor({ ourServiceId, zone }: SessionsOptions) {
constructor({ signalProtocolStore, ourServiceId, zone }: SessionsOptions) {
super();
this.#signalProtocolStore = signalProtocolStore;
this.#ourServiceId = ourServiceId;
this.#zone = zone;
}
@@ -71,7 +74,7 @@ export class Sessions extends SessionStore {
address: ProtocolAddress,
record: SessionRecord
): Promise<void> {
await signalProtocolStore.storeSession(
await this.#signalProtocolStore.storeSession(
toQualifiedAddress(this.#ourServiceId, address),
record,
{ zone: this.#zone }
@@ -80,7 +83,7 @@ export class Sessions extends SessionStore {
async getSession(name: ProtocolAddress): Promise<SessionRecord | null> {
const encodedAddress = toQualifiedAddress(this.#ourServiceId, name);
const record = await signalProtocolStore.loadSession(encodedAddress, {
const record = await this.#signalProtocolStore.loadSession(encodedAddress, {
zone: this.#zone,
});
@@ -93,30 +96,39 @@ export class Sessions extends SessionStore {
const encodedAddresses = addresses.map(addr =>
toQualifiedAddress(this.#ourServiceId, addr)
);
return signalProtocolStore.loadSessions(encodedAddresses, {
return this.#signalProtocolStore.loadSessions(encodedAddresses, {
zone: this.#zone,
});
}
}
export type IdentityKeysOptions = Readonly<{
signalProtocolStore: SignalProtocolStore;
ourServiceId: ServiceIdString;
zone?: Zone;
}>;
export class IdentityKeys extends IdentityKeyStore {
readonly #signalProtocolStore: SignalProtocolStore;
readonly #ourServiceId: ServiceIdString;
readonly #zone: Zone | undefined;
constructor({ ourServiceId, zone }: IdentityKeysOptions) {
constructor({
signalProtocolStore,
ourServiceId,
zone,
}: IdentityKeysOptions) {
super();
this.#signalProtocolStore = signalProtocolStore;
this.#ourServiceId = ourServiceId;
this.#zone = zone;
}
async getIdentityKey(): Promise<PrivateKey> {
const keyPair = signalProtocolStore.getIdentityKeyPair(this.#ourServiceId);
const keyPair = this.#signalProtocolStore.getIdentityKeyPair(
this.#ourServiceId
);
if (!keyPair) {
throw new Error('IdentityKeyStore/getIdentityKey: No identity key!');
}
@@ -124,7 +136,7 @@ export class IdentityKeys extends IdentityKeyStore {
}
async getLocalRegistrationId(): Promise<number> {
const id = await signalProtocolStore.getLocalRegistrationId(
const id = await this.#signalProtocolStore.getLocalRegistrationId(
this.#ourServiceId
);
if (!isNumber(id)) {
@@ -137,7 +149,7 @@ export class IdentityKeys extends IdentityKeyStore {
async getIdentity(address: ProtocolAddress): Promise<PublicKey | null> {
const encodedAddress = encodeAddress(address);
const key = await signalProtocolStore.loadIdentityKey(
const key = await this.#signalProtocolStore.loadIdentityKey(
encodedAddress.serviceId
);
@@ -157,9 +169,14 @@ export class IdentityKeys extends IdentityKeyStore {
// Pass `zone` to let `saveIdentity` archive sibling sessions when identity
// key changes.
return signalProtocolStore.saveIdentity(encodedAddress, publicKey, false, {
zone: this.#zone,
});
return this.#signalProtocolStore.saveIdentity(
encodedAddress,
publicKey,
false,
{
zone: this.#zone,
}
);
}
async isTrustedIdentity(
@@ -170,7 +187,7 @@ export class IdentityKeys extends IdentityKeyStore {
const encodedAddress = encodeAddress(name);
const publicKey = key.serialize();
return signalProtocolStore.isTrustedIdentity(
return this.#signalProtocolStore.isTrustedIdentity(
encodedAddress,
publicKey,
direction
@@ -179,16 +196,19 @@ export class IdentityKeys extends IdentityKeyStore {
}
export type PreKeysOptions = Readonly<{
signalProtocolStore: SignalProtocolStore;
ourServiceId: ServiceIdString;
zone?: Zone;
}>;
export class PreKeys extends PreKeyStore {
readonly #signalProtocolStore: SignalProtocolStore;
readonly #ourServiceId: ServiceIdString;
readonly #zone: Zone | undefined;
constructor({ ourServiceId, zone }: PreKeysOptions) {
constructor({ signalProtocolStore, ourServiceId, zone }: PreKeysOptions) {
super();
this.#signalProtocolStore = signalProtocolStore;
this.#ourServiceId = ourServiceId;
this.#zone = zone;
}
@@ -198,7 +218,10 @@ export class PreKeys extends PreKeyStore {
}
async getPreKey(id: number): Promise<PreKeyRecord> {
const preKey = await signalProtocolStore.loadPreKey(this.#ourServiceId, id);
const preKey = await this.#signalProtocolStore.loadPreKey(
this.#ourServiceId,
id
);
if (preKey === undefined) {
throw new Error(`getPreKey: PreKey ${id} not found`);
@@ -208,18 +231,20 @@ export class PreKeys extends PreKeyStore {
}
async removePreKey(id: number): Promise<void> {
await signalProtocolStore.removePreKeys(this.#ourServiceId, [id], {
await this.#signalProtocolStore.removePreKeys(this.#ourServiceId, [id], {
zone: this.#zone,
});
}
}
export class KyberPreKeys extends KyberPreKeyStore {
readonly #signalProtocolStore: SignalProtocolStore;
readonly #ourServiceId: ServiceIdString;
readonly #zone: Zone | undefined;
constructor({ ourServiceId, zone }: PreKeysOptions) {
constructor({ signalProtocolStore, ourServiceId, zone }: PreKeysOptions) {
super();
this.#signalProtocolStore = signalProtocolStore;
this.#ourServiceId = ourServiceId;
this.#zone = zone;
}
@@ -229,7 +254,7 @@ export class KyberPreKeys extends KyberPreKeyStore {
}
async getKyberPreKey(id: number): Promise<KyberPreKeyRecord> {
const kyberPreKey = await signalProtocolStore.loadKyberPreKey(
const kyberPreKey = await this.#signalProtocolStore.loadKyberPreKey(
this.#ourServiceId,
id
);
@@ -246,7 +271,7 @@ export class KyberPreKeys extends KyberPreKeyStore {
signedPreKeyId: number,
baseKey: PublicKey
): Promise<void> {
await signalProtocolStore.maybeRemoveKyberPreKey(
await this.#signalProtocolStore.maybeRemoveKyberPreKey(
this.#ourServiceId,
{ keyId, signedPreKeyId, baseKey },
{ zone: this.#zone }
@@ -255,16 +280,19 @@ export class KyberPreKeys extends KyberPreKeyStore {
}
export type SenderKeysOptions = Readonly<{
readonly ourServiceId: ServiceIdString;
readonly zone: Zone | undefined;
signalProtocolStore: SignalProtocolStore;
ourServiceId: ServiceIdString;
zone: Zone | undefined;
}>;
export class SenderKeys extends SenderKeyStore {
readonly #signalProtocolStore: SignalProtocolStore;
readonly #ourServiceId: ServiceIdString;
readonly zone: Zone | undefined;
constructor({ ourServiceId, zone }: SenderKeysOptions) {
constructor({ signalProtocolStore, ourServiceId, zone }: SenderKeysOptions) {
super();
this.#signalProtocolStore = signalProtocolStore;
this.#ourServiceId = ourServiceId;
this.zone = zone;
}
@@ -276,7 +304,7 @@ export class SenderKeys extends SenderKeyStore {
): Promise<void> {
const encodedAddress = toQualifiedAddress(this.#ourServiceId, sender);
await signalProtocolStore.saveSenderKey(
await this.#signalProtocolStore.saveSenderKey(
encodedAddress,
distributionId,
record,
@@ -290,7 +318,7 @@ export class SenderKeys extends SenderKeyStore {
): Promise<SenderKeyRecord | null> {
const encodedAddress = toQualifiedAddress(this.#ourServiceId, sender);
const senderKey = await signalProtocolStore.getSenderKey(
const senderKey = await this.#signalProtocolStore.getSenderKey(
encodedAddress,
distributionId,
{ zone: this.zone }
@@ -301,15 +329,18 @@ export class SenderKeys extends SenderKeyStore {
}
export type SignedPreKeysOptions = Readonly<{
signalProtocolStore: SignalProtocolStore;
ourServiceId: ServiceIdString;
}>;
// No need for zone awareness, since no mutation happens in this store
export class SignedPreKeys extends SignedPreKeyStore {
readonly #signalProtocolStore: SignalProtocolStore;
readonly #ourServiceId: ServiceIdString;
constructor({ ourServiceId }: SignedPreKeysOptions) {
constructor({ signalProtocolStore, ourServiceId }: SignedPreKeysOptions) {
super();
this.#signalProtocolStore = signalProtocolStore;
this.#ourServiceId = ourServiceId;
}
@@ -318,7 +349,7 @@ export class SignedPreKeys extends SignedPreKeyStore {
}
async getSignedPreKey(id: number): Promise<SignedPreKeyRecord> {
const signedPreKey = await signalProtocolStore.loadSignedPreKey(
const signedPreKey = await this.#signalProtocolStore.loadSignedPreKey(
this.#ourServiceId,
id
);
@@ -332,24 +363,30 @@ export class SignedPreKeys extends SignedPreKeyStore {
}
export class KeyTransparencyStore implements KeyTransparencyStoreInterface {
readonly #signalProtocolStore: SignalProtocolStore;
constructor(signalProtocolStore: SignalProtocolStore) {
this.#signalProtocolStore = signalProtocolStore;
}
async getLastDistinguishedTreeHead(): Promise<Uint8Array<ArrayBuffer> | null> {
return signalProtocolStore.getLastDistinguishedTreeHead();
return this.#signalProtocolStore.getLastDistinguishedTreeHead();
}
async setLastDistinguishedTreeHead(
bytes: Readonly<Uint8Array<ArrayBuffer>> | null
): Promise<void> {
return signalProtocolStore.setLastDistinguishedTreeHead(bytes);
return this.#signalProtocolStore.setLastDistinguishedTreeHead(bytes);
}
async getAccountData(aci: Aci): Promise<Uint8Array<ArrayBuffer> | null> {
return signalProtocolStore.getKTAccountData(aci);
return this.#signalProtocolStore.getKTAccountData(aci);
}
async setAccountData(
aci: Aci,
bytes: Readonly<Uint8Array<ArrayBuffer>>
): Promise<void> {
return signalProtocolStore.setKTAccountData(aci, bytes);
return this.#signalProtocolStore.setKTAccountData(aci, bytes);
}
}
+2 -1
View File
@@ -36,6 +36,7 @@ import { dropNull } from '../util/dropNull.std.js';
import { getLocalAttachmentUrl } from '../util/getLocalAttachmentUrl.std.js';
import { type Loadable, LoadingState } from '../util/loadable.std.js';
import { missingCaseError } from '../util/missingCaseError.std.js';
import { removeConversation } from '../util/Conversation.preload.js';
import { itemStorage } from '../textsecure/Storage.preload.js';
const log = createLogger('joinViaLink');
@@ -371,7 +372,7 @@ export async function joinViaLink(value: string): Promise<void> {
window.ConversationController.dangerouslyRemoveById(
tempConversation.id
);
await DataWriter.removeConversation(tempConversation.id);
await removeConversation(tempConversation.id);
}
throw error;
+1 -1
View File
@@ -86,7 +86,7 @@ import { JobCancelReason } from './types.std.js';
import { isAbortError } from '../util/isAbortError.std.js';
import { itemStorage } from '../textsecure/Storage.preload.js';
import { calculateExpirationTimestamp } from '../util/expirationTimer.std.js';
import { cleanupAttachmentFiles } from '../types/Message2.preload.js';
import { cleanupAttachmentFiles } from '../util/cleanup.preload.js';
import { getExistingAttachmentDataForReuse } from '../util/attachments/deduplicateAttachment.preload.js';
const { noop, omit, throttle } = lodash;
+1 -1
View File
@@ -67,7 +67,7 @@ import type {
GroupCallPeekInfoType,
} from '../state/ducks/calling.preload.js';
import type { ConversationType } from '../state/ducks/conversations.preload.js';
import { getConversationCallMode } from '../state/ducks/conversations.preload.js';
import { getConversationCallMode } from '../util/getConversationCallMode.std.js';
import { isMe } from '../util/whatTypeOfConversation.dom.js';
import { getAbsoluteTempPath } from '../util/migrations.preload.js';
import { isKnownProtoEnumMember } from '../util/isKnownProtoEnumMember.std.js';
-16
View File
@@ -13,11 +13,9 @@ import * as Bytes from '../Bytes.std.js';
import { createLogger } from '../logging/log.std.js';
import * as Errors from '../types/errors.std.js';
import { deleteExternalFiles } from '../types/Conversation.std.js';
import { createBatcher } from '../util/batcher.std.js';
import { assertDev, softAssert } from '../util/assert.std.js';
import { mapObjectWithSpec } from '../util/mapObjectWithSpec.std.js';
import { maybeDeleteAttachmentFile } from '../util/migrations.preload.js';
import { cleanDataForIpc } from './cleanDataForIpc.std.js';
import { runTaskWithTimeout } from '../textsecure/TaskWithTimeout.std.js';
import { isValidUuid, isValidUuidV7 } from '../util/isValidUuid.std.js';
@@ -131,7 +129,6 @@ const clientOnlyWritable: ClientOnlyWritableInterface = {
createOrUpdateItem,
updateConversation,
removeConversation,
removeMessageById,
removeMessagesById,
@@ -553,19 +550,6 @@ async function updateConversations(
await writableChannel.updateConversations(cleaned);
}
async function removeConversation(id: string): Promise<void> {
const existing = await readableChannel.getConversationById(id);
// Note: It's important to have a fully database-hydrated model to delete here because
// it needs to delete all associated on-disk files along with the database delete.
if (existing) {
await writableChannel.removeConversation(id);
await deleteExternalFiles(existing, {
maybeDeleteAttachmentFile,
});
}
}
function handleSearchMessageJSON(
messages: Array<ServerSearchResultMessageType>
): Array<ClientSearchResultMessageType> {
+2 -3
View File
@@ -1190,7 +1190,8 @@ type WritableInterface = {
saveConversations: (array: Array<ConversationType>) => void;
// updateConversation is a normal data method on Server, a sync batch-add on Client
updateConversations: (array: Array<ConversationType>) => void;
// removeConversation handles either one id or an array on Server, and one id on Client
/** @internal use ts/util/Conversation.preload.ts */
_removeConversation: (id: string) => void;
_removeAllConversations: () => void;
updateAllConversationColors: (
conversationColor?: ConversationColorType,
@@ -1583,7 +1584,6 @@ export type ServerWritableDirectInterface = WritableInterface & {
// Differing signature on client/server
updateConversation: (data: ConversationType) => void;
removeConversation: (id: Array<string> | string) => void;
saveMessage: (
data: ReadonlyDeep<MessageType>,
@@ -1689,7 +1689,6 @@ export type ClientOnlyReadableInterface = ClientInterfaceWrap<{
export type ClientOnlyWritableInterface = ClientInterfaceWrap<{
// Differing signature on client/server
updateConversation: (data: ConversationType) => void;
removeConversation: (id: string) => void;
flushUpdateConversationBatcher: () => void;
saveMessage: (
+5 -32
View File
@@ -637,7 +637,7 @@ export const DataWriter: ServerWritableInterface = {
saveConversations,
updateConversation,
updateConversations,
removeConversation,
_removeConversation,
_removeAllConversations,
updateAllConversationColors,
removeAllProfileKeyCredentials,
@@ -2046,37 +2046,10 @@ function updateConversations(
})();
}
function removeConversations(
db: WritableDB,
ids: ReadonlyArray<string>,
persistent: boolean
): void {
// Our node interface doesn't seem to allow you to replace one single ? with an array
db.prepare(
`
DELETE FROM conversations
WHERE id IN ( ${ids.map(() => '?').join(', ')} );
`,
{ persistent }
).run(ids);
}
function removeConversation(db: WritableDB, id: Array<string> | string): void {
if (!Array.isArray(id)) {
db.prepare('DELETE FROM conversations WHERE id = $id;').run({
id,
});
return;
}
if (!id.length) {
throw new Error('removeConversation: No ids to delete!');
}
batchMultiVarQuery(db, id, (ids, persistent) =>
removeConversations(db, ids, persistent)
);
function _removeConversation(db: WritableDB, id: string): void {
db.prepare('DELETE FROM conversations WHERE id = $id;').run({
id,
});
}
function _removeAllConversations(db: WritableDB): void {
+2 -4
View File
@@ -69,12 +69,10 @@ import type {
ConversationsUpdatedActionType,
ConversationRemovedActionType,
} from './conversations.preload.js';
import {
getConversationCallMode,
updateLastMessage,
} from './conversations.preload.js';
import { updateLastMessage } from './conversations.preload.js';
import { createLogger } from '../../logging/log.std.js';
import { strictAssert } from '../../util/assert.std.js';
import { getConversationCallMode } from '../../util/getConversationCallMode.std.js';
import { waitForOnline } from '../../util/waitForOnline.dom.js';
import * as mapUtil from '../../util/mapUtil.std.js';
import { isCallSafe } from '../../util/isCallSafe.dom.js';
-25
View File
@@ -657,31 +657,6 @@ export type ConversationsStateType = ReadonlyDeep<{
hasProfileUpdateError?: boolean;
}>;
// Helpers
export const getConversationCallMode = (
conversation: ConversationType
): CallMode | null => {
if (
conversation.left ||
conversation.isBlocked ||
conversation.isMe ||
!conversation.acceptedMessageRequest
) {
return null;
}
if (conversation.type === 'direct') {
return CallMode.Direct;
}
if (conversation.type === 'group' && conversation.groupVersion === 2) {
return CallMode.Group;
}
return null;
};
// Actions
const CANCEL_CONVERSATION_PENDING_VERIFICATION =
+1 -1
View File
@@ -97,7 +97,7 @@ import {
AttachmentDisposition,
} from '../../util/getLocalAttachmentUrl.std.js';
import { isVoiceMessagePlayed } from '../../util/isVoiceMessagePlayed.std.js';
import { isPermanentlyUndownloadable } from '../../jobs/AttachmentDownloadManager.preload.js';
import { isPermanentlyUndownloadable } from '../../jobs/helpers/attachmentBackfill.preload.js';
import { getAccountSelector } from './accounts.std.js';
import {
@@ -20,13 +20,11 @@ import { isConversationSMSOnly } from '../../util/isConversationSMSOnly.std.js';
import { isGroupOrAdhocCallState } from '../../util/isGroupOrAdhocCall.std.js';
import { isSignalConversation } from '../../util/isSignalConversation.dom.js';
import { missingCaseError } from '../../util/missingCaseError.std.js';
import { getConversationCallMode } from '../../util/getConversationCallMode.std.js';
import { useCallingActions } from '../ducks/calling.preload.js';
import { isAnybodyElseInGroupCall } from '../ducks/callingHelpers.std.js';
import type { ConversationType } from '../ducks/conversations.preload.js';
import {
getConversationCallMode,
useConversationsActions,
} from '../ducks/conversations.preload.js';
import { useConversationsActions } from '../ducks/conversations.preload.js';
import { useSearchActions } from '../ducks/search.preload.js';
import { useStoriesActions } from '../ducks/stories.preload.js';
import { getPreferredBadgeSelector } from '../selectors/badges.preload.js';
@@ -26,14 +26,14 @@ import { strictAssert } from '../util/assert.std.js';
import {
cleanupAllMessageAttachmentFiles,
cleanupAttachmentFiles,
} from '../types/Message2.preload.js';
cleanupMessages,
} from '../util/cleanup.preload.js';
import { DataReader, DataWriter } from '../sql/Client.preload.js';
import { generateAci } from '../types/ServiceId.std.js';
import {
testAttachmentLocalKey,
testPlaintextHash,
} from '../test-helpers/attachments.node.js';
import { cleanupMessages } from '../util/cleanup.preload.js';
const { emptyDir, ensureFile } = fsExtra;
@@ -30,7 +30,6 @@ import {
actions,
cancelConversationVerification,
clearCanceledConversationVerification,
getConversationCallMode,
getEmptyState,
reducer,
updateConversationLookups,
@@ -69,6 +68,7 @@ import {
import { MY_STORY_ID } from '../../../types/Stories.std.js';
import type { ReadonlyMessageAttributesType } from '../../../model-types.d.ts';
import { strictAssert } from '../../../util/assert.std.js';
import { getConversationCallMode } from '../../../util/getConversationCallMode.std.js';
import { itemStorage } from '../../../textsecure/Storage.preload.js';
const { times } = lodash;
@@ -14,6 +14,7 @@ import * as KeyChangeListener from '../../textsecure/KeyChangeListener.dom.js';
import { itemStorage } from '../../textsecure/Storage.preload.js';
import * as Bytes from '../../Bytes.std.js';
import { cleanupMessages } from '../../util/cleanup.preload.js';
import { removeConversation } from '../../util/Conversation.preload.js';
describe('KeyChangeListener', () => {
let oldNumberId: string | undefined;
@@ -71,7 +72,7 @@ describe('KeyChangeListener', () => {
logId: ourServiceIdWithKeyChange,
cleanupMessages,
});
await DataWriter.removeConversation(convo.id);
await removeConversation(convo.id);
await store.removeIdentityKey(ourServiceIdWithKeyChange);
});
@@ -113,7 +114,7 @@ describe('KeyChangeListener', () => {
logId: ourServiceIdWithKeyChange,
cleanupMessages,
});
await DataWriter.removeConversation(groupConvo.id);
await removeConversation(groupConvo.id);
});
it('generates a key change notice in the group conversation with this contact', async () => {
+2 -1
View File
@@ -38,7 +38,7 @@ import {
SenderKeys,
Sessions,
SignedPreKeys,
} from '../LibSignalStores.preload.js';
} from '../LibSignalStores.node.js';
import { createName } from '../util/attachmentPath.node.js';
import { assertDev, strictAssert } from '../util/assert.std.js';
import type { BatcherType } from '../util/batcher.std.js';
@@ -1022,6 +1022,7 @@ export default class MessageReceiver
let stores = storesMap.get(destinationServiceId);
if (!stores) {
const sharedParams = {
signalProtocolStore,
ourServiceId: destinationServiceId,
zone,
};
+9 -3
View File
@@ -45,7 +45,7 @@ import * as Errors from '../types/errors.std.js';
import { HTTPError } from '../types/HTTPError.std.js';
import { QualifiedAddress } from '../types/QualifiedAddress.std.js';
import type { ServiceIdString } from '../types/ServiceId.std.js';
import { Sessions, IdentityKeys } from '../LibSignalStores.preload.js';
import { Sessions, IdentityKeys } from '../LibSignalStores.node.js';
import { getKeysForServiceId } from './getKeysForServiceId.preload.js';
import { SignalService as Proto } from '../protobuf/index.std.js';
import { createLogger } from '../logging/log.std.js';
@@ -438,8 +438,14 @@ export default class OutgoingMessage {
);
}
const sessionStore = new Sessions({ ourServiceId: ourAci });
const identityKeyStore = new IdentityKeys({ ourServiceId: ourAci });
const sessionStore = new Sessions({
signalProtocolStore,
ourServiceId: ourAci,
});
const identityKeyStore = new IdentityKeys({
signalProtocolStore,
ourServiceId: ourAci,
});
return Promise.all(
deviceIds.map(async destinationDeviceId => {
+2 -1
View File
@@ -27,7 +27,7 @@ import { uuidToBytes } from '../util/uuidToBytes.std.js';
import { Address } from '../types/Address.std.js';
import { QualifiedAddress } from '../types/QualifiedAddress.std.js';
import type { StoryMessageRecipientsType } from '../types/Stories.std.js';
import { SenderKeys } from '../LibSignalStores.preload.js';
import { SenderKeys } from '../LibSignalStores.node.js';
import type {
TextAttachmentType,
UploadedAttachmentType,
@@ -2722,6 +2722,7 @@ export class MessageSender {
const senderKeyDistributionMessage =
await signalProtocolStore.enqueueSenderKeyJob(address, async () => {
const senderKeyStore = new SenderKeys({
signalProtocolStore,
ourServiceId: ourAci,
zone: GLOBAL_ZONE,
});
+4 -3
View File
@@ -129,7 +129,8 @@ import {
type RemoteMegaphoneId,
} from '../types/Megaphone.std.js';
import { bindRemoteConfigToLibsignalNet } from '../LibsignalNetRemoteConfig.preload.js';
import { KeyTransparencyStore } from '../LibSignalStores.preload.js';
import { KeyTransparencyStore } from '../LibSignalStores.node.js';
import { signalProtocolStore } from '../SignalProtocolStore.preload.js';
const { escapeRegExp, isNumber, throttle } = lodash;
@@ -2501,7 +2502,7 @@ export async function keyTransparencySearch(
throw new Error('Aborted');
}
const kt = chat.keyTransparencyClient();
const store = new KeyTransparencyStore();
const store = new KeyTransparencyStore(signalProtocolStore);
return kt.search(request, store, { abortSignal });
});
}
@@ -2517,7 +2518,7 @@ export async function keyTransparencyMonitor(
throw new Error('Aborted');
}
const kt = chat.keyTransparencyClient();
const store = new KeyTransparencyStore();
const store = new KeyTransparencyStore(signalProtocolStore);
return kt.monitor(
{
...request,
+9 -3
View File
@@ -15,7 +15,7 @@ import {
OutgoingIdentityKeyError,
UnregisteredUserError,
} from './Errors.std.js';
import { Sessions, IdentityKeys } from '../LibSignalStores.preload.js';
import { Sessions, IdentityKeys } from '../LibSignalStores.node.js';
import { Address } from '../types/Address.std.js';
import { QualifiedAddress } from '../types/QualifiedAddress.std.js';
import type { ServiceIdString } from '../types/ServiceId.std.js';
@@ -133,8 +133,14 @@ async function handleServerKeys(
devicesToUpdate: Array<number> | null
): Promise<void> {
const ourAci = itemStorage.user.getCheckedAci();
const sessionStore = new Sessions({ ourServiceId: ourAci });
const identityKeyStore = new IdentityKeys({ ourServiceId: ourAci });
const sessionStore = new Sessions({
signalProtocolStore,
ourServiceId: ourAci,
});
const identityKeyStore = new IdentityKeys({
signalProtocolStore,
ourServiceId: ourAci,
});
await Promise.all(
response.devices.map(async device => {
-29
View File
@@ -1,29 +0,0 @@
// Copyright 2018 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { ConversationAttributesType } from '../model-types.d.ts';
export async function deleteExternalFiles(
conversation: ConversationAttributesType,
{
maybeDeleteAttachmentFile,
}: {
maybeDeleteAttachmentFile: (
path: string
) => Promise<{ wasDeleted: boolean }>;
}
): Promise<void> {
if (!conversation) {
return;
}
const { avatar, profileAvatar } = conversation;
if (avatar && avatar.path) {
await maybeDeleteAttachmentFile(avatar.path);
}
if (profileAvatar && profileAvatar.path) {
await maybeDeleteAttachmentFile(profileAvatar.path);
}
}
-33
View File
@@ -56,14 +56,6 @@ import { deepClone } from '../util/deepClone.std.js';
import * as Bytes from '../Bytes.std.js';
import { isBodyTooLong } from '../util/longAttachment.std.js';
import type { MessageAttachmentType } from './AttachmentDownload.std.js';
import {
getFilePathsReferencedByAttachment,
getFilePathsReferencedByMessage,
} from '../util/messageFilePaths.std.js';
import {
deleteDownloadFile,
maybeDeleteAttachmentFile,
} from '../util/migrations.preload.js';
import type { getExistingAttachmentDataForReuse } from '../util/attachments/deduplicateAttachment.preload.js';
import type { getPlaintextHashForInMemoryAttachment } from '../AttachmentCrypto.node.js';
import { strictAssert } from '../util/assert.std.js';
@@ -1050,31 +1042,6 @@ export const loadStickerData = (
};
};
export const cleanupAllMessageAttachmentFiles = async (
message: MessageAttributesType
): Promise<void> => {
const { externalAttachments, externalDownloads } =
getFilePathsReferencedByMessage(message);
await Promise.all(
[...externalAttachments].map(attachmentPath =>
maybeDeleteAttachmentFile(attachmentPath)
)
);
await Promise.all(
[...externalDownloads].map(downloadPath => deleteDownloadFile(downloadPath))
);
};
export async function cleanupAttachmentFiles(
attachment: AttachmentType
): Promise<void> {
const result = getFilePathsReferencedByAttachment(attachment);
await Promise.all(
[...result.externalAttachments].map(maybeDeleteAttachmentFile)
);
await Promise.all([...result.externalDownloads].map(deleteDownloadFile));
}
export async function migrateBodyAttachmentToDisk(
message: MessageAttributesType,
{ logger, writeNewAttachmentData }: ContextType
+35
View File
@@ -0,0 +1,35 @@
// Copyright 2018 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { DataReader, DataWriter } from '../sql/Client.preload.js';
import type { ConversationAttributesType } from '../model-types.d.ts';
import { maybeDeleteAttachmentFile } from './migrations.preload.js';
async function deleteExternalFiles(
conversation: ConversationAttributesType
): Promise<void> {
if (!conversation) {
return;
}
const { avatar, profileAvatar } = conversation;
if (avatar && avatar.path) {
await maybeDeleteAttachmentFile(avatar.path);
}
if (profileAvatar && profileAvatar.path) {
await maybeDeleteAttachmentFile(profileAvatar.path);
}
}
export async function removeConversation(id: string): Promise<void> {
const existing = await DataReader.getConversationById(id);
// Note: It's important to have a fully database-hydrated model to delete here because
// it needs to delete all associated on-disk files along with the database delete.
if (existing) {
await DataWriter._removeConversation(id);
await deleteExternalFiles(existing);
}
}
+34 -1
View File
@@ -26,12 +26,20 @@ import { getMessageIdForLogging } from './idForLogging.preload.js';
import { singleProtoJobQueue } from '../jobs/singleProtoJobQueue.preload.js';
import { MINUTE } from './durations/index.std.js';
import { drop } from './drop.std.js';
import {
getFilePathsReferencedByAttachment,
getFilePathsReferencedByMessage,
} from './messageFilePaths.std.js';
import {
deleteDownloadFile,
maybeDeleteAttachmentFile,
} from './migrations.preload.js';
import { hydrateStoryContext } from './hydrateStoryContext.preload.js';
import { update as updateExpiringMessagesService } from '../services/expiringMessagesDeletion.preload.js';
import { tapToViewMessagesDeletionService } from '../services/tapToViewMessagesDeletionService.preload.js';
import { throttledUpdateBackupMediaDownloadProgress } from './updateBackupMediaDownloadProgress.preload.js';
import { messageAttrsToPreserveAfterErase } from '../types/Message.std.js';
import { cleanupAllMessageAttachmentFiles } from '../types/Message2.preload.js';
import type { AttachmentType } from '../types/Attachment.std.js';
const log = createLogger('cleanup');
@@ -281,3 +289,28 @@ export async function maybeDeleteCall(
await DataWriter.markCallHistoryDeleted(callId);
window.reduxActions.callHistory.removeCallHistory(callId);
}
export const cleanupAllMessageAttachmentFiles = async (
message: MessageAttributesType
): Promise<void> => {
const { externalAttachments, externalDownloads } =
getFilePathsReferencedByMessage(message);
await Promise.all(
[...externalAttachments].map(attachmentPath =>
maybeDeleteAttachmentFile(attachmentPath)
)
);
await Promise.all(
[...externalDownloads].map(downloadPath => deleteDownloadFile(downloadPath))
);
};
export async function cleanupAttachmentFiles(
attachment: AttachmentType
): Promise<void> {
const result = getFilePathsReferencedByAttachment(attachment);
await Promise.all(
[...result.externalAttachments].map(maybeDeleteAttachmentFile)
);
await Promise.all([...result.externalDownloads].map(deleteDownloadFile));
}
+5 -2
View File
@@ -11,13 +11,16 @@ import type { ConversationModel } from '../models/conversations.preload.js';
import type { AddressableMessage } from '../textsecure/messageReceiverEvents.std.js';
import type { AttachmentType } from '../types/Attachment.std.js';
import { MessageModel } from '../models/messages.preload.js';
import { cleanupMessages, postSaveUpdates } from './cleanup.preload.js';
import {
cleanupMessages,
cleanupAttachmentFiles,
postSaveUpdates,
} from './cleanup.preload.js';
import {
findMatchingMessage,
getMessageQueryFromTarget,
} from './syncIdentifiers.preload.js';
import { itemStorage } from '../textsecure/Storage.preload.js';
import { cleanupAttachmentFiles } from '../types/Message2.preload.js';
const { last, sortBy } = lodash;
+28
View File
@@ -0,0 +1,28 @@
// Copyright 2026 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { ConversationType } from '../state/ducks/conversations.preload.js';
import { CallMode } from '../types/CallDisposition.std.js';
export const getConversationCallMode = (
conversation: ConversationType
): CallMode | null => {
if (
conversation.left ||
conversation.isBlocked ||
conversation.isMe ||
!conversation.acceptedMessageRequest
) {
return null;
}
if (conversation.type === 'direct') {
return CallMode.Direct;
}
if (conversation.type === 'group' && conversation.groupVersion === 2) {
return CallMode.Group;
}
return null;
};
+10 -7
View File
@@ -53,11 +53,7 @@ import {
UnknownRecipientError,
UnregisteredUserError,
} from '../textsecure/Errors.std.js';
import {
IdentityKeys,
SenderKeys,
Sessions,
} from '../LibSignalStores.preload.js';
import { IdentityKeys, SenderKeys, Sessions } from '../LibSignalStores.node.js';
import type { ConversationModel } from '../models/conversations.preload.js';
import type { DeviceType, CallbackResultType } from '../textsecure/Types.d.ts';
import { getKeysForServiceId } from '../textsecure/getKeysForServiceId.preload.js';
@@ -1297,6 +1293,7 @@ async function encryptForSenderKey({
);
const ourAddress = getOurAddress();
const senderKeyStore = new SenderKeys({
signalProtocolStore,
ourServiceId: ourAci,
zone: GLOBAL_ZONE,
});
@@ -1341,8 +1338,14 @@ async function encryptForSenderKey({
.map(device => {
return ProtocolAddress.new(device.serviceId, device.id);
});
const identityKeyStore = new IdentityKeys({ ourServiceId: ourAci });
const sessionStore = new Sessions({ ourServiceId: ourAci });
const identityKeyStore = new IdentityKeys({
signalProtocolStore,
ourServiceId: ourAci,
});
const sessionStore = new Sessions({
signalProtocolStore,
ourServiceId: ourAci,
});
return sealedSenderMultiRecipientEncrypt(
content,
recipients,