From 3fd112e4520682b7613db50fda55068313b3af5f Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 5 Nov 2020 15:22:34 -0300 Subject: [PATCH 1/7] Persistent Dictionary: Wiring constants --- Simperium/SPPersistentMutableDictionary.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Simperium/SPPersistentMutableDictionary.m b/Simperium/SPPersistentMutableDictionary.m index 49e72aac..cef617e1 100644 --- a/Simperium/SPPersistentMutableDictionary.m +++ b/Simperium/SPPersistentMutableDictionary.m @@ -245,12 +245,12 @@ - (NSManagedObjectModel *)managedObjectModel { // Dynamic Attributes NSAttributeDescription *keyAttribute = [[NSAttributeDescription alloc] init]; - keyAttribute.name = @"key"; + keyAttribute.name = SPDictionaryEntityKey; keyAttribute.attributeType = NSStringAttributeType; keyAttribute.optional = NO; NSAttributeDescription *valueAttribute = [[NSAttributeDescription alloc] init]; - valueAttribute.name = @"value"; + valueAttribute.name = SPDictionaryEntityValue; valueAttribute.attributeType = NSBinaryDataAttributeType; valueAttribute.optional = NO; From 1ea17092f3393d162304fe6173340795b9b127b2 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 5 Nov 2020 15:22:56 -0300 Subject: [PATCH 2/7] Persistent Dictionary: New Supported Types property --- Simperium/SPPersistentMutableDictionary.h | 1 + Simperium/SPPersistentMutableDictionary.m | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/Simperium/SPPersistentMutableDictionary.h b/Simperium/SPPersistentMutableDictionary.h index 51850701..0e7d1d03 100644 --- a/Simperium/SPPersistentMutableDictionary.h +++ b/Simperium/SPPersistentMutableDictionary.h @@ -17,6 +17,7 @@ @interface SPPersistentMutableDictionary : NSObject @property (nonatomic, strong, readonly) NSString *label; +@property (nonatomic, strong, readwrite) NSSet *supportedObjectTypes; - (NSInteger)count; - (BOOL)containsObjectForKey:(id)aKey; diff --git a/Simperium/SPPersistentMutableDictionary.m b/Simperium/SPPersistentMutableDictionary.m index cef617e1..925166f3 100644 --- a/Simperium/SPPersistentMutableDictionary.m +++ b/Simperium/SPPersistentMutableDictionary.m @@ -48,6 +48,11 @@ - (instancetype)initWithLabel:(NSString *)label { if (self) { self.label = label; self.cache = [[NSCache alloc] init]; + self.supportedObjectTypes = [NSSet setWithArray:@[ + [NSDictionary class], + [NSArray class], + [NSString class] + ]]; } return self; From db1a88c89724c71cfcf713684e76b6829c89d51b Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 5 Nov 2020 15:26:24 -0300 Subject: [PATCH 3/7] Persistent Dictionary: Documents Public API --- Simperium/SPPersistentMutableDictionary.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Simperium/SPPersistentMutableDictionary.h b/Simperium/SPPersistentMutableDictionary.h index 0e7d1d03..b31a2b32 100644 --- a/Simperium/SPPersistentMutableDictionary.h +++ b/Simperium/SPPersistentMutableDictionary.h @@ -16,14 +16,32 @@ @interface SPPersistentMutableDictionary : NSObject +/// The Dictionary's Label is used to define the Persistent Store identifier. Different labels will map to different persistent databases. +/// @property (nonatomic, strong, readonly) NSString *label; + +/// Specifies the Supported Types +/// @property (nonatomic, strong, readwrite) NSSet *supportedObjectTypes; +/// Returns the total number of stored entities +/// - (NSInteger)count; + +/// Indicates if there's an object associated ot the specified Key +/// - (BOOL)containsObjectForKey:(id)aKey; +/// Returns an object associated to the specified Key. Note that the resulting Object Type will be constrained by the `supportedObjectTypes` collection +/// - (id)objectForKey:(NSString*)aKey; + +/// Stores the specified Object. Please note that the Object's Type must be specified by the `supportedObjectTypes` collection +/// - (void)setObject:(id)anObject forKey:(NSString*)aKey; + +/// Persists the internal stack +/// - (BOOL)save; - (NSArray*)allKeys; From 7af83a6d80daac8a31c985841407218ebfb3a6ba Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 5 Nov 2020 15:58:59 -0300 Subject: [PATCH 4/7] Persistent Dictionary: Secure Coding Support --- Simperium/SPPersistentMutableDictionary.h | 8 ++++- Simperium/SPPersistentMutableDictionary.m | 43 +++++++++++++++++------ 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/Simperium/SPPersistentMutableDictionary.h b/Simperium/SPPersistentMutableDictionary.h index b31a2b32..4519614e 100644 --- a/Simperium/SPPersistentMutableDictionary.h +++ b/Simperium/SPPersistentMutableDictionary.h @@ -21,8 +21,14 @@ @property (nonatomic, strong, readonly) NSString *label; /// Specifies the Supported Types +/// - Note: All classes specified here must conform to NSSecureCoding /// -@property (nonatomic, strong, readwrite) NSSet *supportedObjectTypes; +@property (nonatomic, strong, readwrite) NSSet *supportedObjectTypes; + +/// Indicates if the stored `Supported Object Types` should be required to conform to NSCoding. Defaults to YES +/// +@property (nonatomic, assign, readwrite) BOOL requiringSecureCoding; + /// Returns the total number of stored entities /// diff --git a/Simperium/SPPersistentMutableDictionary.m b/Simperium/SPPersistentMutableDictionary.m index 925166f3..eceaf2e5 100644 --- a/Simperium/SPPersistentMutableDictionary.m +++ b/Simperium/SPPersistentMutableDictionary.m @@ -47,7 +47,8 @@ - (instancetype)initWithLabel:(NSString *)label { self = [super init]; if (self) { self.label = label; - self.cache = [[NSCache alloc] init]; + self.cache = [NSCache new]; + self.requiringSecureCoding = YES; self.supportedObjectTypes = [NSSet setWithArray:@[ [NSDictionary class], [NSArray class], @@ -116,7 +117,9 @@ - (id)objectForKey:(id)aKey { // Unarchive id archivedValue = [object valueForKey:SPDictionaryEntityValue]; if (archivedValue) { - value = [NSKeyedUnarchiver unarchiveObjectWithData:archivedValue]; + value = [NSKeyedUnarchiver unarchivedObjectOfClasses:self.supportedObjectTypes + fromData:archivedValue + error:nil]; } } }]; @@ -136,6 +139,8 @@ - (void)setObject:(id)anObject forKey:(NSString*)aKey { return; } + NSAssert([self canStoreObject:anObject], @"Unsupported Object Type"); + [self.managedObjectContext performBlock:^{ NSError *error = nil; @@ -151,9 +156,11 @@ - (void)setObject:(id)anObject forKey:(NSString*)aKey { change = [NSEntityDescription insertNewObjectForEntityForName:SPDictionaryEntityName inManagedObjectContext:self.managedObjectContext]; [change setValue:aKey forKey:SPDictionaryEntityKey]; } - + // Wrap up the value - id archivedValue = [NSKeyedArchiver archivedDataWithRootObject:anObject]; + id archivedValue = [NSKeyedArchiver archivedDataWithRootObject:anObject + requiringSecureCoding:self.requiringSecureCoding + error:nil]; [change setValue:archivedValue forKey:SPDictionaryEntityValue]; }]; @@ -439,7 +446,7 @@ - (NSFetchRequest *)requestForEntityWithKey:(id)aKey { } - (NSArray *)loadObjectsProperty:(NSString*)property unarchive:(BOOL)unarchive { - NSMutableArray *keys = [NSMutableArray array]; + NSMutableArray *output = [NSMutableArray array]; [self.managedObjectContext performBlockAndWait:^{ @@ -455,15 +462,31 @@ - (NSArray *)loadObjectsProperty:(NSString*)property unarchive:(BOOL)unarchive { continue; } - if (unarchive) { - [keys addObject:[NSKeyedUnarchiver unarchiveObjectWithData:value]]; - } else { - [keys addObject:value]; + if (!unarchive) { + [output addObject:value]; + continue;; + } + + id decodedValue = [NSKeyedUnarchiver unarchivedObjectOfClasses:self.supportedObjectTypes + fromData:value + error:nil]; + if (decodedValue) { + [output addObject:decodedValue]; } } }]; - return keys; + return output; +} + +- (BOOL)canStoreObject:(id)anObject { + for (Class supportedClass in self.supportedObjectTypes) { + if ([anObject isKindOfClass:supportedClass]) { + return YES; + } + } + + return NO; } @end From 8713e54e207e2200cac3ae8a297239bd93b583b4 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 5 Nov 2020 15:59:12 -0300 Subject: [PATCH 5/7] Persistent Dictionary: New Test --- .../SPPersistentMutableDictionaryTests.m | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/SimperiumTests/SPPersistentMutableDictionaryTests.m b/SimperiumTests/SPPersistentMutableDictionaryTests.m index 0fc2406d..cf886903 100644 --- a/SimperiumTests/SPPersistentMutableDictionaryTests.m +++ b/SimperiumTests/SPPersistentMutableDictionaryTests.m @@ -176,12 +176,34 @@ - (void)testStressReopeningMutableDictionaryInBackground { [self waitForExpectationsWithTimeout:SPStressTimeout handler:nil]; } +- (void)testDictionaryStoredWithSecureCodingCanBeLoadedByDictionaryWithoutSecureCoding { + NSString *label = [NSString sp_makeUUID]; + SPPersistentMutableDictionary *insecureStorage = [SPPersistentMutableDictionary loadDictionaryWithLabel:label]; + insecureStorage.requiringSecureCoding = NO; + + NSDictionary *samples = [self sampleKeyValues]; + for (NSString *key in samples.allKeys) { + [insecureStorage setObject:samples[key] forKey:key]; + } + + [insecureStorage save]; + + SPPersistentMutableDictionary *secureStorage = [SPPersistentMutableDictionary loadDictionaryWithLabel:label]; + insecureStorage.requiringSecureCoding = YES; + for (NSString *key in samples.allKeys) { + id retrievedValue = [secureStorage objectForKey:key]; + id expectedValue = samples[key]; + + XCTAssertTrue([retrievedValue isEqual:expectedValue]); + } +} + #pragma mark ==================================================================================== #pragma mark Helpers #pragma mark ==================================================================================== -- (NSDictionary*)randomContentObject { +- (NSDictionary *)randomContentObject { NSMutableDictionary *random = [NSMutableDictionary dictionary]; for (NSInteger i = 0; ++i <= SPMetadataIterations; ) { @@ -191,4 +213,12 @@ - (NSDictionary*)randomContentObject { return random; } +- (NSDictionary *)sampleKeyValues { + return @{ + @"1" : @"YO! Yosemite!", + @"2" : @{ @1234: @"567" }, + @"3" : @[ @1, @"2" ] + }; +} + @end From 2e8773cc271cf5a4443424e16a6f71fa184ab369 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 6 Nov 2020 11:24:20 -0300 Subject: [PATCH 6/7] Persistent Dictionary: Adds comment --- Simperium/SPPersistentMutableDictionary.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Simperium/SPPersistentMutableDictionary.h b/Simperium/SPPersistentMutableDictionary.h index 4519614e..47a15d97 100644 --- a/Simperium/SPPersistentMutableDictionary.h +++ b/Simperium/SPPersistentMutableDictionary.h @@ -26,6 +26,7 @@ @property (nonatomic, strong, readwrite) NSSet *supportedObjectTypes; /// Indicates if the stored `Supported Object Types` should be required to conform to NSCoding. Defaults to YES +/// - Important: Only used for Unit Testing purposes! /// @property (nonatomic, assign, readwrite) BOOL requiringSecureCoding; From 82554ea91e051fed5591ffe582220ee5f52a5984 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 6 Nov 2020 11:43:54 -0300 Subject: [PATCH 7/7] Updates to Mk 1.1.0 --- Simperium.xcodeproj/project.pbxproj | 8 ++++---- Simperium/SPEnvironment.m | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Simperium.xcodeproj/project.pbxproj b/Simperium.xcodeproj/project.pbxproj index 5d2ce65b..e77c639d 100644 --- a/Simperium.xcodeproj/project.pbxproj +++ b/Simperium.xcodeproj/project.pbxproj @@ -2099,7 +2099,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.1.0; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = com.automattic.simperium; PRODUCT_NAME = Simperium; @@ -2150,7 +2150,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.1.0; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = com.automattic.simperium; PRODUCT_NAME = Simperium; @@ -2207,7 +2207,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.13; - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.1.0; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = com.automattic.simperium; PRODUCT_NAME = Simperium; @@ -2259,7 +2259,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.13; - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.1.0; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = com.automattic.simperium; PRODUCT_NAME = Simperium; diff --git a/Simperium/SPEnvironment.m b/Simperium/SPEnvironment.m index b8caa8bb..43bc9ce5 100644 --- a/Simperium/SPEnvironment.m +++ b/Simperium/SPEnvironment.m @@ -30,7 +30,7 @@ #endif // TODO: Update this automatically via a script that looks at current git tag -NSString* const SPLibraryVersion = @"1.0.0"; +NSString* const SPLibraryVersion = @"1.1.0"; /// SSL Pinning ///