Use other sync messages for conversations missing ACI
This commit is contained in:
parent
fd0ee8ecae
commit
c279108c75
4 changed files with 224 additions and 93 deletions
|
|
@ -220,6 +220,8 @@ import {
|
||||||
import { markFailed } from '../../test-node/util/messageFailures';
|
import { markFailed } from '../../test-node/util/messageFailures';
|
||||||
import { cleanupMessages } from '../../util/cleanup';
|
import { cleanupMessages } from '../../util/cleanup';
|
||||||
import { MessageModel } from '../../models/messages';
|
import { MessageModel } from '../../models/messages';
|
||||||
|
import type { ConversationModel } from '../../models/conversations';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
export type DBConversationType = ReadonlyDeep<{
|
export type DBConversationType = ReadonlyDeep<{
|
||||||
|
|
@ -3579,17 +3581,10 @@ function revokePendingMembershipsFromGroupV2(
|
||||||
}
|
}
|
||||||
|
|
||||||
async function syncMessageRequestResponse(
|
async function syncMessageRequestResponse(
|
||||||
conversationData: ConversationType,
|
conversation: ConversationModel,
|
||||||
response: Proto.SyncMessage.MessageRequestResponse.Type,
|
response: Proto.SyncMessage.MessageRequestResponse.Type,
|
||||||
{ shouldSave = true } = {}
|
{ shouldSave = true } = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const conversation = window.ConversationController.get(conversationData.id);
|
|
||||||
if (!conversation) {
|
|
||||||
throw new Error(
|
|
||||||
`syncMessageRequestResponse: No conversation found for conversation ${conversationData.id}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// In GroupsV2, this may modify the server. We only want to continue if those
|
// In GroupsV2, this may modify the server. We only want to continue if those
|
||||||
// server updates were successful.
|
// server updates were successful.
|
||||||
await conversation.applyMessageRequestResponse(response, { shouldSave });
|
await conversation.applyMessageRequestResponse(response, { shouldSave });
|
||||||
|
|
@ -3603,11 +3598,18 @@ async function syncMessageRequestResponse(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const threadAci = conversation.getAci();
|
||||||
|
if (!threadAci) {
|
||||||
|
log.warn(
|
||||||
|
'syncMessageRequestResponse: No ACI for target conversation, not sending'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await singleProtoJobQueue.add(
|
await singleProtoJobQueue.add(
|
||||||
MessageSender.getMessageRequestResponseSync({
|
MessageSender.getMessageRequestResponseSync({
|
||||||
threadE164: conversation.get('e164'),
|
threadAci,
|
||||||
threadAci: conversation.getAci(),
|
|
||||||
groupId,
|
groupId,
|
||||||
type: response,
|
type: response,
|
||||||
})
|
})
|
||||||
|
|
@ -3651,7 +3653,13 @@ function reportSpam(
|
||||||
}
|
}
|
||||||
|
|
||||||
const conversation = getConversationForReportSpam(conversationOrGroup);
|
const conversation = getConversationForReportSpam(conversationOrGroup);
|
||||||
if (conversation == null) {
|
const conversationModel = window.ConversationController.get(
|
||||||
|
conversation?.id
|
||||||
|
);
|
||||||
|
if (!conversation || !conversationModel) {
|
||||||
|
log.error(
|
||||||
|
`reportSpam: Conversation for report spam not found ${conversation?.id}. Doing nothing.`
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3664,7 +3672,10 @@ function reportSpam(
|
||||||
idForLogging,
|
idForLogging,
|
||||||
task: async () => {
|
task: async () => {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
syncMessageRequestResponse(conversation, messageRequestEnum.SPAM),
|
syncMessageRequestResponse(
|
||||||
|
conversationModel,
|
||||||
|
messageRequestEnum.SPAM
|
||||||
|
),
|
||||||
addReportSpamJob({
|
addReportSpamJob({
|
||||||
conversation,
|
conversation,
|
||||||
getMessageServerGuidsForSpam:
|
getMessageServerGuidsForSpam:
|
||||||
|
|
@ -3700,68 +3711,112 @@ function blockAndReportSpam(
|
||||||
|
|
||||||
const conversationForSpam =
|
const conversationForSpam =
|
||||||
getConversationForReportSpam(conversationOrGroup);
|
getConversationForReportSpam(conversationOrGroup);
|
||||||
|
const conversationModel = window.ConversationController.get(
|
||||||
|
conversationForSpam?.id
|
||||||
|
);
|
||||||
|
if (!conversationForSpam || !conversationModel) {
|
||||||
|
log.error(
|
||||||
|
`reportSpam: Conversation for report spam not found ${conversationForSpam?.id}. Doing nothing.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
|
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
|
||||||
const idForLogging = getConversationIdForLogging(conversationOrGroup);
|
const idForLogging = getConversationIdForLogging(conversationOrGroup);
|
||||||
|
|
||||||
drop(
|
if (conversationModel.getAci()) {
|
||||||
longRunningTaskWrapper({
|
drop(
|
||||||
name: 'blockAndReportSpam',
|
longRunningTaskWrapper({
|
||||||
idForLogging,
|
name: 'blockAndReportSpam',
|
||||||
task: async () => {
|
idForLogging,
|
||||||
await Promise.all([
|
task: async () => {
|
||||||
syncMessageRequestResponse(
|
await Promise.all([
|
||||||
conversationOrGroup,
|
syncMessageRequestResponse(
|
||||||
messageRequestEnum.BLOCK_AND_SPAM
|
conversationModel,
|
||||||
),
|
messageRequestEnum.BLOCK_AND_SPAM
|
||||||
conversationForSpam != null &&
|
),
|
||||||
addReportSpamJob({
|
conversationForSpam != null &&
|
||||||
conversation: conversationForSpam,
|
addReportSpamJob({
|
||||||
getMessageServerGuidsForSpam:
|
conversation: conversationForSpam,
|
||||||
DataReader.getMessageServerGuidsForSpam,
|
getMessageServerGuidsForSpam:
|
||||||
jobQueue: reportSpamJobQueue,
|
DataReader.getMessageServerGuidsForSpam,
|
||||||
}),
|
jobQueue: reportSpamJobQueue,
|
||||||
]);
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: SHOW_TOAST,
|
type: SHOW_TOAST,
|
||||||
payload: {
|
payload: {
|
||||||
toastType: ToastType.ReportedSpamAndBlocked,
|
toastType: ToastType.ReportedSpamAndBlocked,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
await singleProtoJobQueue.add(
|
||||||
|
MessageSender.getBlockSync(
|
||||||
|
window.textsecure.storage.blocked.getBlockedData()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
log.error(
|
||||||
|
`blockConversation/${idForLogging}: Failed to queue block sync message`,
|
||||||
|
Errors.toLogFormat(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function acceptConversation(
|
function acceptConversation(
|
||||||
conversationId: string
|
conversationId: string
|
||||||
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
||||||
return async (dispatch, getState) => {
|
return async dispatch => {
|
||||||
const conversationSelector = getConversationSelector(getState());
|
const conversation = window.ConversationController.get(conversationId);
|
||||||
const conversationOrGroup = conversationSelector(conversationId);
|
if (!conversation) {
|
||||||
if (!conversationOrGroup) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'acceptConversation: Expected a conversation to be found. Doing nothing'
|
'acceptConversation: Expected a conversation to be found. Doing nothing'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
|
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
|
||||||
const idForLogging = getConversationIdForLogging(conversationOrGroup);
|
const idForLogging = getConversationIdForLogging(conversation.attributes);
|
||||||
|
|
||||||
drop(
|
if (conversation.getAci()) {
|
||||||
longRunningTaskWrapper({
|
drop(
|
||||||
name: 'acceptConversation',
|
longRunningTaskWrapper({
|
||||||
idForLogging,
|
name: 'acceptConversation',
|
||||||
task: async () => {
|
idForLogging,
|
||||||
await syncMessageRequestResponse(
|
task: async () => {
|
||||||
conversationOrGroup,
|
await syncMessageRequestResponse(
|
||||||
messageRequestEnum.ACCEPT
|
conversation,
|
||||||
);
|
messageRequestEnum.ACCEPT
|
||||||
},
|
);
|
||||||
})
|
},
|
||||||
);
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await conversation.applyMessageRequestResponse(
|
||||||
|
messageRequestEnum.ACCEPT,
|
||||||
|
{
|
||||||
|
shouldSave: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await singleProtoJobQueue.add(
|
||||||
|
MessageSender.getBlockSync(
|
||||||
|
window.textsecure.storage.blocked.getBlockedData()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
log.error(
|
||||||
|
`acceptConversation/${idForLogging}: Failed to queue sync message`,
|
||||||
|
Errors.toLogFormat(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'NOOP',
|
type: 'NOOP',
|
||||||
|
|
@ -3794,10 +3849,8 @@ function removeConversation(conversationId: string): ShowToastActionType {
|
||||||
function blockConversation(
|
function blockConversation(
|
||||||
conversationId: string
|
conversationId: string
|
||||||
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
||||||
return (dispatch, getState) => {
|
return async dispatch => {
|
||||||
const conversationSelector = getConversationSelector(getState());
|
const conversation = window.ConversationController.get(conversationId);
|
||||||
const conversation = conversationSelector(conversationId);
|
|
||||||
|
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'blockConversation: Expected a conversation to be found. Doing nothing'
|
'blockConversation: Expected a conversation to be found. Doing nothing'
|
||||||
|
|
@ -3805,20 +3858,41 @@ function blockConversation(
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
|
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
|
||||||
const idForLogging = getConversationIdForLogging(conversation);
|
const idForLogging = getConversationIdForLogging(conversation.attributes);
|
||||||
|
|
||||||
drop(
|
if (conversation.getAci()) {
|
||||||
longRunningTaskWrapper({
|
drop(
|
||||||
name: 'blockConversation',
|
longRunningTaskWrapper({
|
||||||
idForLogging,
|
name: 'blockConversation',
|
||||||
task: async () => {
|
idForLogging,
|
||||||
await syncMessageRequestResponse(
|
task: async () => {
|
||||||
conversation,
|
await syncMessageRequestResponse(
|
||||||
messageRequestEnum.BLOCK
|
conversation,
|
||||||
);
|
messageRequestEnum.BLOCK
|
||||||
},
|
);
|
||||||
})
|
},
|
||||||
);
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// In GroupsV2, this may modify the server. We only want to continue if those
|
||||||
|
// server updates were successful.
|
||||||
|
await conversation.applyMessageRequestResponse(messageRequestEnum.BLOCK, {
|
||||||
|
shouldSave: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await singleProtoJobQueue.add(
|
||||||
|
MessageSender.getBlockSync(
|
||||||
|
window.textsecure.storage.blocked.getBlockedData()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
log.error(
|
||||||
|
`blockConversation/${idForLogging}: Failed to queue block sync message`,
|
||||||
|
Errors.toLogFormat(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'NOOP',
|
type: 'NOOP',
|
||||||
|
|
@ -3830,9 +3904,8 @@ function blockConversation(
|
||||||
function deleteConversation(
|
function deleteConversation(
|
||||||
conversationId: string
|
conversationId: string
|
||||||
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
||||||
return (dispatch, getState) => {
|
return async dispatch => {
|
||||||
const conversationSelector = getConversationSelector(getState());
|
const conversation = window.ConversationController.get(conversationId);
|
||||||
const conversation = conversationSelector(conversationId);
|
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'deleteConversation: Expected a conversation to be found. Doing nothing'
|
'deleteConversation: Expected a conversation to be found. Doing nothing'
|
||||||
|
|
@ -3840,20 +3913,24 @@ function deleteConversation(
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
|
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
|
||||||
const idForLogging = getConversationIdForLogging(conversation);
|
const idForLogging = getConversationIdForLogging(conversation.attributes);
|
||||||
|
|
||||||
drop(
|
if (conversation.getAci()) {
|
||||||
longRunningTaskWrapper({
|
drop(
|
||||||
name: 'deleteConversation',
|
longRunningTaskWrapper({
|
||||||
idForLogging,
|
name: 'deleteConversation',
|
||||||
task: async () => {
|
idForLogging,
|
||||||
await syncMessageRequestResponse(
|
task: async () => {
|
||||||
conversation,
|
await syncMessageRequestResponse(
|
||||||
messageRequestEnum.DELETE
|
conversation,
|
||||||
);
|
messageRequestEnum.DELETE
|
||||||
},
|
);
|
||||||
})
|
},
|
||||||
);
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await conversation.destroyMessages({ source: 'local-delete' });
|
||||||
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'NOOP',
|
type: 'NOOP',
|
||||||
|
|
|
||||||
|
|
@ -1796,6 +1796,40 @@ export default class MessageSender {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getBlockSync(
|
||||||
|
options: Readonly<{
|
||||||
|
e164s: Array<string>;
|
||||||
|
acis: Array<string>;
|
||||||
|
groupIds: Array<Uint8Array>;
|
||||||
|
}>
|
||||||
|
): SingleProtoJobData {
|
||||||
|
const myAci = window.textsecure.storage.user.getCheckedAci();
|
||||||
|
|
||||||
|
const syncMessage = MessageSender.createSyncMessage();
|
||||||
|
|
||||||
|
const blocked = new Proto.SyncMessage.Blocked();
|
||||||
|
blocked.numbers = options.e164s;
|
||||||
|
blocked.acis = options.acis;
|
||||||
|
blocked.groupIds = options.groupIds;
|
||||||
|
syncMessage.blocked = blocked;
|
||||||
|
|
||||||
|
const contentMessage = new Proto.Content();
|
||||||
|
contentMessage.syncMessage = syncMessage;
|
||||||
|
|
||||||
|
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
|
||||||
|
|
||||||
|
return {
|
||||||
|
contentHint: ContentHint.RESENDABLE,
|
||||||
|
serviceId: myAci,
|
||||||
|
isSyncMessage: true,
|
||||||
|
protoBase64: Bytes.toBase64(
|
||||||
|
Proto.Content.encode(contentMessage).finish()
|
||||||
|
),
|
||||||
|
type: 'blockSync',
|
||||||
|
urgent: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static getMessageRequestResponseSync(
|
static getMessageRequestResponseSync(
|
||||||
options: Readonly<{
|
options: Readonly<{
|
||||||
threadE164?: string;
|
threadE164?: string;
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,11 @@
|
||||||
|
|
||||||
import { without } from 'lodash';
|
import { without } from 'lodash';
|
||||||
|
|
||||||
import type { StorageInterface } from '../../types/Storage.d';
|
|
||||||
import type { ServiceIdString } from '../../types/ServiceId';
|
|
||||||
import * as log from '../../logging/log';
|
import * as log from '../../logging/log';
|
||||||
|
import * as Bytes from '../../Bytes';
|
||||||
|
import { isAciString } from '../../util/isAciString';
|
||||||
|
import type { StorageInterface } from '../../types/Storage.d';
|
||||||
|
import type { AciString, ServiceIdString } from '../../types/ServiceId';
|
||||||
|
|
||||||
export const BLOCKED_NUMBERS_ID = 'blocked';
|
export const BLOCKED_NUMBERS_ID = 'blocked';
|
||||||
export const BLOCKED_UUIDS_ID = 'blocked-uuids';
|
export const BLOCKED_UUIDS_ID = 'blocked-uuids';
|
||||||
|
|
@ -99,4 +101,22 @@ export class Blocked {
|
||||||
log.info(`removing group(${groupId} from blocked list`);
|
log.info(`removing group(${groupId} from blocked list`);
|
||||||
await this.storage.put(BLOCKED_GROUPS_ID, without(groupIds, groupId));
|
await this.storage.put(BLOCKED_GROUPS_ID, without(groupIds, groupId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getBlockedData(): {
|
||||||
|
e164s: Array<string>;
|
||||||
|
acis: Array<AciString>;
|
||||||
|
groupIds: Array<Uint8Array>;
|
||||||
|
} {
|
||||||
|
const e164s = this.getBlockedNumbers();
|
||||||
|
const acis = this.getBlockedServiceIds().filter(item => isAciString(item));
|
||||||
|
const groupIds = this.getBlockedGroups().map(item =>
|
||||||
|
Bytes.fromBase64(item)
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
e164s,
|
||||||
|
acis,
|
||||||
|
groupIds,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,13 +49,13 @@ export const sendTypesEnum = z.enum([
|
||||||
'pniIdentitySyncRequest', // urgent because we need our PNI to be fully functional
|
'pniIdentitySyncRequest', // urgent because we need our PNI to be fully functional
|
||||||
|
|
||||||
// The actual sync messages, which we never send, just receive - non-urgent
|
// The actual sync messages, which we never send, just receive - non-urgent
|
||||||
'blockSync',
|
|
||||||
'configurationSync',
|
'configurationSync',
|
||||||
'contactSync',
|
'contactSync',
|
||||||
'keySync',
|
'keySync',
|
||||||
'pniIdentitySync',
|
'pniIdentitySync',
|
||||||
|
|
||||||
// Syncs, default non-urgent
|
// Syncs, default non-urgent
|
||||||
|
'blockSync',
|
||||||
'deleteForMeSync',
|
'deleteForMeSync',
|
||||||
'fetchLatestManifestSync',
|
'fetchLatestManifestSync',
|
||||||
'fetchLocalProfileSync',
|
'fetchLocalProfileSync',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue