Merge branch 'master' into message-expiration

pull/16/head
Niels Andriesse 6 years ago
commit 201b8095ee

@ -108,9 +108,9 @@ public class SessionResetOperation: OWSOperation, DurableOperation {
override public func run() { override public func run() {
assert(self.durableOperationDelegate != nil) assert(self.durableOperationDelegate != nil)
/* Loki Original Code /* Loki: Original code
* We don't want to delete session. Ref: SignalServiceKit/Loki/Docs/SessionReset.md * We don't want to delete session. Ref: SignalServiceKit/Loki/Docs/SessionReset.md
* ================== * ================
if firstAttempt { if firstAttempt {
self.dbConnection.readWrite { transaction in self.dbConnection.readWrite { transaction in
Logger.info("deleting sessions for recipient: \(self.recipientId)") Logger.info("deleting sessions for recipient: \(self.recipientId)")
@ -118,7 +118,8 @@ public class SessionResetOperation: OWSOperation, DurableOperation {
} }
firstAttempt = false firstAttempt = false
} }
*/ * ================
*/
let endSessionMessage = EndSessionMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: self.contactThread) let endSessionMessage = EndSessionMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: self.contactThread)
@ -132,22 +133,21 @@ public class SessionResetOperation: OWSOperation, DurableOperation {
// Otherwise if we send another message before them, they wont have the session to decrypt it. // Otherwise if we send another message before them, they wont have the session to decrypt it.
self.primaryStorage.archiveAllSessions(forContact: self.recipientId, protocolContext: transaction) self.primaryStorage.archiveAllSessions(forContact: self.recipientId, protocolContext: transaction)
/* Loki original code /* Loki: Original code
* ================== * ================
let message = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), let message = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(),
in: self.contactThread, in: self.contactThread,
messageType: TSInfoMessageType.typeSessionDidEnd) messageType: TSInfoMessageType.typeSessionDidEnd)
message.save(with: transaction) message.save(with: transaction)
*/ * ================
*/
if (self.contactThread.sessionResetState != .requestReceived) { if (self.contactThread.sessionResetState != .requestReceived) {
let message = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), let message = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: self.contactThread, messageType: .typeLokiSessionResetProgress)
in: self.contactThread,
messageType: .typeLokiSessionResetProgress)
message.save(with: transaction) message.save(with: transaction)
/// Loki: We have initiated a session reset // Loki: We have initiated a session reset
Logger.debug("[Loki Session Reset] Session reset has been initiated") Logger.debug("[Loki] Session reset has been initiated.")
self.contactThread.sessionResetState = .initiated self.contactThread.sessionResetState = .initiated
self.contactThread.save(with: transaction) self.contactThread.save(with: transaction)
} }

@ -273,7 +273,7 @@ typedef void (^SystemMessageActionBlock)(void);
case TSInfoMessageAddGroupToProfileWhitelistOffer: case TSInfoMessageAddGroupToProfileWhitelistOffer:
case TSInfoMessageTypeGroupUpdate: case TSInfoMessageTypeGroupUpdate:
case TSInfoMessageTypeGroupQuit: case TSInfoMessageTypeGroupQuit:
case TSInfoMessageTypeLokiSessionResetProgress: case TSInfoMessageTypeLokiSessionResetInProgress:
case TSInfoMessageTypeLokiSessionResetDone: case TSInfoMessageTypeLokiSessionResetDone:
return nil; return nil;
case TSInfoMessageTypeDisappearingMessagesUpdate: { case TSInfoMessageTypeDisappearingMessagesUpdate: {
@ -461,7 +461,7 @@ typedef void (^SystemMessageActionBlock)(void);
switch (message.messageType) { switch (message.messageType) {
case TSInfoMessageUserNotRegistered: case TSInfoMessageUserNotRegistered:
case TSInfoMessageTypeSessionDidEnd: case TSInfoMessageTypeSessionDidEnd:
case TSInfoMessageTypeLokiSessionResetProgress: case TSInfoMessageTypeLokiSessionResetInProgress:
case TSInfoMessageTypeLokiSessionResetDone: case TSInfoMessageTypeLokiSessionResetDone:
return nil; return nil;
case TSInfoMessageTypeUnsupportedMessage: case TSInfoMessageTypeUnsupportedMessage:

@ -10,9 +10,9 @@ NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, TSContactThreadSessionResetState) { typedef NS_ENUM(NSInteger, TSContactThreadSessionResetState) {
// No ongoing session reset // No ongoing session reset
TSContactThreadSessionResetStateNone, TSContactThreadSessionResetStateNone,
// We initiated session reset // We initiated a session reset
TSContactThreadSessionResetStateInitiated, TSContactThreadSessionResetStateInitiated,
// We received the session reset // We received a session reset
TSContactThreadSessionResetStateRequestReceived, TSContactThreadSessionResetStateRequestReceived,
}; };
@ -20,7 +20,7 @@ extern NSString *const TSContactThreadPrefix;
@interface TSContactThread : TSThread @interface TSContactThread : TSThread
// Loki: The current session reset state with this thread // Loki: The current session reset state for this thread
@property (atomic) TSContactThreadSessionResetState sessionResetState; @property (atomic) TSContactThreadSessionResetState sessionResetState;
@property (nonatomic) BOOL hasDismissedOffers; @property (nonatomic) BOOL hasDismissedOffers;

@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
@param pubKey The hex encoded public key of the contact. @param pubKey The hex encoded public key of the contact.
@param transaction A `YapDatabaseReadTransaction`. @param transaction A `YapDatabaseReadTransaction`.
@return The record associated with the contact or nil if it didn't exist. @return The record associated with the contact or `nil` if it doesn't exist.
*/ */
- (PreKeyRecord *_Nullable)getPreKeyForContact:(NSString *)pubKey transaction:(YapDatabaseReadTransaction *)transaction; - (PreKeyRecord *_Nullable)getPreKeyForContact:(NSString *)pubKey transaction:(YapDatabaseReadTransaction *)transaction;

@ -38,13 +38,10 @@
int preKeyId = [transaction intForKey:pubKey inCollection:LokiPreKeyContactCollection]; int preKeyId = [transaction intForKey:pubKey inCollection:LokiPreKeyContactCollection];
// If we don't have an id then return nil // If we don't have an id then return nil
if (preKeyId <= 0) { if (preKeyId <= 0) { return nil; }
return nil;
}
/// thows_loadPreKey doesn't allow us to pass transaction ;( /// throws_loadPreKey doesn't allow us to pass transaction ;(
return [transaction preKeyRecordForKey:[self keyFromInt:preKeyId] return [transaction preKeyRecordForKey:[self keyFromInt:preKeyId] inCollection:OWSPrimaryStoragePreKeyStoreCollection];
inCollection:OWSPrimaryStoragePreKeyStoreCollection];
} }
- (PreKeyRecord *)getOrCreatePreKeyForContact:(NSString *)pubKey { - (PreKeyRecord *)getOrCreatePreKeyForContact:(NSString *)pubKey {

@ -1,4 +1,4 @@
/// Loki: Refer to Docs/SessionReset.md for explanations // Loki: Refer to Docs/SessionReset.md for explanations
#import "SessionCipher.h" #import "SessionCipher.h"
@ -11,14 +11,14 @@ extern NSString *const kNSNotificationKey_ContactPubKey;
/** /**
Decrypt the given `CipherMessage`. Decrypt the given `CipherMessage`.
This function is a wrapper around `throws_decrypt:protocolContext:` and adds on the custom loki session handling ontop. This function is a wrapper around `throws_decrypt:protocolContext:` and adds on the custom Loki session handling.
Refer to SignalServiceKit/Loki/Docs/SessionReset.md for overview on how it works. Refer to SignalServiceKit/Loki/Docs/SessionReset.md for an overview of how it works.
@param whisperMessage The cipher message. @param whisperMessage The cipher message.
@param protocolContext The protocol context (YapDatabaseReadWriteTransaction) @param protocolContext The protocol context (a `YapDatabaseReadWriteTransaction`).
@return The decrypted data. @return The decrypted data.
*/ */
- (NSData *)throws_lokiDecrypt:(id<CipherMessage>)whisperMessage protocolContext:(nullable id)protocolContext NS_SWIFT_UNAVAILABLE("throws objc exceptions"); - (NSData *)throws_lokiDecrypt:(id<CipherMessage>)whisperMessage protocolContext:(nullable id)protocolContext NS_SWIFT_UNAVAILABLE("throws Obj-C exceptions");
@end @end

@ -1,4 +1,4 @@
/// Loki: Refer to Docs/SessionReset.md for explanations // Loki: Refer to Docs/SessionReset.md for explanations
#import "SessionCipher+Loki.h" #import "SessionCipher+Loki.h"
#import "NSNotificationCenter+OWS.h" #import "NSNotificationCenter+OWS.h"
@ -47,36 +47,26 @@ NSString *const kNSNotificationKey_ContactPubKey = @"kNSNotificationKey_ContactP
SessionState *state = record.sessionState; SessionState *state = record.sessionState;
// Check if session is initialized // Check if session is initialized
if (!state.hasSenderChain) { if (!state.hasSenderChain) { return nil; }
return nil;
}
return state; return state;
} }
/// Handle any loki session reset stuff /// Handle any Loki session reset stuff
- (void)handleSessionReset:(id<CipherMessage>)whisperMessage - (void)handleSessionReset:(id<CipherMessage>)whisperMessage previousState:(SessionState *_Nullable)previousState protocolContext:(nullable id)protocolContext
previousState:(SessionState *_Nullable)previousState
protocolContext:(nullable id)protocolContext
{ {
// Don't bother doing anything if we didn't have a session before // Don't bother doing anything if we didn't have a session before
if (!previousState) { if (!previousState) { return; }
return;
}
OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]); OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]);
YapDatabaseReadWriteTransaction *transaction = protocolContext; YapDatabaseReadWriteTransaction *transaction = protocolContext;
// Get the thread // Get the thread
TSContactThread *thread = [TSContactThread getThreadWithContactId:self.recipientId transaction:transaction]; TSContactThread *thread = [TSContactThread getThreadWithContactId:self.recipientId transaction:transaction];
if (!thread) { if (!thread) { return; }
return;
}
// Bail early if no session reset is in progress // Bail early if no session reset is in progress
if (thread.sessionResetState == TSContactThreadSessionResetStateNone) { if (thread.sessionResetState == TSContactThreadSessionResetStateNone) { return; }
return;
}
BOOL sessionResetReceived = thread.sessionResetState == TSContactThreadSessionResetStateRequestReceived; BOOL sessionResetReceived = thread.sessionResetState == TSContactThreadSessionResetStateRequestReceived;
SessionState *_Nullable currentState = [self getCurrentState:protocolContext]; SessionState *_Nullable currentState = [self getCurrentState:protocolContext];
@ -106,12 +96,8 @@ NSString *const kNSNotificationKey_ContactPubKey = @"kNSNotificationKey_ContactP
/// Send a notification about a new session being adopted /// Send a notification about a new session being adopted
- (void)notifySessionAdopted - (void)notifySessionAdopted
{ {
[[NSNotificationCenter defaultCenter] NSDictionary *userInfo = @{ kNSNotificationKey_ContactPubKey : self.recipientId };
postNotificationNameAsync:kNSNotificationName_SessionAdopted [NSNotificationCenter.defaultCenter postNotificationNameAsync:kNSNotificationName_SessionAdopted object:nil userInfo:userInfo];
object:nil
userInfo:@{
kNSNotificationKey_ContactPubKey : self.recipientId,
}];
} }
/// Delete all other sessions except the given one /// Delete all other sessions except the given one
@ -121,10 +107,7 @@ NSString *const kNSNotificationKey_ContactPubKey = @"kNSNotificationKey_ContactP
[record removePreviousSessionStates]; [record removePreviousSessionStates];
[record setState:state]; [record setState:state];
[self.sessionStore storeSession:self.recipientId [self.sessionStore storeSession:self.recipientId deviceId:self.deviceId session:record protocolContext:protocolContext];
deviceId:self.deviceId
session:record
protocolContext:protocolContext];
} }
/// Set the given session as the active one while archiving the old one /// Set the given session as the active one while archiving the old one
@ -136,17 +119,14 @@ NSString *const kNSNotificationKey_ContactPubKey = @"kNSNotificationKey_ContactP
[record.previousSessionStates enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(SessionState *obj, NSUInteger idx, BOOL *stop) { [record.previousSessionStates enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(SessionState *obj, NSUInteger idx, BOOL *stop) {
if ([state.aliceBaseKey isEqualToData:obj.aliceBaseKey]) { if ([state.aliceBaseKey isEqualToData:obj.aliceBaseKey]) {
[record.previousSessionStates removeObjectAtIndex:idx]; [record.previousSessionStates removeObjectAtIndex:idx];
*stop = true; *stop = YES;
} }
}]; }];
// Promote it so the previous state gets archived // Promote it so the previous state gets archived
[record promoteState:state]; [record promoteState:state];
[self.sessionStore storeSession:self.recipientId [self.sessionStore storeSession:self.recipientId deviceId:self.deviceId session:record protocolContext:protocolContext];
deviceId:self.deviceId
session:record
protocolContext:protocolContext];
} }
/// Check that we have matching prekeys in the case of a `PreKeyWhisperMessage` /// Check that we have matching prekeys in the case of a `PreKeyWhisperMessage`
@ -155,26 +135,22 @@ NSString *const kNSNotificationKey_ContactPubKey = @"kNSNotificationKey_ContactP
OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadTransaction class]]); OWSAssertDebug([protocolContext isKindOfClass:[YapDatabaseReadTransaction class]]);
YapDatabaseReadTransaction *transaction = protocolContext; YapDatabaseReadTransaction *transaction = protocolContext;
/// We only want to look at `PreKeyWhisperMessage` // We only want to look at `PreKeyWhisperMessage`
if (![whisperMessage isKindOfClass:[PreKeyWhisperMessage class]]) { if (![whisperMessage isKindOfClass:[PreKeyWhisperMessage class]]) { return; }
return;
}
/// We need the primary storage to access contact prekeys // We need the primary storage to access contact prekeys
if (![self.prekeyStore isKindOfClass:[OWSPrimaryStorage class]]) { if (![self.prekeyStore isKindOfClass:[OWSPrimaryStorage class]]) { return; }
return;
}
PreKeyWhisperMessage *preKeyMessage = whisperMessage; PreKeyWhisperMessage *preKeyMessage = whisperMessage;
OWSPrimaryStorage *primaryStorage = self.prekeyStore; OWSPrimaryStorage *primaryStorage = self.prekeyStore;
PreKeyRecord *_Nullable storedPreKey = [primaryStorage getPreKeyForContact:self.recipientId transaction:transaction]; PreKeyRecord *_Nullable storedPreKey = [primaryStorage getPreKeyForContact:self.recipientId transaction:transaction];
if(!storedPreKey) { if (!storedPreKey) {
OWSRaiseException(@"LokiInvalidPreKey", @"Received a friend request from a pubkey for which no prekey bundle was created"); OWSRaiseException(@"LokiInvalidPreKey", @"Received a friend request from a public key for which no prekey bundle was created.");
} }
if (storedPreKey.Id != preKeyMessage.prekeyID) { if (storedPreKey.Id != preKeyMessage.prekeyID) {
OWSRaiseException(@"LokiPreKeyIdsDontMatch", @"Received a preKeyWhisperMessage (friend request accept) from an unknown source"); OWSRaiseException(@"LokiPreKeyIdsDontMatch", @"Received a PreKeyWhisperMessage (friend request accept) from an unknown source.");
} }
} }

@ -1,4 +1,3 @@
#import "SignalServiceKit.h"
#import "TSOutgoingMessage.h" #import "TSOutgoingMessage.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN

@ -21,7 +21,7 @@ typedef NS_ENUM(NSInteger, TSInfoMessageType) {
TSInfoMessageVerificationStateChange, TSInfoMessageVerificationStateChange,
TSInfoMessageAddUserToProfileWhitelistOffer, TSInfoMessageAddUserToProfileWhitelistOffer,
TSInfoMessageAddGroupToProfileWhitelistOffer, TSInfoMessageAddGroupToProfileWhitelistOffer,
TSInfoMessageTypeLokiSessionResetProgress, TSInfoMessageTypeLokiSessionResetInProgress,
TSInfoMessageTypeLokiSessionResetDone, TSInfoMessageTypeLokiSessionResetDone,
}; };

@ -117,7 +117,7 @@ NSUInteger TSInfoMessageSchemaVersion = 1;
- (NSString *)previewTextWithTransaction:(YapDatabaseReadTransaction *)transaction - (NSString *)previewTextWithTransaction:(YapDatabaseReadTransaction *)transaction
{ {
switch (_messageType) { switch (_messageType) {
case TSInfoMessageTypeLokiSessionResetProgress: case TSInfoMessageTypeLokiSessionResetInProgress:
return NSLocalizedString(@"Secure session reset in progress", nil); return NSLocalizedString(@"Secure session reset in progress", nil);
case TSInfoMessageTypeLokiSessionResetDone: case TSInfoMessageTypeLokiSessionResetDone:
return NSLocalizedString(@"Secure session reset done", nil); return NSLocalizedString(@"Secure session reset done", nil);

@ -438,10 +438,11 @@ NSError *EnsureDecryptError(NSError *_Nullable error, NSString *fallbackErrorDes
NSData *_Nullable plaintextData = NSData *_Nullable plaintextData =
[[cipher throws_lokiDecrypt:cipherMessage protocolContext:transaction] removePadding]; [[cipher throws_lokiDecrypt:cipherMessage protocolContext:transaction] removePadding];
/* Loki original code /* Loki: Original code
* ================= * ================
NSData *_Nullable plaintextData = NSData *_Nullable plaintextData =
[[cipher throws_decrypt:cipherMessage protocolContext:transaction] removePadding]; [[cipher throws_decrypt:cipherMessage protocolContext:transaction] removePadding];
* ================
*/ */
OWSMessageDecryptResult *result = [OWSMessageDecryptResult resultWithEnvelopeData:envelopeData OWSMessageDecryptResult *result = [OWSMessageDecryptResult resultWithEnvelopeData:envelopeData
plaintextData:plaintextData plaintextData:plaintextData

@ -88,11 +88,8 @@ NS_ASSUME_NONNULL_BEGIN
_dbConnection = primaryStorage.newDatabaseConnection; _dbConnection = primaryStorage.newDatabaseConnection;
_incomingMessageFinder = [[OWSIncomingMessageFinder alloc] initWithPrimaryStorage:primaryStorage]; _incomingMessageFinder = [[OWSIncomingMessageFinder alloc] initWithPrimaryStorage:primaryStorage];
/// Loki: Add observation for new session // Loki: Add observation for new session
[[NSNotificationCenter defaultCenter] addObserver:self [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(onNewSessionAdopted:) name:kNSNotificationName_SessionAdopted object:nil];
selector:@selector(onNewSessionAdopted:)
name:kNSNotificationName_SessionAdopted
object:nil];
OWSSingletonAssert(); OWSSingletonAssert();
@ -100,7 +97,7 @@ NS_ASSUME_NONNULL_BEGIN
} }
- (void)dealloc { - (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self]; [NSNotificationCenter.defaultCenter removeObserver:self];
} }
#pragma mark - Dependencies #pragma mark - Dependencies
@ -1004,14 +1001,15 @@ NS_ASSUME_NONNULL_BEGIN
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction]; TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
// MJK TODO - safe to remove senderTimestamp // MJK TODO - safe to remove senderTimestamp
[[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] [[[TSInfoMessage alloc] initWithTimestamp:NSDate.ows_millisecondTimeStamp
inThread:thread inThread:thread
messageType:TSInfoMessageTypeLokiSessionResetProgress] saveWithTransaction:transaction]; messageType:TSInfoMessageTypeLokiSessionResetInProgress] saveWithTransaction:transaction];
/* Loki original code /* Loki: Original code
* ================== * ================
[[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] [[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
inThread:thread inThread:thread
messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction]; messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction];
* ================
*/ */
/// Loki: Archive all our sessions /// Loki: Archive all our sessions
@ -1026,11 +1024,12 @@ NS_ASSUME_NONNULL_BEGIN
OWSEphemeralMessage *emptyMessage = [OWSEphemeralMessage createEmptyOutgoingMessageInThread:thread]; OWSEphemeralMessage *emptyMessage = [OWSEphemeralMessage createEmptyOutgoingMessageInThread:thread];
[self.messageSenderJobQueue addMessage:emptyMessage transaction:transaction]; [self.messageSenderJobQueue addMessage:emptyMessage transaction:transaction];
OWSLogDebug(@"[Loki Session Reset] Session reset has been received from %@", envelope.source); OWSLogDebug(@"[Loki] Session reset has been received from %@.", envelope.source);
/* Loki Original Code /* Loki: Original code
* =================== * ================
[self.primaryStorage deleteAllSessionsForContact:envelope.source protocolContext:transaction]; [self.primaryStorage deleteAllSessionsForContact:envelope.source protocolContext:transaction];
* ================
*/ */
} }
@ -1689,15 +1688,13 @@ NS_ASSUME_NONNULL_BEGIN
- (void)onNewSessionAdopted:(NSNotification *)notification { - (void)onNewSessionAdopted:(NSNotification *)notification {
NSString *pubKey = notification.userInfo[kNSNotificationKey_ContactPubKey]; NSString *pubKey = notification.userInfo[kNSNotificationKey_ContactPubKey];
if (pubKey.length == 0) { if (pubKey.length == 0) { return; }
return;
}
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
TSContactThread *_Nullable thread = [TSContactThread getThreadWithContactId:pubKey transaction:transaction]; TSContactThread *_Nullable thread = [TSContactThread getThreadWithContactId:pubKey transaction:transaction];
if (!thread) { if (!thread) {
OWSLogDebug(@"[Loki Session Reset] New session was adopted but we failed to get the thread for %@", pubKey); OWSLogDebug(@"[Loki] New session was adopted but we failed to get the thread for %@.", pubKey);
return; return;
} }
@ -1708,7 +1705,7 @@ NS_ASSUME_NONNULL_BEGIN
} }
// Show session reset done message // Show session reset done message
[[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] [[[TSInfoMessage alloc] initWithTimestamp:NSDate.ows_millisecondTimeStamp
inThread:thread inThread:thread
messageType:TSInfoMessageTypeLokiSessionResetDone] saveWithTransaction:transaction]; messageType:TSInfoMessageTypeLokiSessionResetDone] saveWithTransaction:transaction];

Loading…
Cancel
Save