From daab2a58af947cddd67fe9f30dd3a9fc327650c0 Mon Sep 17 00:00:00 2001
From: Chris Ballinger <chrisballinger@gmail.com>
Date: Wed, 13 Apr 2016 16:53:47 -0700
Subject: [PATCH] OLMAccount and OLMSession serialization

---
 xcode/OLMKit/OLMAccount.h           |   8 +-
 xcode/OLMKit/OLMAccount.m           | 113 ++++++++++++++++++++++++-
 xcode/OLMKit/OLMSerializable.h      |   6 +-
 xcode/OLMKit/OLMSession.h           |   6 +-
 xcode/OLMKit/OLMSession.m           | 124 ++++++++++++++++++++++------
 xcode/OLMKit/OLMSession_Private.h   |  16 ++++
 xcode/OLMKitTests/OLMKitTests.m     | 111 ++++++++++++++++++++++++-
 xcode/olm.xcodeproj/project.pbxproj |   4 +
 8 files changed, 350 insertions(+), 38 deletions(-)
 create mode 100644 xcode/OLMKit/OLMSession_Private.h

diff --git a/xcode/OLMKit/OLMAccount.h b/xcode/OLMKit/OLMAccount.h
index cfa7129..a2923f9 100644
--- a/xcode/OLMKit/OLMAccount.h
+++ b/xcode/OLMKit/OLMAccount.h
@@ -9,7 +9,9 @@
 #import <Foundation/Foundation.h>
 #import "OLMSerializable.h"
 
-@interface OLMAccount : NSObject <OLMSerializable>
+@class OLMSession;
+
+@interface OLMAccount : NSObject <OLMSerializable, NSSecureCoding>
 
 /** Creates new account */
 - (instancetype) initNewAccount;
@@ -18,11 +20,13 @@
 - (NSDictionary*) identityKeys;
 
 /** signs message with ed25519 key for account */
-- (NSData*) signMessage:(NSData*)messageData;
+- (NSString*) signMessage:(NSData*)messageData;
 
 /** Public parts of the unpublished one time keys for the account */
 - (NSDictionary*) oneTimeKeys;
 
+- (BOOL) removeOneTimeKeysForSession:(OLMSession*)session;
+
 /** Marks the current set of one time keys as being published. */
 - (void) markKeysAsPublished;
 
diff --git a/xcode/OLMKit/OLMAccount.m b/xcode/OLMKit/OLMAccount.m
index d56b6b4..4561a37 100644
--- a/xcode/OLMKit/OLMAccount.m
+++ b/xcode/OLMKit/OLMAccount.m
@@ -8,6 +8,8 @@
 
 #import "OLMAccount.h"
 #import "OLMAccount_Private.h"
+#import "OLMSession.h"
+#import "OLMSession_Private.h"
 #import "OLMUtility.h"
 
 @import Security;
@@ -34,7 +36,7 @@
     return YES;
 }
 
-- (instancetype) initNewAccount {
+- (instancetype) init {
     self = [super init];
     if (!self) {
         return nil;
@@ -43,6 +45,14 @@
     if (!success) {
         return nil;
     }
+    return self;
+}
+
+- (instancetype) initNewAccount {
+    self = [self init];
+    if (!self) {
+        return nil;
+    }
     size_t randomLength = olm_create_account_random_length(_account);
     NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength];
     size_t accountResult = olm_create_account(_account, random.mutableBytes, random.length);
@@ -114,5 +124,106 @@
     }
 }
 
+- (BOOL) removeOneTimeKeysForSession:(OLMSession *)session {
+    NSParameterAssert(session != nil);
+    if (!session) {
+        return nil;
+    }
+    size_t result = olm_remove_one_time_keys(self.account, session.session);
+    if (result == olm_error()) {
+        const char *error = olm_session_last_error(session.session);
+        NSAssert(NO, @"olm_remove_one_time_keys error: %s", error);
+        return NO;
+    }
+    return YES;
+}
+
+#pragma mark OLMSerializable
+
+/** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */
+- (instancetype) initWithSerializedData:(NSString*)serializedData key:(NSData*)key error:(NSError**)error {
+    self = [self init];
+    if (!self) {
+        return nil;
+    }
+    NSParameterAssert(key.length > 0);
+    NSParameterAssert(serializedData.length > 0);
+    if (key.length == 0 || serializedData.length == 0) {
+        if (error) {
+            *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: @"Bad length."}];
+        }
+        return nil;
+    }
+    NSMutableData *pickle = [serializedData dataUsingEncoding:NSUTF8StringEncoding].mutableCopy;
+    size_t result = olm_unpickle_account(_account, key.bytes, key.length, pickle.mutableBytes, pickle.length);
+    if (result == olm_error()) {
+        const char *olm_error = olm_account_last_error(_account);
+        NSString *errorString = [NSString stringWithUTF8String:olm_error];
+        if (error && errorString) {
+            *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
+        }
+        return nil;
+    }
+    return self;
+}
+
+/** Serializes and encrypts object data, outputs base64 blob */
+- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error {
+    NSParameterAssert(key.length > 0);
+    size_t length = olm_pickle_account_length(_account);
+    NSMutableData *pickled = [NSMutableData dataWithLength:length];
+    size_t result = olm_pickle_account(_account, key.bytes, key.length, pickled.mutableBytes, pickled.length);
+    if (result == olm_error()) {
+        const char *olm_error = olm_account_last_error(_account);
+        NSString *errorString = [NSString stringWithUTF8String:olm_error];
+        if (error && errorString) {
+            *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
+        }
+        return nil;
+    }
+    NSString *pickleString = [[NSString alloc] initWithData:pickled encoding:NSUTF8StringEncoding];
+    return pickleString;
+}
+
+#pragma mark NSSecureCoding
+
++ (BOOL) supportsSecureCoding {
+    return YES;
+}
+
+#pragma mark NSCoding
+
+- (id)initWithCoder:(NSCoder *)decoder {
+    NSString *version = [decoder decodeObjectOfClass:[NSString class] forKey:@"version"];
+    
+    NSError *error = nil;
+    
+    if ([version isEqualToString:@"1"]) {
+        NSString *pickle = [decoder decodeObjectOfClass:[NSString class] forKey:@"pickle"];
+        NSData *key = [decoder decodeObjectOfClass:[NSData class] forKey:@"key"];
+
+        self = [self initWithSerializedData:pickle key:key error:&error];
+    }
+    
+    NSParameterAssert(error == nil);
+    NSParameterAssert(self != nil);
+    if (!self) {
+        return nil;
+    }
+    
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)encoder {
+    NSData *key = [OLMUtility randomBytesOfLength:32];
+    NSError *error = nil;
+    NSString *pickle = [self serializeDataWithKey:key error:&error];
+    NSParameterAssert(pickle.length > 0 && error == nil);
+    
+    [encoder encodeObject:pickle forKey:@"pickle"];
+    [encoder encodeObject:key forKey:@"key"];
+    [encoder encodeObject:@"1" forKey:@"version"];
+}
+
 
 @end
diff --git a/xcode/OLMKit/OLMSerializable.h b/xcode/OLMKit/OLMSerializable.h
index afacdaa..b4b115a 100644
--- a/xcode/OLMKit/OLMSerializable.h
+++ b/xcode/OLMKit/OLMSerializable.h
@@ -11,9 +11,9 @@
 @protocol OLMSerializable <NSObject>
 
 /** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */
-- (instancetype) initWithSerializedData:(NSData*)serializedData key:(NSData*)key error:(NSError**)error;
+- (instancetype) initWithSerializedData:(NSString*)serializedData key:(NSData*)key error:(NSError**)error;
 
-/** Serializes and encrypts object data */
-- (NSData*) serializeDataWithKey:(NSData*)key;
+/** Serializes and encrypts object data, outputs base64 blob */
+- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error;
 
 @end
diff --git a/xcode/OLMKit/OLMSession.h b/xcode/OLMKit/OLMSession.h
index 1a075e4..c209564 100644
--- a/xcode/OLMKit/OLMSession.h
+++ b/xcode/OLMKit/OLMSession.h
@@ -11,9 +11,7 @@
 #import "OLMAccount.h"
 #import "OLMMessage.h"
 
-@interface OLMSession : NSObject <OLMSerializable>
-
-@property (nonatomic, strong) OLMAccount *account;
+@interface OLMSession : NSObject <OLMSerializable, NSSecureCoding>
 
 - (instancetype) initOutboundSessionWithAccount:(OLMAccount*)account theirIdentityKey:(NSString*)theirIdentityKey theirOneTimeKey:(NSString*)theirOneTimeKey;
 
@@ -27,8 +25,6 @@
 
 - (BOOL) matchesInboundSessionFrom:(NSString*)theirIdentityKey oneTimeKeyMessage:(NSString *)oneTimeKeyMessage;
 
-- (BOOL) removeOneTimeKeys;
-
 /** UTF-8 plaintext -> base64 ciphertext */
 - (OLMMessage*) encryptMessage:(NSString*)message;
 
diff --git a/xcode/OLMKit/OLMSession.m b/xcode/OLMKit/OLMSession.m
index fa7cb62..119079f 100644
--- a/xcode/OLMKit/OLMSession.m
+++ b/xcode/OLMKit/OLMSession.m
@@ -9,12 +9,9 @@
 #import "OLMSession.h"
 #import "OLMUtility.h"
 #import "OLMAccount_Private.h"
+#import "OLMSession_Private.h"
 @import olm;
 
-@interface OLMSession()
-@property (nonatomic) OlmSession *session;
-@end
-
 @implementation OLMSession
 
 - (void) dealloc {
@@ -37,7 +34,7 @@
     return YES;
 }
 
-- (instancetype) initWithAccount:(OLMAccount*)account {
+- (instancetype) init {
     self = [super init];
     if (!self) {
         return nil;
@@ -46,6 +43,18 @@
     if (!success) {
         return nil;
     }
+    return self;
+}
+
+- (instancetype) initWithAccount:(OLMAccount*)account {
+    self = [self init];
+    if (!self) {
+        return nil;
+    }
+    NSParameterAssert(account != nil &&  account.account != NULL);
+    if (account == nil || account.account == NULL) {
+        return nil;
+    }
     _account = account;
     return self;
 }
@@ -72,10 +81,6 @@
     if (!self) {
         return nil;
     }
-    BOOL success = [self initializeSessionMemory];
-    if (!success) {
-        return nil;
-    }
     NSMutableData *otk = [NSMutableData dataWithData:[oneTimeKeyMessage dataUsingEncoding:NSUTF8StringEncoding]];
     size_t result = olm_create_inbound_session(_session, account.account, otk.mutableBytes, oneTimeKeyMessage.length);
     if (result == olm_error()) {
@@ -91,10 +96,6 @@
     if (!self) {
         return nil;
     }
-    BOOL success = [self initializeSessionMemory];
-    if (!success) {
-        return nil;
-    }
     NSData *idKey = [theirIdentityKey dataUsingEncoding:NSUTF8StringEncoding];
     NSMutableData *otk = [NSMutableData dataWithData:[oneTimeKeyMessage dataUsingEncoding:NSUTF8StringEncoding]];
     size_t result = olm_create_inbound_session_from(_session, account.account, idKey.bytes, idKey.length, otk.mutableBytes, otk.length);
@@ -143,16 +144,6 @@
     return encryptedMessage;
 }
 
-- (BOOL) removeOneTimeKeys {
-    size_t result = olm_remove_one_time_keys(_account.account, _session);
-    if (result == olm_error()) {
-        const char *error = olm_session_last_error(_session);
-        NSAssert(NO, @"olm_remove_one_time_keys error: %s", error);
-        return NO;
-    }
-    return YES;
-}
-
 - (NSString*) decryptMessage:(OLMMessage*)message {
     NSParameterAssert(message != nil);
     NSData *messageData = [message.ciphertext dataUsingEncoding:NSUTF8StringEncoding];
@@ -180,4 +171,91 @@
     return plaintext;
 }
 
+#pragma mark OLMSerializable
+
+/** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */
+- (instancetype) initWithSerializedData:(NSString*)serializedData key:(NSData*)key error:(NSError**)error {
+    self = [self init];
+    if (!self) {
+        return nil;
+    }
+    NSParameterAssert(key.length > 0);
+    NSParameterAssert(serializedData.length > 0);
+    if (key.length == 0 || serializedData.length == 0) {
+        if (error) {
+            *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: @"Bad length."}];
+        }
+        return nil;
+    }
+    NSMutableData *pickle = [serializedData dataUsingEncoding:NSUTF8StringEncoding].mutableCopy;
+    size_t result = olm_unpickle_session(_session, key.bytes, key.length, pickle.mutableBytes, pickle.length);
+    if (result == olm_error()) {
+        const char *olm_error = olm_session_last_error(_session);
+        NSString *errorString = [NSString stringWithUTF8String:olm_error];
+        if (error && errorString) {
+            *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
+        }
+        return nil;
+    }
+    return self;
+}
+
+/** Serializes and encrypts object data, outputs base64 blob */
+- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error {
+    NSParameterAssert(key.length > 0);
+    size_t length = olm_pickle_session_length(_session);
+    NSMutableData *pickled = [NSMutableData dataWithLength:length];
+    size_t result = olm_pickle_session(_session, key.bytes, key.length, pickled.mutableBytes, pickled.length);
+    if (result == olm_error()) {
+        const char *olm_error = olm_session_last_error(_session);
+        NSString *errorString = [NSString stringWithUTF8String:olm_error];
+        if (error && errorString) {
+            *error = [NSError errorWithDomain:@"org.matrix.olm" code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
+        }
+        return nil;
+    }
+    NSString *pickleString = [[NSString alloc] initWithData:pickled encoding:NSUTF8StringEncoding];
+    return pickleString;
+}
+
+#pragma mark NSSecureCoding
+
++ (BOOL) supportsSecureCoding {
+    return YES;
+}
+
+#pragma mark NSCoding
+
+- (id)initWithCoder:(NSCoder *)decoder {
+    NSString *version = [decoder decodeObjectOfClass:[NSString class] forKey:@"version"];
+    
+    NSError *error = nil;
+    
+    if ([version isEqualToString:@"1"]) {
+        NSString *pickle = [decoder decodeObjectOfClass:[NSString class] forKey:@"pickle"];
+        NSData *key = [decoder decodeObjectOfClass:[NSData class] forKey:@"key"];
+        
+        self = [self initWithSerializedData:pickle key:key error:&error];
+    }
+    
+    NSParameterAssert(error == nil);
+    NSParameterAssert(self != nil);
+    if (!self) {
+        return nil;
+    }
+    
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)encoder {
+    NSData *key = [OLMUtility randomBytesOfLength:32];
+    NSError *error = nil;
+    NSString *pickle = [self serializeDataWithKey:key error:&error];
+    NSParameterAssert(pickle.length > 0 && error == nil);
+    
+    [encoder encodeObject:pickle forKey:@"pickle"];
+    [encoder encodeObject:key forKey:@"key"];
+    [encoder encodeObject:@"1" forKey:@"version"];
+}
+
 @end
diff --git a/xcode/OLMKit/OLMSession_Private.h b/xcode/OLMKit/OLMSession_Private.h
new file mode 100644
index 0000000..d906b14
--- /dev/null
+++ b/xcode/OLMKit/OLMSession_Private.h
@@ -0,0 +1,16 @@
+//
+//  OLMSession_Private.h
+//  olm
+//
+//  Created by Chris Ballinger on 4/13/16.
+//
+//
+
+@import olm;
+
+@interface OLMSession()
+
+@property (nonatomic) OlmSession *session;
+@property (nonatomic, strong) OLMAccount *account;
+
+@end
\ No newline at end of file
diff --git a/xcode/OLMKitTests/OLMKitTests.m b/xcode/OLMKitTests/OLMKitTests.m
index 7075057..c76d636 100644
--- a/xcode/OLMKitTests/OLMKitTests.m
+++ b/xcode/OLMKitTests/OLMKitTests.m
@@ -25,9 +25,7 @@
     [super tearDown];
 }
 
-- (void)testExample {
-    // This is an example of a functional test case.
-    // Use XCTAssert and related functions to verify your tests produce the correct results.
+- (void)testAliceAndBob {
     OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
     OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
     [bob generateOneTimeKeys:5];
@@ -50,9 +48,114 @@
     OLMSession *bobSession = [[OLMSession alloc] initInboundSessionWithAccount:bob oneTimeKeyMessage:aliceToBobMsg.ciphertext];
     NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg];
     XCTAssertEqualObjects(message, plaintext);
-    BOOL success = [bobSession removeOneTimeKeys];
+    BOOL success = [bob removeOneTimeKeysForSession:bobSession];
     XCTAssertTrue(success);
 }
 
+- (void) testBackAndForth {
+    OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
+    OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
+    [bob generateOneTimeKeys:1];
+    NSDictionary *bobIdKeys = bob.identityKeys;
+    NSString *bobIdKey = bobIdKeys[@"curve25519"];
+    NSDictionary *bobOneTimeKeys = bob.oneTimeKeys;
+    NSParameterAssert(bobIdKey != nil);
+    NSParameterAssert(bobOneTimeKeys != nil);
+    __block NSString *bobOneTimeKey = nil;
+    NSDictionary *bobOtkCurve25519 = bobOneTimeKeys[@"curve25519"];
+    [bobOtkCurve25519 enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
+        bobOneTimeKey = obj;
+    }];
+    XCTAssert([bobOneTimeKey isKindOfClass:[NSString class]]);
+    
+    OLMSession *aliceSession = [[OLMSession alloc] initOutboundSessionWithAccount:alice theirIdentityKey:bobIdKey theirOneTimeKey:bobOneTimeKey];
+    NSString *message = @"Hello I'm Alice!";
+    OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message];
+    
+    OLMSession *bobSession = [[OLMSession alloc] initInboundSessionWithAccount:bob oneTimeKeyMessage:aliceToBobMsg.ciphertext];
+    NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg];
+    XCTAssertEqualObjects(message, plaintext);
+    BOOL success = [bob removeOneTimeKeysForSession:bobSession];
+    XCTAssertTrue(success);
+    
+    NSString *msg1 = @"Hello I'm Bob!";
+    NSString *msg2 = @"Isn't life grand?";
+    NSString *msg3 = @"Let's go to the opera.";
+    
+    OLMMessage *eMsg1 = [bobSession encryptMessage:msg1];
+    OLMMessage *eMsg2 = [bobSession encryptMessage:msg2];
+    OLMMessage *eMsg3 = [bobSession encryptMessage:msg3];
+    
+    NSString *dMsg1 = [aliceSession decryptMessage:eMsg1];
+    NSString *dMsg2 = [aliceSession decryptMessage:eMsg2];
+    NSString *dMsg3 = [aliceSession decryptMessage:eMsg3];
+    XCTAssertEqualObjects(msg1, dMsg1);
+    XCTAssertEqualObjects(msg2, dMsg2);
+    XCTAssertEqualObjects(msg3, dMsg3);
+
+    
+}
+
+- (void) testAccountSerialization {
+    OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
+    [bob generateOneTimeKeys:5];
+    NSDictionary *bobIdKeys = bob.identityKeys;
+    NSDictionary *bobOneTimeKeys = bob.oneTimeKeys;
+    
+    NSData *bobData = [NSKeyedArchiver archivedDataWithRootObject:bob];
+    
+    OLMAccount *bob2 = [NSKeyedUnarchiver unarchiveObjectWithData:bobData];
+    NSDictionary *bobIdKeys2 = bob2.identityKeys;
+    NSDictionary *bobOneTimeKeys2 = bob.oneTimeKeys;
+    
+    XCTAssertEqualObjects(bobIdKeys, bobIdKeys2);
+    XCTAssertEqualObjects(bobOneTimeKeys, bobOneTimeKeys2);
+}
+
+- (void) testSessionSerialization {
+    OLMAccount *alice = [[OLMAccount alloc] initNewAccount];
+    OLMAccount *bob = [[OLMAccount alloc] initNewAccount];
+    [bob generateOneTimeKeys:1];
+    NSDictionary *bobIdKeys = bob.identityKeys;
+    NSString *bobIdKey = bobIdKeys[@"curve25519"];
+    NSDictionary *bobOneTimeKeys = bob.oneTimeKeys;
+    NSParameterAssert(bobIdKey != nil);
+    NSParameterAssert(bobOneTimeKeys != nil);
+    __block NSString *bobOneTimeKey = nil;
+    NSDictionary *bobOtkCurve25519 = bobOneTimeKeys[@"curve25519"];
+    [bobOtkCurve25519 enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
+        bobOneTimeKey = obj;
+    }];
+    XCTAssert([bobOneTimeKey isKindOfClass:[NSString class]]);
+    
+    OLMSession *aliceSession = [[OLMSession alloc] initOutboundSessionWithAccount:alice theirIdentityKey:bobIdKey theirOneTimeKey:bobOneTimeKey];
+    NSString *message = @"Hello I'm Alice!";
+    OLMMessage *aliceToBobMsg = [aliceSession encryptMessage:message];
+    
+    OLMSession *bobSession = [[OLMSession alloc] initInboundSessionWithAccount:bob oneTimeKeyMessage:aliceToBobMsg.ciphertext];
+    NSString *plaintext = [bobSession decryptMessage:aliceToBobMsg];
+    XCTAssertEqualObjects(message, plaintext);
+    BOOL success = [bob removeOneTimeKeysForSession:bobSession];
+    XCTAssertTrue(success);
+    
+    NSString *msg1 = @"Hello I'm Bob!";
+    NSString *msg2 = @"Isn't life grand?";
+    NSString *msg3 = @"Let's go to the opera.";
+    
+    OLMMessage *eMsg1 = [bobSession encryptMessage:msg1];
+    OLMMessage *eMsg2 = [bobSession encryptMessage:msg2];
+    OLMMessage *eMsg3 = [bobSession encryptMessage:msg3];
+    
+    NSData *aliceData = [NSKeyedArchiver archivedDataWithRootObject:aliceSession];
+    OLMSession *alice2 = [NSKeyedUnarchiver unarchiveObjectWithData:aliceData];
+    
+    NSString *dMsg1 = [alice2 decryptMessage:eMsg1];
+    NSString *dMsg2 = [alice2 decryptMessage:eMsg2];
+    NSString *dMsg3 = [alice2 decryptMessage:eMsg3];
+    XCTAssertEqualObjects(msg1, dMsg1);
+    XCTAssertEqualObjects(msg2, dMsg2);
+    XCTAssertEqualObjects(msg3, dMsg3);
+}
+
 
 @end
diff --git a/xcode/olm.xcodeproj/project.pbxproj b/xcode/olm.xcodeproj/project.pbxproj
index b1a62b0..6c6fa32 100644
--- a/xcode/olm.xcodeproj/project.pbxproj
+++ b/xcode/olm.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		D9401CDC1CBF10BD003DD078 /* OLMSession_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D9401CDB1CBF10BD003DD078 /* OLMSession_Private.h */; };
 		D976E4411CB852E000F5C124 /* OLMKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D976E4401CB852E000F5C124 /* OLMKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		D976E4481CB852E000F5C124 /* OLMKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D976E43E1CB852E000F5C124 /* OLMKit.framework */; };
 		D976E44D1CB852E000F5C124 /* OLMKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D976E44C1CB852E000F5C124 /* OLMKitTests.m */; };
@@ -37,6 +38,7 @@
 		0A0809C67039D4BDCE9CE9AF /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
 		235C5A0B708438C11BCE552C /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		81B8A7B31F3BA6548ACC45DE /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
+		D9401CDB1CBF10BD003DD078 /* OLMSession_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLMSession_Private.h; sourceTree = "<group>"; };
 		D976E43E1CB852E000F5C124 /* OLMKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OLMKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		D976E4401CB852E000F5C124 /* OLMKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OLMKit.h; sourceTree = "<group>"; };
 		D976E4421CB852E000F5C124 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -115,6 +117,7 @@
 				D976E4671CB8696100F5C124 /* OLMAccount_Private.h */,
 				D976E4561CB8536500F5C124 /* OLMAccount.m */,
 				D976E4591CB8538300F5C124 /* OLMSession.h */,
+				D9401CDB1CBF10BD003DD078 /* OLMSession_Private.h */,
 				D976E45A1CB8538300F5C124 /* OLMSession.m */,
 				D976E45D1CB8538E00F5C124 /* OLMUtility.h */,
 				D976E45E1CB8538E00F5C124 /* OLMUtility.m */,
@@ -139,6 +142,7 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				D9401CDC1CBF10BD003DD078 /* OLMSession_Private.h in Headers */,
 				D976E45B1CB8538300F5C124 /* OLMSession.h in Headers */,
 				D976E4681CB8787D00F5C124 /* OLMAccount_Private.h in Headers */,
 				D976E4651CB8674900F5C124 /* OLMMessage.h in Headers */,
-- 
GitLab