|
|
|
@ -260,26 +260,27 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!CurrentAppContext().isMainApp) {
|
|
|
|
|
OWSFail(@"Not main app.");
|
|
|
|
|
OWSFail(@"Not the main app.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OWSLogInfo(@"handling decrypted envelope: %@", [self descriptionForEnvelope:envelope]);
|
|
|
|
|
OWSLogInfo(@"Handling decrypted envelope: %@.", [self descriptionForEnvelope:envelope]);
|
|
|
|
|
|
|
|
|
|
if (!wasReceivedByUD) {
|
|
|
|
|
if (!envelope.hasSource || envelope.source.length < 1) {
|
|
|
|
|
OWSFailDebug(@"incoming envelope has invalid source");
|
|
|
|
|
OWSFailDebug(@"Incoming envelope with invalid source.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!envelope.hasSourceDevice || envelope.sourceDevice < 1) {
|
|
|
|
|
OWSFailDebug(@"incoming envelope has invalid source device");
|
|
|
|
|
OWSFailDebug(@"Incoming envelope with invalid source device.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OWSAssertDebug(![self isEnvelopeSenderBlocked:envelope]);
|
|
|
|
|
|
|
|
|
|
// Loki: Ignore any friend requests that we got before restoration
|
|
|
|
|
// Loki: Ignore any friend requests from before restoration
|
|
|
|
|
// The envelope type is set during UD decryption.
|
|
|
|
|
uint64_t restorationTime = [NSNumber numberWithDouble:[OWSPrimaryStorage.sharedManager getRestorationTime]].unsignedLongLongValue;
|
|
|
|
|
if (envelope.type == SSKProtoEnvelopeTypeFriendRequest && envelope.timestamp < restorationTime * 1000) {
|
|
|
|
|
[LKLogger print:@"[Loki] Ignoring friend request received before restoration."];
|
|
|
|
@ -417,7 +418,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (envelope.sourceDevice < 1) {
|
|
|
|
|
OWSFailDebug(@"Invaid source device.");
|
|
|
|
|
OWSFailDebug(@"Invalid source device.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -426,23 +427,24 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
sourceDeviceId:envelope.sourceDevice
|
|
|
|
|
transaction:transaction];
|
|
|
|
|
if (duplicateEnvelope) {
|
|
|
|
|
OWSLogInfo(@"Ignoring previously received envelope from %@ with timestamp: %llu",
|
|
|
|
|
OWSLogInfo(@"Ignoring previously received envelope from: %@ with timestamp: %llu.",
|
|
|
|
|
envelopeAddress(envelope),
|
|
|
|
|
envelope.timestamp);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loki: Handle friend request acceptance if needed
|
|
|
|
|
// The envelope type is set during UD decryption.
|
|
|
|
|
[self handleFriendRequestAcceptanceIfNeededWithEnvelope:envelope transaction:transaction];
|
|
|
|
|
|
|
|
|
|
if (envelope.content != nil) {
|
|
|
|
|
NSError *error;
|
|
|
|
|
SSKProtoContent *_Nullable contentProto = [SSKProtoContent parseData:plaintextData error:&error];
|
|
|
|
|
if (error || !contentProto) {
|
|
|
|
|
OWSFailDebug(@"could not parse proto: %@", error);
|
|
|
|
|
OWSFailDebug(@"Could not parse proto due to error: %@.", error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
OWSLogInfo(@"handling content: <Content: %@>", [self descriptionForContent:contentProto]);
|
|
|
|
|
OWSLogInfo(@"Handling content: <Content: %@>.", [self descriptionForContent:contentProto]);
|
|
|
|
|
|
|
|
|
|
// Loki: Workaround for duplicate sync transcript issue
|
|
|
|
|
if (contentProto.syncMessage != nil && contentProto.syncMessage.sent != nil) {
|
|
|
|
@ -460,7 +462,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
}
|
|
|
|
|
[self.primaryStorage setPreKeyBundle:bundle forContact:envelope.source transaction:transaction];
|
|
|
|
|
|
|
|
|
|
// Loki: If we received a friend request, but we were already friends with this user, then reset the session
|
|
|
|
|
// Loki: If we received a friend request, but we were already friends with this user, reset the session
|
|
|
|
|
// The envelope type is set during UD decryption.
|
|
|
|
|
if (envelope.type == SSKProtoEnvelopeTypeFriendRequest) {
|
|
|
|
|
TSContactThread *thread = [TSContactThread getThreadWithContactId:envelope.source transaction:transaction];
|
|
|
|
|
if (thread && thread.isContactFriend) {
|
|
|
|
@ -558,13 +561,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loki: Don't process session request messages
|
|
|
|
|
// Loki: Don't process session request messages any further
|
|
|
|
|
if ((dataMessage.flags & SSKProtoDataMessageFlagsSessionRequest) != 0) { return; }
|
|
|
|
|
// Loki: Don't process session restore messages
|
|
|
|
|
// Loki: Don't process session restore messages any further
|
|
|
|
|
if ((dataMessage.flags & SSKProtoDataMessageFlagsSessionRestore) != 0) { return; }
|
|
|
|
|
|
|
|
|
|
if ([self isDataMessageBlocked:dataMessage envelope:envelope]) {
|
|
|
|
|
NSString *logMessage = [NSString stringWithFormat:@"Ignoring blocked message from sender: %@", envelope.source];
|
|
|
|
|
NSString *logMessage = [NSString stringWithFormat:@"Ignoring blocked message from sender: %@.", envelope.source];
|
|
|
|
|
if (dataMessage.group) {
|
|
|
|
|
logMessage = [logMessage stringByAppendingFormat:@" in group: %@", dataMessage.group.id];
|
|
|
|
|
}
|
|
|
|
@ -574,14 +577,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
|
|
|
|
|
if (dataMessage.hasTimestamp) {
|
|
|
|
|
if (dataMessage.timestamp <= 0) {
|
|
|
|
|
OWSFailDebug(@"Ignoring message with invalid data message timestamp: %@", envelope.source);
|
|
|
|
|
// TODO: Add analytics.
|
|
|
|
|
OWSFailDebug(@"Ignoring data message with invalid timestamp: %@.", envelope.source);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// This prevents replay attacks by the service.
|
|
|
|
|
if (dataMessage.timestamp != envelope.timestamp) {
|
|
|
|
|
OWSFailDebug(@"Ignoring message with non-matching data message timestamp: %@", envelope.source);
|
|
|
|
|
// TODO: Add analytics.
|
|
|
|
|
OWSFailDebug(@"Ignoring data message with non-matching timestamp: %@.", envelope.source);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -607,7 +608,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
[self sendGroupInfoRequest:dataMessage.group.id envelope:envelope transaction:transaction];
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
OWSLogInfo(@"Ignoring group message for unknown group from: %@", envelope.source);
|
|
|
|
|
OWSLogInfo(@"Ignoring group message for unknown group from: %@.", envelope.source);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -890,7 +891,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
|
|
|
|
|
TSThread *_Nullable thread = [self threadForEnvelope:envelope dataMessage:dataMessage transaction:transaction];
|
|
|
|
|
if (!thread) {
|
|
|
|
|
OWSFailDebug(@"ignoring media message for unknown group.");
|
|
|
|
|
OWSFailDebug(@"Ignoring media message for unknown group.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -905,17 +906,17 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
|
|
|
|
|
[message saveWithTransaction:transaction];
|
|
|
|
|
|
|
|
|
|
OWSLogDebug(@"incoming attachment message: %@", message.debugDescription);
|
|
|
|
|
OWSLogDebug(@"Incoming attachment message: %@.", message.debugDescription);
|
|
|
|
|
|
|
|
|
|
[self.attachmentDownloads downloadAttachmentsForMessage:message
|
|
|
|
|
transaction:transaction
|
|
|
|
|
success:^(NSArray<TSAttachmentStream *> *attachmentStreams) {
|
|
|
|
|
OWSLogDebug(@"successfully fetched attachments: %lu for message: %@",
|
|
|
|
|
OWSLogDebug(@"Successfully fetched attachments: %lu for message: %@.",
|
|
|
|
|
(unsigned long)attachmentStreams.count,
|
|
|
|
|
message);
|
|
|
|
|
}
|
|
|
|
|
failure:^(NSError *error) {
|
|
|
|
|
OWSLogError(@"failed to fetch attachments for message: %@ with error: %@", message, error);
|
|
|
|
|
OWSLogError(@"Failed to fetch attachments for message: %@ with error: %@.", message, error);
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1402,7 +1403,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
|
|
|
|
|
dispatch_queue_t messageProcessingQueue = SSKEnvironment.shared.batchMessageProcessor.processingQueue.serialQueue;
|
|
|
|
|
AssertOnDispatchQueue(messageProcessingQueue);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The envelope source is set during UD decryption.
|
|
|
|
|
|
|
|
|
|
if ([ECKeyPair isValidHexEncodedPublicKeyWithCandidate:envelope.source]) {
|
|
|
|
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
|
|
|
[[LKAPI getDestinationsFor:envelope.source inTransaction:transaction].ensureOn(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() {
|
|
|
|
@ -1432,7 +1435,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
// We distinguish between the old group state (if any) and the new group state.
|
|
|
|
|
TSGroupThread *_Nullable oldGroupThread = [TSGroupThread threadWithGroupId:groupId transaction:transaction];
|
|
|
|
|
if (oldGroupThread) {
|
|
|
|
|
// Loki: Try to figure out removed members
|
|
|
|
|
// Loki: Determine removed members
|
|
|
|
|
removedMemberIds = [NSMutableSet setWithArray:oldGroupThread.groupModel.groupMemberIds];
|
|
|
|
|
[removedMemberIds minusSet:newMemberIds];
|
|
|
|
|
[removedMemberIds removeObject:hexEncodedPublicKey];
|
|
|
|
@ -1562,7 +1565,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
|
|
|
|
|
// Loki: Don't process friend requests in group chats
|
|
|
|
|
if (body.length == 0 && attachmentPointers.count < 1 && !contact) {
|
|
|
|
|
OWSLogWarn(@"ignoring empty incoming message from: %@ for group: %@ with timestamp: %lu",
|
|
|
|
|
OWSLogWarn(@"Ignoring empty incoming message from: %@ for group: %@ with timestamp: %lu.",
|
|
|
|
|
hexEncodedPublicKey,
|
|
|
|
|
groupId,
|
|
|
|
|
(unsigned long)timestamp);
|
|
|
|
@ -1591,14 +1594,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
return incomingMessage;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
OWSLogWarn(@"Ignoring unknown group message type: %d", (int)dataMessage.group.type);
|
|
|
|
|
OWSLogWarn(@"Ignoring unknown group message type: %d.", (int)dataMessage.group.type);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
// Loki: A message from a secondary device should appear as if it came from the primary device; the underlying
|
|
|
|
|
// friend request logic, however, should still be specific to the secondary device.
|
|
|
|
|
// Loki: A message from a slave device should appear as if it came from the master device; the underlying
|
|
|
|
|
// friend request logic, however, should still be specific to the slave device.
|
|
|
|
|
|
|
|
|
|
// Loki: Get the master hex encoded public key and thread
|
|
|
|
|
NSString *hexEncodedPublicKey = envelope.source;
|
|
|
|
@ -1606,7 +1609,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:hexEncodedPublicKey transaction:transaction];
|
|
|
|
|
TSContactThread *masterThread = [TSContactThread getOrCreateThreadWithContactId:masterHexEncodedPublicKey transaction:transaction];
|
|
|
|
|
|
|
|
|
|
OWSLogDebug(@"incoming message from: %@ with timestamp: %lu", hexEncodedPublicKey, (unsigned long)timestamp);
|
|
|
|
|
OWSLogDebug(@"Incoming message from: %@ with timestamp: %lu.", hexEncodedPublicKey, (unsigned long)timestamp);
|
|
|
|
|
|
|
|
|
|
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
|
|
|
|
|
thread:masterThread
|
|
|
|
@ -1665,7 +1668,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
[self handleFriendRequestMessageIfNeededWithEnvelope:envelope data:dataMessage message:incomingMessage thread:thread transaction:transaction];
|
|
|
|
|
|
|
|
|
|
if (body.length == 0 && attachmentPointers.count < 1 && !contact) {
|
|
|
|
|
OWSLogWarn(@"ignoring empty incoming message from: %@ with timestamp: %lu",
|
|
|
|
|
OWSLogWarn(@"Ignoring empty incoming message from: %@ with timestamp: %lu.",
|
|
|
|
|
hexEncodedPublicKey,
|
|
|
|
|
(unsigned long)timestamp);
|
|
|
|
|
return nil;
|
|
|
|
@ -1703,13 +1706,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
if (profileKey.length == kAES256_KeyByteLength) {
|
|
|
|
|
[self.profileManager setProfileKeyData:profileKey forRecipientId:recipientId avatarURL:url];
|
|
|
|
|
} else {
|
|
|
|
|
OWSFailDebug(
|
|
|
|
|
@"Unexpected profile key length:%lu on message from:%@", (unsigned long)profileKey.length, recipientId);
|
|
|
|
|
OWSFailDebug(@"Unexpected profile key length:%lu on message from:%@", (unsigned long)profileKey.length, recipientId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loki: Establish a session if there is no session between the memebers of a group
|
|
|
|
|
- (void)establishSessionsWithMembersIfNeeded:(NSArray *)members forThread:(TSGroupThread *)thread transaction:(YapDatabaseReadWriteTransaction *)transaction
|
|
|
|
|
{
|
|
|
|
|
NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
|
|
|
|
@ -1759,6 +1760,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
if (envelope.isGroupChatMessage) {
|
|
|
|
|
return NSLog(@"[Loki] Ignoring friend request in group chat.", @"");
|
|
|
|
|
}
|
|
|
|
|
// The envelope type is set during UD decryption.
|
|
|
|
|
if (envelope.type != SSKProtoEnvelopeTypeFriendRequest) {
|
|
|
|
|
return NSLog(@"[Loki] Ignoring friend request logic for non friend request type envelope.");
|
|
|
|
|
}
|
|
|
|
@ -1804,6 +1806,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
- (void)handleFriendRequestAcceptanceIfNeededWithEnvelope:(SSKProtoEnvelope *)envelope transaction:(YapDatabaseReadWriteTransaction *)transaction {
|
|
|
|
|
// If we get an envelope that isn't a friend request, then we can infer that we had to use
|
|
|
|
|
// Signal cipher decryption and thus that we have a session with the other person.
|
|
|
|
|
// The envelope type is set during UD decryption.
|
|
|
|
|
if (envelope.isGroupChatMessage || envelope.type == SSKProtoEnvelopeTypeFriendRequest) return;
|
|
|
|
|
// Currently this uses `envelope.source` but with sync messages we'll need to use the message sender ID
|
|
|
|
|
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
|
|
|
|
@ -1896,7 +1899,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
failure:^(NSError *error) {
|
|
|
|
|
OWSLogWarn(@"failed to download attachment for message: %lu with error: %@",
|
|
|
|
|
OWSLogWarn(@"Failed to download attachment for message: %lu with error: %@.",
|
|
|
|
|
(unsigned long)incomingMessage.timestamp,
|
|
|
|
|
error);
|
|
|
|
|
}];
|
|
|
|
@ -2017,7 +2020,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# pragma mark - Loki Session
|
|
|
|
|
# pragma mark - Loki Session Handling
|
|
|
|
|
|
|
|
|
|
- (void)handleNewSessionAdopted:(NSNotification *)notification {
|
|
|
|
|
NSString *hexEncodedPublicKey = notification.userInfo[kNSNotificationKey_ContactPubKey];
|
|
|
|
|