|
|
|
@ -415,21 +415,21 @@
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async acceptFriendRequest() {
|
|
|
|
|
const primaryDevicePubKey = this.attributes.conversationId;
|
|
|
|
|
|
|
|
|
|
if (this.get('friendStatus') !== 'pending') {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const allDevices = await libloki.storage.getAllDevicePubKeysForPrimaryPubKey(
|
|
|
|
|
primaryDevicePubKey
|
|
|
|
|
const devicePubKey = this.get('conversationId');
|
|
|
|
|
const otherDevices = await libloki.storage.getPairedDevicesFor(
|
|
|
|
|
devicePubKey
|
|
|
|
|
);
|
|
|
|
|
const allDevices = [devicePubKey, ...otherDevices];
|
|
|
|
|
|
|
|
|
|
// Set profile name to primary conversation
|
|
|
|
|
let profileName;
|
|
|
|
|
const allConversationsWithUser = allDevices.map(d =>
|
|
|
|
|
ConversationController.get(d)
|
|
|
|
|
);
|
|
|
|
|
const allConversationsWithUser = allDevices
|
|
|
|
|
.map(d => ConversationController.get(d))
|
|
|
|
|
.filter(c => Boolean(c));
|
|
|
|
|
allConversationsWithUser.forEach(conversation => {
|
|
|
|
|
// If we somehow received an old friend request (e.g. after having restored
|
|
|
|
|
// from seed, we won't be able to accept it, we should initiate our own
|
|
|
|
@ -447,6 +447,9 @@
|
|
|
|
|
|
|
|
|
|
// If you don't have a profile name for this device, and profileName is set,
|
|
|
|
|
// add profileName to conversation.
|
|
|
|
|
const primaryDevicePubKey =
|
|
|
|
|
(await window.Signal.Data.getPrimaryDeviceFor(devicePubKey)) ||
|
|
|
|
|
devicePubKey;
|
|
|
|
|
const primaryConversation = allConversationsWithUser.find(
|
|
|
|
|
c => c.id === primaryDevicePubKey
|
|
|
|
|
);
|
|
|
|
@ -471,13 +474,23 @@
|
|
|
|
|
if (this.get('friendStatus') !== 'pending') {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const conversation = this.getConversation();
|
|
|
|
|
|
|
|
|
|
this.set({ friendStatus: 'declined' });
|
|
|
|
|
await window.Signal.Data.saveMessage(this.attributes, {
|
|
|
|
|
Message: Whisper.Message,
|
|
|
|
|
});
|
|
|
|
|
conversation.onDeclineFriendRequest();
|
|
|
|
|
|
|
|
|
|
const devicePubKey = this.attributes.conversationId;
|
|
|
|
|
const otherDevices = await libloki.storage.getPairedDevicesFor(
|
|
|
|
|
devicePubKey
|
|
|
|
|
);
|
|
|
|
|
const allDevices = [devicePubKey, ...otherDevices];
|
|
|
|
|
const allConversationsWithUser = allDevices
|
|
|
|
|
.map(d => ConversationController.get(d))
|
|
|
|
|
.filter(c => Boolean(c));
|
|
|
|
|
allConversationsWithUser.forEach(conversation => {
|
|
|
|
|
conversation.onDeclineFriendRequest();
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
getPropsForFriendRequest() {
|
|
|
|
|
const friendStatus = this.get('friendStatus') || 'pending';
|
|
|
|
@ -2083,6 +2096,7 @@
|
|
|
|
|
return false;
|
|
|
|
|
},
|
|
|
|
|
async handleSessionRequest(source, confirm) {
|
|
|
|
|
window.console.log(`Received SESSION_REQUEST from source: ${source}`);
|
|
|
|
|
window.libloki.api.sendSessionEstablishedMessage(source);
|
|
|
|
|
confirm();
|
|
|
|
|
},
|
|
|
|
@ -2234,11 +2248,10 @@
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const conversation = conversationPrimary;
|
|
|
|
|
|
|
|
|
|
return conversation.queueJob(async () => {
|
|
|
|
|
return conversationPrimary.queueJob(async () => {
|
|
|
|
|
window.log.info(
|
|
|
|
|
`Starting handleDataMessage for message ${message.idForLogging()} in conversation ${conversation.idForLogging()}`
|
|
|
|
|
`Starting handleDataMessage for message ${message.idForLogging()} in conversation ${conversationPrimary.idForLogging()}`
|
|
|
|
|
);
|
|
|
|
|
const GROUP_TYPES = textsecure.protobuf.GroupContext.Type;
|
|
|
|
|
const type = message.get('type');
|
|
|
|
@ -2251,7 +2264,7 @@
|
|
|
|
|
try {
|
|
|
|
|
const now = new Date().getTime();
|
|
|
|
|
let attributes = {
|
|
|
|
|
...conversation.attributes,
|
|
|
|
|
...conversationPrimary.attributes,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (dataMessage.group) {
|
|
|
|
@ -2269,18 +2282,18 @@
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
groupUpdate =
|
|
|
|
|
conversation.changedAttributes(
|
|
|
|
|
conversationPrimary.changedAttributes(
|
|
|
|
|
_.pick(dataMessage.group, 'name', 'avatar')
|
|
|
|
|
) || {};
|
|
|
|
|
|
|
|
|
|
const addedMembers = _.difference(
|
|
|
|
|
attributes.members,
|
|
|
|
|
conversation.get('members')
|
|
|
|
|
conversationPrimary.get('members')
|
|
|
|
|
);
|
|
|
|
|
if (addedMembers.length > 0) {
|
|
|
|
|
groupUpdate.joined = addedMembers;
|
|
|
|
|
}
|
|
|
|
|
if (conversation.get('left')) {
|
|
|
|
|
if (conversationPrimary.get('left')) {
|
|
|
|
|
// TODO: Maybe we shouldn't assume this message adds us:
|
|
|
|
|
// we could maybe still get this message by mistake
|
|
|
|
|
window.log.warn('re-added to a left group');
|
|
|
|
@ -2294,7 +2307,7 @@
|
|
|
|
|
|
|
|
|
|
// Check if anyone got kicked:
|
|
|
|
|
const removedMembers = _.difference(
|
|
|
|
|
conversation.get('members'),
|
|
|
|
|
conversationPrimary.get('members'),
|
|
|
|
|
attributes.members
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
@ -2316,7 +2329,7 @@
|
|
|
|
|
groupUpdate = { left: source };
|
|
|
|
|
}
|
|
|
|
|
attributes.members = _.without(
|
|
|
|
|
conversation.get('members'),
|
|
|
|
|
conversationPrimary.get('members'),
|
|
|
|
|
source
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
@ -2349,7 +2362,7 @@
|
|
|
|
|
attachments: dataMessage.attachments,
|
|
|
|
|
body: dataMessage.body,
|
|
|
|
|
contact: dataMessage.contact,
|
|
|
|
|
conversationId: conversation.id,
|
|
|
|
|
conversationId: conversationPrimary.id,
|
|
|
|
|
decrypted_at: now,
|
|
|
|
|
errors: [],
|
|
|
|
|
flags: dataMessage.flags,
|
|
|
|
@ -2363,7 +2376,7 @@
|
|
|
|
|
|
|
|
|
|
if (type === 'outgoing') {
|
|
|
|
|
const receipts = Whisper.DeliveryReceipts.forMessage(
|
|
|
|
|
conversation,
|
|
|
|
|
conversationPrimary,
|
|
|
|
|
message
|
|
|
|
|
);
|
|
|
|
|
receipts.forEach(receipt =>
|
|
|
|
@ -2376,10 +2389,10 @@
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
attributes.active_at = now;
|
|
|
|
|
conversation.set(attributes);
|
|
|
|
|
conversationPrimary.set(attributes);
|
|
|
|
|
|
|
|
|
|
// Re-enable typing if re-joined the group
|
|
|
|
|
conversation.updateTextInputState();
|
|
|
|
|
conversationPrimary.updateTextInputState();
|
|
|
|
|
|
|
|
|
|
if (message.isExpirationTimerUpdate()) {
|
|
|
|
|
message.set({
|
|
|
|
@ -2388,7 +2401,7 @@
|
|
|
|
|
expireTimer: dataMessage.expireTimer,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
conversation.set({ expireTimer: dataMessage.expireTimer });
|
|
|
|
|
conversationPrimary.set({ expireTimer: dataMessage.expireTimer });
|
|
|
|
|
} else if (dataMessage.expireTimer) {
|
|
|
|
|
message.set({ expireTimer: dataMessage.expireTimer });
|
|
|
|
|
}
|
|
|
|
@ -2400,7 +2413,7 @@
|
|
|
|
|
message.isExpirationTimerUpdate() || expireTimer;
|
|
|
|
|
if (shouldLogExpireTimerChange) {
|
|
|
|
|
window.log.info("Update conversation 'expireTimer'", {
|
|
|
|
|
id: conversation.idForLogging(),
|
|
|
|
|
id: conversationPrimary.idForLogging(),
|
|
|
|
|
expireTimer,
|
|
|
|
|
source: 'handleDataMessage',
|
|
|
|
|
});
|
|
|
|
@ -2408,8 +2421,11 @@
|
|
|
|
|
|
|
|
|
|
if (!message.isEndSession()) {
|
|
|
|
|
if (dataMessage.expireTimer) {
|
|
|
|
|
if (dataMessage.expireTimer !== conversation.get('expireTimer')) {
|
|
|
|
|
conversation.updateExpirationTimer(
|
|
|
|
|
if (
|
|
|
|
|
dataMessage.expireTimer !==
|
|
|
|
|
conversationPrimary.get('expireTimer')
|
|
|
|
|
) {
|
|
|
|
|
conversationPrimary.updateExpirationTimer(
|
|
|
|
|
dataMessage.expireTimer,
|
|
|
|
|
source,
|
|
|
|
|
message.get('received_at'),
|
|
|
|
@ -2419,18 +2435,18 @@
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else if (
|
|
|
|
|
conversation.get('expireTimer') &&
|
|
|
|
|
conversationPrimary.get('expireTimer') &&
|
|
|
|
|
// We only turn off timers if it's not a group update
|
|
|
|
|
!message.isGroupUpdate()
|
|
|
|
|
) {
|
|
|
|
|
conversation.updateExpirationTimer(
|
|
|
|
|
conversationPrimary.updateExpirationTimer(
|
|
|
|
|
null,
|
|
|
|
|
source,
|
|
|
|
|
message.get('received_at')
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const endSessionType = conversation.isSessionResetReceived()
|
|
|
|
|
const endSessionType = conversationPrimary.isSessionResetReceived()
|
|
|
|
|
? 'ongoing'
|
|
|
|
|
: 'done';
|
|
|
|
|
this.set({ endSessionType });
|
|
|
|
@ -2462,11 +2478,11 @@
|
|
|
|
|
message.attributes.body &&
|
|
|
|
|
message.attributes.body.indexOf(`@${ourNumber}`) !== -1
|
|
|
|
|
) {
|
|
|
|
|
conversation.set({ mentionedUs: true });
|
|
|
|
|
conversationPrimary.set({ mentionedUs: true });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conversation.set({
|
|
|
|
|
unreadCount: conversation.get('unreadCount') + 1,
|
|
|
|
|
conversationPrimary.set({
|
|
|
|
|
unreadCount: conversationPrimary.get('unreadCount') + 1,
|
|
|
|
|
isArchived: false,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -2474,7 +2490,7 @@
|
|
|
|
|
|
|
|
|
|
if (type === 'outgoing') {
|
|
|
|
|
const reads = Whisper.ReadReceipts.forMessage(
|
|
|
|
|
conversation,
|
|
|
|
|
conversationPrimary,
|
|
|
|
|
message
|
|
|
|
|
);
|
|
|
|
|
if (reads.length) {
|
|
|
|
@ -2485,39 +2501,35 @@
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A sync'd message to ourself is automatically considered read and delivered
|
|
|
|
|
if (conversation.isMe()) {
|
|
|
|
|
if (conversationPrimary.isMe()) {
|
|
|
|
|
message.set({
|
|
|
|
|
read_by: conversation.getRecipients(),
|
|
|
|
|
delivered_to: conversation.getRecipients(),
|
|
|
|
|
read_by: conversationPrimary.getRecipients(),
|
|
|
|
|
delivered_to: conversationPrimary.getRecipients(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
message.set({ recipients: conversation.getRecipients() });
|
|
|
|
|
message.set({ recipients: conversationPrimary.getRecipients() });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const conversationTimestamp = conversation.get('timestamp');
|
|
|
|
|
const conversationTimestamp = conversationPrimary.get('timestamp');
|
|
|
|
|
if (
|
|
|
|
|
!conversationTimestamp ||
|
|
|
|
|
message.get('sent_at') > conversationTimestamp
|
|
|
|
|
) {
|
|
|
|
|
conversation.lastMessage = message.getNotificationText();
|
|
|
|
|
conversation.set({
|
|
|
|
|
conversationPrimary.lastMessage = message.getNotificationText();
|
|
|
|
|
conversationPrimary.set({
|
|
|
|
|
timestamp: message.get('sent_at'),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const sendingDeviceConversation = await ConversationController.getOrCreateAndWait(
|
|
|
|
|
source,
|
|
|
|
|
'private'
|
|
|
|
|
);
|
|
|
|
|
if (dataMessage.profileKey) {
|
|
|
|
|
const profileKey = dataMessage.profileKey.toString('base64');
|
|
|
|
|
if (source === textsecure.storage.user.getNumber()) {
|
|
|
|
|
conversation.set({ profileSharing: true });
|
|
|
|
|
} else if (conversation.isPrivate()) {
|
|
|
|
|
conversation.setProfileKey(profileKey);
|
|
|
|
|
conversationPrimary.set({ profileSharing: true });
|
|
|
|
|
} else if (conversationPrimary.isPrivate()) {
|
|
|
|
|
conversationPrimary.setProfileKey(profileKey);
|
|
|
|
|
} else {
|
|
|
|
|
sendingDeviceConversation.setProfileKey(profileKey);
|
|
|
|
|
conversationOrigin.setProfileKey(profileKey);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2544,8 +2556,8 @@
|
|
|
|
|
and that user just sent us a friend request.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const isFriend = sendingDeviceConversation.isFriend();
|
|
|
|
|
const hasSentFriendRequest = sendingDeviceConversation.hasSentFriendRequest();
|
|
|
|
|
const isFriend = conversationOrigin.isFriend();
|
|
|
|
|
const hasSentFriendRequest = conversationOrigin.hasSentFriendRequest();
|
|
|
|
|
autoAccept = isFriend || hasSentFriendRequest;
|
|
|
|
|
|
|
|
|
|
if (autoAccept) {
|
|
|
|
@ -2559,16 +2571,17 @@
|
|
|
|
|
if (isFriend) {
|
|
|
|
|
window.Whisper.events.trigger('endSession', source);
|
|
|
|
|
} else if (hasSentFriendRequest) {
|
|
|
|
|
await sendingDeviceConversation.onFriendRequestAccepted();
|
|
|
|
|
await conversationOrigin.onFriendRequestAccepted();
|
|
|
|
|
} else {
|
|
|
|
|
await sendingDeviceConversation.onFriendRequestReceived();
|
|
|
|
|
await conversationOrigin.onFriendRequestReceived();
|
|
|
|
|
}
|
|
|
|
|
} else if (message.get('type') !== 'outgoing') {
|
|
|
|
|
// Ignore 'outgoing' messages because they are sync messages
|
|
|
|
|
await sendingDeviceConversation.onFriendRequestAccepted();
|
|
|
|
|
await conversationOrigin.onFriendRequestAccepted();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We need to map the original message source to the primary device
|
|
|
|
|
if (source !== ourNumber) {
|
|
|
|
|
message.set({ source: primarySource });
|
|
|
|
|
}
|
|
|
|
@ -2586,11 +2599,11 @@
|
|
|
|
|
|
|
|
|
|
await window.Signal.Data.updateConversation(
|
|
|
|
|
conversationId,
|
|
|
|
|
conversation.attributes,
|
|
|
|
|
conversationPrimary.attributes,
|
|
|
|
|
{ Conversation: Whisper.Conversation }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
conversation.trigger('newmessage', message);
|
|
|
|
|
conversationPrimary.trigger('newmessage', message);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// We go to the database here because, between the message save above and
|
|
|
|
@ -2628,9 +2641,9 @@
|
|
|
|
|
if (message.get('unread')) {
|
|
|
|
|
// Need to do this here because the conversation has already changed states
|
|
|
|
|
if (autoAccept) {
|
|
|
|
|
await conversation.notifyFriendRequest(source, 'accepted');
|
|
|
|
|
await conversationPrimary.notifyFriendRequest(source, 'accepted');
|
|
|
|
|
} else {
|
|
|
|
|
await conversation.notify(message);
|
|
|
|
|
await conversationPrimary.notify(message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|