Handle and send isRecipientUpdate sync messages
* Handle and send isRecipientUpdate sync messages * Disable sending isRecipientUpdates for now
This commit is contained in:
parent
8c365b1a3a
commit
13ad4abaea
5 changed files with 128 additions and 56 deletions
152
js/background.js
152
js/background.js
|
@ -3,6 +3,7 @@
|
||||||
_,
|
_,
|
||||||
Backbone,
|
Backbone,
|
||||||
ConversationController,
|
ConversationController,
|
||||||
|
MessageController,
|
||||||
getAccountManager,
|
getAccountManager,
|
||||||
Signal,
|
Signal,
|
||||||
storage,
|
storage,
|
||||||
|
@ -1134,40 +1135,6 @@
|
||||||
? getGroupDescriptor(message.group)
|
? getGroupDescriptor(message.group)
|
||||||
: { type: Message.PRIVATE, id: source };
|
: { type: Message.PRIVATE, id: source };
|
||||||
|
|
||||||
function createMessageHandler({
|
|
||||||
createMessage,
|
|
||||||
getMessageDescriptor,
|
|
||||||
handleProfileUpdate,
|
|
||||||
}) {
|
|
||||||
return async event => {
|
|
||||||
const { data, confirm } = event;
|
|
||||||
|
|
||||||
const messageDescriptor = getMessageDescriptor(data);
|
|
||||||
|
|
||||||
const { PROFILE_KEY_UPDATE } = textsecure.protobuf.DataMessage.Flags;
|
|
||||||
// eslint-disable-next-line no-bitwise
|
|
||||||
const isProfileUpdate = Boolean(data.message.flags & PROFILE_KEY_UPDATE);
|
|
||||||
if (isProfileUpdate) {
|
|
||||||
return handleProfileUpdate({ data, confirm, messageDescriptor });
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = await createMessage(data);
|
|
||||||
const isDuplicate = await isMessageDuplicate(message);
|
|
||||||
if (isDuplicate) {
|
|
||||||
window.log.warn('Received duplicate message', message.idForLogging());
|
|
||||||
return event.confirm();
|
|
||||||
}
|
|
||||||
|
|
||||||
await ConversationController.getOrCreateAndWait(
|
|
||||||
messageDescriptor.id,
|
|
||||||
messageDescriptor.type
|
|
||||||
);
|
|
||||||
return message.handleDataMessage(data.message, event.confirm, {
|
|
||||||
initialLoadComplete,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Received:
|
// Received:
|
||||||
async function handleMessageReceivedProfileUpdate({
|
async function handleMessageReceivedProfileUpdate({
|
||||||
data,
|
data,
|
||||||
|
@ -1186,11 +1153,37 @@
|
||||||
return confirm();
|
return confirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
const onMessageReceived = createMessageHandler({
|
async function onMessageReceived(event) {
|
||||||
handleProfileUpdate: handleMessageReceivedProfileUpdate,
|
const { data, confirm } = event;
|
||||||
getMessageDescriptor: getDescriptorForReceived,
|
|
||||||
createMessage: initIncomingMessage,
|
const messageDescriptor = getDescriptorForReceived(data);
|
||||||
|
|
||||||
|
const { PROFILE_KEY_UPDATE } = textsecure.protobuf.DataMessage.Flags;
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
const isProfileUpdate = Boolean(data.message.flags & PROFILE_KEY_UPDATE);
|
||||||
|
if (isProfileUpdate) {
|
||||||
|
return handleMessageReceivedProfileUpdate({
|
||||||
|
data,
|
||||||
|
confirm,
|
||||||
|
messageDescriptor,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = await initIncomingMessage(data);
|
||||||
|
const isDuplicate = await isMessageDuplicate(message);
|
||||||
|
if (isDuplicate) {
|
||||||
|
window.log.warn('Received duplicate message', message.idForLogging());
|
||||||
|
return event.confirm();
|
||||||
|
}
|
||||||
|
|
||||||
|
await ConversationController.getOrCreateAndWait(
|
||||||
|
messageDescriptor.id,
|
||||||
|
messageDescriptor.type
|
||||||
|
);
|
||||||
|
return message.handleDataMessage(data.message, event.confirm, {
|
||||||
|
initialLoadComplete,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Sent:
|
// Sent:
|
||||||
async function handleMessageSentProfileUpdate({
|
async function handleMessageSentProfileUpdate({
|
||||||
|
@ -1251,26 +1244,93 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSentMessage = createMessageHandler({
|
async function onSentMessage(event) {
|
||||||
handleProfileUpdate: handleMessageSentProfileUpdate,
|
const { data, confirm } = event;
|
||||||
getMessageDescriptor: getDescriptorForSent,
|
|
||||||
createMessage: createSentMessage,
|
|
||||||
});
|
|
||||||
|
|
||||||
async function isMessageDuplicate(message) {
|
const messageDescriptor = getDescriptorForSent(data);
|
||||||
|
|
||||||
|
const { PROFILE_KEY_UPDATE } = textsecure.protobuf.DataMessage.Flags;
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
const isProfileUpdate = Boolean(data.message.flags & PROFILE_KEY_UPDATE);
|
||||||
|
if (isProfileUpdate) {
|
||||||
|
await handleMessageSentProfileUpdate({
|
||||||
|
data,
|
||||||
|
confirm,
|
||||||
|
messageDescriptor,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = await createSentMessage(data);
|
||||||
|
const existing = await getExistingMessage(message);
|
||||||
|
const isUpdate = Boolean(data.isRecipientUpdate);
|
||||||
|
|
||||||
|
if (isUpdate && existing) {
|
||||||
|
event.confirm();
|
||||||
|
|
||||||
|
let sentTo = [];
|
||||||
|
let unidentifiedDeliveries = [];
|
||||||
|
if (Array.isArray(data.unidentifiedStatus)) {
|
||||||
|
sentTo = data.unidentifiedStatus.map(item => item.destination);
|
||||||
|
|
||||||
|
const unidentified = _.filter(data.unidentifiedStatus, item =>
|
||||||
|
Boolean(item.unidentified)
|
||||||
|
);
|
||||||
|
unidentifiedDeliveries = unidentified.map(item => item.destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
existing.set({
|
||||||
|
sent_to: _.union(existing.get('sent_to'), sentTo),
|
||||||
|
unidentifiedDeliveries: _.union(
|
||||||
|
existing.get('unidentifiedDeliveries'),
|
||||||
|
unidentifiedDeliveries
|
||||||
|
),
|
||||||
|
});
|
||||||
|
await window.Signal.Data.saveMessage(existing.attributes, {
|
||||||
|
Message: Whisper.Message,
|
||||||
|
});
|
||||||
|
} else if (isUpdate) {
|
||||||
|
window.log.warn(
|
||||||
|
`onSentMessage: Received update transcript, but no existing entry for message ${message.idForLogging()}. Dropping.`
|
||||||
|
);
|
||||||
|
} else if (existing) {
|
||||||
|
window.log.warn(
|
||||||
|
`onSentMessage: Received duplicate transcript for message ${message.idForLogging()}, but it was not an update transcript. Dropping.`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await ConversationController.getOrCreateAndWait(
|
||||||
|
messageDescriptor.id,
|
||||||
|
messageDescriptor.type
|
||||||
|
);
|
||||||
|
await message.handleDataMessage(data.message, event.confirm, {
|
||||||
|
initialLoadComplete,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getExistingMessage(message) {
|
||||||
try {
|
try {
|
||||||
const { attributes } = message;
|
const { attributes } = message;
|
||||||
const result = await window.Signal.Data.getMessageBySender(attributes, {
|
const result = await window.Signal.Data.getMessageBySender(attributes, {
|
||||||
Message: Whisper.Message,
|
Message: Whisper.Message,
|
||||||
});
|
});
|
||||||
|
|
||||||
return Boolean(result);
|
if (result) {
|
||||||
|
return MessageController.register(result.id, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
window.log.error('isMessageDuplicate error:', Errors.toLogFormat(error));
|
window.log.error('getExistingMessage error:', Errors.toLogFormat(error));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function isMessageDuplicate(message) {
|
||||||
|
const result = await getExistingMessage(message);
|
||||||
|
return Boolean(result);
|
||||||
|
}
|
||||||
|
|
||||||
async function initIncomingMessage(data, options = {}) {
|
async function initIncomingMessage(data, options = {}) {
|
||||||
const { isError } = options;
|
const { isError } = options;
|
||||||
|
|
||||||
|
|
|
@ -1113,7 +1113,7 @@
|
||||||
this.trigger('done');
|
this.trigger('done');
|
||||||
|
|
||||||
// This is used by sendSyncMessage, then set to null
|
// This is used by sendSyncMessage, then set to null
|
||||||
if (!this.get('synced') && result.dataMessage) {
|
if (result.dataMessage) {
|
||||||
this.set({ dataMessage: result.dataMessage });
|
this.set({ dataMessage: result.dataMessage });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1244,9 +1244,16 @@
|
||||||
this.syncPromise = this.syncPromise || Promise.resolve();
|
this.syncPromise = this.syncPromise || Promise.resolve();
|
||||||
const next = () => {
|
const next = () => {
|
||||||
const dataMessage = this.get('dataMessage');
|
const dataMessage = this.get('dataMessage');
|
||||||
if (this.get('synced') || !dataMessage) {
|
if (!dataMessage) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
const isUpdate = Boolean(this.get('synced'));
|
||||||
|
|
||||||
|
// Until isRecipientUpdate sync messages are widely supported, will not send them
|
||||||
|
if (isUpdate) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
return wrap(
|
return wrap(
|
||||||
textsecure.messaging.sendSyncMessage(
|
textsecure.messaging.sendSyncMessage(
|
||||||
dataMessage,
|
dataMessage,
|
||||||
|
@ -1255,6 +1262,7 @@
|
||||||
this.get('expirationStartTimestamp'),
|
this.get('expirationStartTimestamp'),
|
||||||
this.get('sent_to'),
|
this.get('sent_to'),
|
||||||
this.get('unidentifiedDeliveries'),
|
this.get('unidentifiedDeliveries'),
|
||||||
|
isUpdate,
|
||||||
sendOptions
|
sendOptions
|
||||||
)
|
)
|
||||||
).then(result => {
|
).then(result => {
|
||||||
|
|
|
@ -865,12 +865,14 @@ MessageReceiver.prototype.extend({
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleSentMessage(envelope, sentContainer, msg) {
|
handleSentMessage(envelope, sentContainer) {
|
||||||
const {
|
const {
|
||||||
destination,
|
destination,
|
||||||
timestamp,
|
timestamp,
|
||||||
|
message: msg,
|
||||||
expirationStartTimestamp,
|
expirationStartTimestamp,
|
||||||
unidentifiedStatus,
|
unidentifiedStatus,
|
||||||
|
isRecipientUpdate,
|
||||||
} = sentContainer;
|
} = sentContainer;
|
||||||
|
|
||||||
let p = Promise.resolve();
|
let p = Promise.resolve();
|
||||||
|
@ -905,6 +907,7 @@ MessageReceiver.prototype.extend({
|
||||||
device: envelope.sourceDevice,
|
device: envelope.sourceDevice,
|
||||||
unidentifiedStatus,
|
unidentifiedStatus,
|
||||||
message,
|
message,
|
||||||
|
isRecipientUpdate,
|
||||||
};
|
};
|
||||||
if (expirationStartTimestamp) {
|
if (expirationStartTimestamp) {
|
||||||
ev.data.expirationStartTimestamp = expirationStartTimestamp.toNumber();
|
ev.data.expirationStartTimestamp = expirationStartTimestamp.toNumber();
|
||||||
|
@ -1090,7 +1093,7 @@ MessageReceiver.prototype.extend({
|
||||||
'from',
|
'from',
|
||||||
this.getEnvelopeId(envelope)
|
this.getEnvelopeId(envelope)
|
||||||
);
|
);
|
||||||
return this.handleSentMessage(envelope, sentMessage, sentMessage.message);
|
return this.handleSentMessage(envelope, sentMessage);
|
||||||
} else if (syncMessage.contacts) {
|
} else if (syncMessage.contacts) {
|
||||||
return this.handleContacts(envelope, syncMessage.contacts);
|
return this.handleContacts(envelope, syncMessage.contacts);
|
||||||
} else if (syncMessage.groups) {
|
} else if (syncMessage.groups) {
|
||||||
|
|
|
@ -23,7 +23,6 @@ function Message(options) {
|
||||||
this.flags = options.flags;
|
this.flags = options.flags;
|
||||||
this.recipients = options.recipients;
|
this.recipients = options.recipients;
|
||||||
this.timestamp = options.timestamp;
|
this.timestamp = options.timestamp;
|
||||||
this.needsSync = options.needsSync;
|
|
||||||
this.expireTimer = options.expireTimer;
|
this.expireTimer = options.expireTimer;
|
||||||
this.profileKey = options.profileKey;
|
this.profileKey = options.profileKey;
|
||||||
|
|
||||||
|
@ -438,6 +437,7 @@ MessageSender.prototype = {
|
||||||
expirationStartTimestamp,
|
expirationStartTimestamp,
|
||||||
sentTo = [],
|
sentTo = [],
|
||||||
unidentifiedDeliveries = [],
|
unidentifiedDeliveries = [],
|
||||||
|
isUpdate = false,
|
||||||
options
|
options
|
||||||
) {
|
) {
|
||||||
const myNumber = textsecure.storage.user.getNumber();
|
const myNumber = textsecure.storage.user.getNumber();
|
||||||
|
@ -468,6 +468,10 @@ MessageSender.prototype = {
|
||||||
Object.create(null)
|
Object.create(null)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isUpdate) {
|
||||||
|
syncMessage.isRecipientUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Though this field has 'unidenified' in the name, it should have entries for each
|
// Though this field has 'unidenified' in the name, it should have entries for each
|
||||||
// number we sent to.
|
// number we sent to.
|
||||||
if (sentTo && sentTo.length) {
|
if (sentTo && sentTo.length) {
|
||||||
|
@ -841,7 +845,6 @@ MessageSender.prototype = {
|
||||||
attachments,
|
attachments,
|
||||||
quote,
|
quote,
|
||||||
preview,
|
preview,
|
||||||
needsSync: true,
|
|
||||||
expireTimer,
|
expireTimer,
|
||||||
profileKey,
|
profileKey,
|
||||||
},
|
},
|
||||||
|
@ -939,7 +942,6 @@ MessageSender.prototype = {
|
||||||
attachments,
|
attachments,
|
||||||
quote,
|
quote,
|
||||||
preview,
|
preview,
|
||||||
needsSync: true,
|
|
||||||
expireTimer,
|
expireTimer,
|
||||||
profileKey,
|
profileKey,
|
||||||
group: {
|
group: {
|
||||||
|
@ -1054,7 +1056,6 @@ MessageSender.prototype = {
|
||||||
const attrs = {
|
const attrs = {
|
||||||
recipients: numbers,
|
recipients: numbers,
|
||||||
timestamp,
|
timestamp,
|
||||||
needsSync: true,
|
|
||||||
expireTimer,
|
expireTimer,
|
||||||
profileKey,
|
profileKey,
|
||||||
flags: textsecure.protobuf.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
|
flags: textsecure.protobuf.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
|
||||||
|
@ -1087,7 +1088,6 @@ MessageSender.prototype = {
|
||||||
{
|
{
|
||||||
recipients: [number],
|
recipients: [number],
|
||||||
timestamp,
|
timestamp,
|
||||||
needsSync: true,
|
|
||||||
expireTimer,
|
expireTimer,
|
||||||
profileKey,
|
profileKey,
|
||||||
flags: textsecure.protobuf.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
|
flags: textsecure.protobuf.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
|
||||||
|
|
|
@ -224,6 +224,7 @@ message SyncMessage {
|
||||||
optional DataMessage message = 3;
|
optional DataMessage message = 3;
|
||||||
optional uint64 expirationStartTimestamp = 4;
|
optional uint64 expirationStartTimestamp = 4;
|
||||||
repeated UnidentifiedDeliveryStatus unidentifiedStatus = 5;
|
repeated UnidentifiedDeliveryStatus unidentifiedStatus = 5;
|
||||||
|
optional bool isRecipientUpdate = 6 [default = false];
|
||||||
}
|
}
|
||||||
|
|
||||||
message Contacts {
|
message Contacts {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue