From c26a54a295dabb7f9f611038e5c20b002699d9c9 Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Thu, 16 Nov 2023 14:42:21 -0800 Subject: [PATCH] Messaging: Adopt NSSecureCoding for internal classes (#12110) --- FirebaseMessaging/CHANGELOG.md | 3 ++ .../Sources/Token/FIRMessagingAPNSInfo.h | 2 +- .../Sources/Token/FIRMessagingAPNSInfo.m | 4 ++ .../Sources/Token/FIRMessagingTokenInfo.h | 2 +- .../Sources/Token/FIRMessagingTokenInfo.m | 43 +++++-------------- .../UnitTests/FIRMessagingAPNSInfoTest.m | 17 +++++--- .../UnitTests/FIRMessagingAuthKeychainTest.m | 31 +++++++------ .../UnitTests/FIRMessagingTokenInfoTest.m | 30 ++++++++----- 8 files changed, 69 insertions(+), 63 deletions(-) diff --git a/FirebaseMessaging/CHANGELOG.md b/FirebaseMessaging/CHANGELOG.md index 29547cc0808..8a509e949bc 100644 --- a/FirebaseMessaging/CHANGELOG.md +++ b/FirebaseMessaging/CHANGELOG.md @@ -1,3 +1,6 @@ +# 10.19.0 +- [changed] Adopt NSSecureCoding for internal classes. (#12075) + # 10.12.0 - [changed] Removing fiam scoped tokens set by old FIAM SDK(s) from keychain if exists (b/284207019). diff --git a/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.h b/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.h index 4cf700f9dcd..dae9ff4c363 100644 --- a/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.h +++ b/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.h @@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN * Represents an APNS device token and whether its environment is for sandbox. * It can read from and write to an NSDictionary for simple serialization. */ -@interface FIRMessagingAPNSInfo : NSObject +@interface FIRMessagingAPNSInfo : NSObject /// The APNs device token, provided by the OS to the application delegate @property(nonatomic, readonly, copy) NSData *deviceToken; diff --git a/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.m b/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.m index 2a76e9c1364..6bf33f9b5d6 100644 --- a/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.m +++ b/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.m @@ -70,6 +70,10 @@ - (id)copyWithZone:(NSZone *)zone { #pragma mark - NSCoding ++ (BOOL)supportsSecureCoding { + return YES; +} + - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { id deviceToken = [aDecoder decodeObjectForKey:kFIRInstanceIDAPNSInfoTokenKey]; if (![deviceToken isKindOfClass:[NSData class]]) { diff --git a/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h b/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h index 3b4f64db754..415b0398a84 100644 --- a/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h +++ b/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN * associated with it. It can read from and write to an NSDictionary object, for * simple serialization. */ -@interface FIRMessagingTokenInfo : NSObject +@interface FIRMessagingTokenInfo : NSObject /// The authorized entity (also known as Sender ID), associated with the token. @property(nonatomic, readonly, copy) NSString *authorizedEntity; diff --git a/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.m b/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.m index 335e52ff910..7589912cdc6 100644 --- a/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.m +++ b/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.m @@ -133,7 +133,11 @@ - (BOOL)isDefaultToken { return [self.scope isEqualToString:kFIRMessagingDefaultTokenScope]; } -#pragma mark - NSCoding +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { // These value cannot be nil @@ -164,30 +168,13 @@ - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { if (firebaseAppID && ![firebaseAppID isKindOfClass:[NSString class]]) { return nil; } - - id rawAPNSInfo = [aDecoder decodeObjectForKey:kFIRInstanceIDAPNSInfoKey]; - if (rawAPNSInfo && ![rawAPNSInfo isKindOfClass:[NSData class]]) { + NSSet *classes = [[NSSet alloc] initWithArray:@[ FIRMessagingAPNSInfo.class ]]; + FIRMessagingAPNSInfo *rawAPNSInfo = [aDecoder decodeObjectOfClasses:classes + forKey:kFIRInstanceIDAPNSInfoKey]; + if (rawAPNSInfo && ![rawAPNSInfo isKindOfClass:[FIRMessagingAPNSInfo class]]) { return nil; } - FIRMessagingAPNSInfo *APNSInfo = nil; - if (rawAPNSInfo) { - // TODO(chliangGoogle: Use the new API and secureCoding protocol. - @try { - [NSKeyedUnarchiver setClass:[FIRMessagingAPNSInfo class] - forClassName:@"FIRInstanceIDAPNSInfo"]; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - APNSInfo = [NSKeyedUnarchiver unarchiveObjectWithData:rawAPNSInfo]; -#pragma clang diagnostic pop - } @catch (NSException *exception) { - FIRMessagingLoggerInfo(kFIRMessagingMessageCodeTokenInfoBadAPNSInfo, - @"Could not parse raw APNS Info while parsing archived token info."); - APNSInfo = nil; - } @finally { - } - } - id cacheTime = [aDecoder decodeObjectForKey:kFIRInstanceIDCacheTimeKey]; if (cacheTime && ![cacheTime isKindOfClass:[NSDate class]]) { return nil; @@ -200,7 +187,7 @@ - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { _token = [token copy]; _appVersion = [appVersion copy]; _firebaseAppID = [firebaseAppID copy]; - _APNSInfo = [APNSInfo copy]; + _APNSInfo = [rawAPNSInfo copy]; _cacheTime = cacheTime; } return self; @@ -212,16 +199,8 @@ - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:self.token forKey:kFIRInstanceIDTokenKey]; [aCoder encodeObject:self.appVersion forKey:kFIRInstanceIDAppVersionKey]; [aCoder encodeObject:self.firebaseAppID forKey:kFIRInstanceIDFirebaseAppIDKey]; - NSData *rawAPNSInfo; if (self.APNSInfo) { - // TODO(chliangGoogle: Use the new API and secureCoding protocol. - [NSKeyedArchiver setClassName:@"FIRInstanceIDAPNSInfo" forClass:[FIRMessagingAPNSInfo class]]; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - rawAPNSInfo = [NSKeyedArchiver archivedDataWithRootObject:self.APNSInfo]; -#pragma clang diagnostic pop - - [aCoder encodeObject:rawAPNSInfo forKey:kFIRInstanceIDAPNSInfoKey]; + [aCoder encodeObject:self.APNSInfo forKey:kFIRInstanceIDAPNSInfoKey]; } [aCoder encodeObject:self.cacheTime forKey:kFIRInstanceIDCacheTimeKey]; } diff --git a/FirebaseMessaging/Tests/UnitTests/FIRMessagingAPNSInfoTest.m b/FirebaseMessaging/Tests/UnitTests/FIRMessagingAPNSInfoTest.m index e52e90ecf2e..4c9c4d51beb 100644 --- a/FirebaseMessaging/Tests/UnitTests/FIRMessagingAPNSInfoTest.m +++ b/FirebaseMessaging/Tests/UnitTests/FIRMessagingAPNSInfoTest.m @@ -72,15 +72,20 @@ - (void)testAPNSInfoCreationWithInvalidSandboxFormat { - (void)testAPNSInfoEncodingAndDecoding { NSDictionary *validDictionary = @{ kFIRMessagingTokenOptionsAPNSKey : [@"tokenData" dataUsingEncoding:NSUTF8StringEncoding], - kFIRMessagingTokenOptionsAPNSIsSandboxKey : @"sandboxValueAsString" + kFIRMessagingTokenOptionsAPNSIsSandboxKey : @1234 }; + NSError *error; FIRMessagingAPNSInfo *info = [[FIRMessagingAPNSInfo alloc] initWithTokenOptionsDictionary:validDictionary]; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:info]; - FIRMessagingAPNSInfo *restoredInfo = [NSKeyedUnarchiver unarchiveObjectWithData:archive]; -#pragma clang diagnostic pop + NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:info + requiringSecureCoding:YES + error:&error]; + XCTAssertNil(error); + NSSet *classes = [[NSSet alloc] initWithArray:@[ FIRMessagingAPNSInfo.class, NSData.class ]]; + FIRMessagingAPNSInfo *restoredInfo = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes + fromData:archive + error:&error]; + XCTAssertNil(error); XCTAssertEqualObjects(info.deviceToken, restoredInfo.deviceToken); XCTAssertEqual(info.sandbox, restoredInfo.sandbox); } diff --git a/FirebaseMessaging/Tests/UnitTests/FIRMessagingAuthKeychainTest.m b/FirebaseMessaging/Tests/UnitTests/FIRMessagingAuthKeychainTest.m index 798679e39cc..ce11a757230 100644 --- a/FirebaseMessaging/Tests/UnitTests/FIRMessagingAuthKeychainTest.m +++ b/FirebaseMessaging/Tests/UnitTests/FIRMessagingAuthKeychainTest.m @@ -101,16 +101,19 @@ - (void)testKeyChainNoCorruptionWithUniqueAccount { // Now query the token and compare, they should not corrupt // each other. NSData *data1 = [weakKeychain dataForService:service account:account1]; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" FIRMessagingTokenInfo *tokenInfo1 = - [NSKeyedUnarchiver unarchiveObjectWithData:data1]; + [NSKeyedUnarchiver unarchivedObjectOfClass:FIRMessagingTokenInfo.class + fromData:data1 + error:&error]; + XCTAssertNil(error); XCTAssertEqualObjects(kToken1, tokenInfo1.token); NSData *data2 = [weakKeychain dataForService:service account:account2]; FIRMessagingTokenInfo *tokenInfo2 = - [NSKeyedUnarchiver unarchiveObjectWithData:data2]; -#pragma clang diagnostic pop + [NSKeyedUnarchiver unarchivedObjectOfClass:FIRMessagingTokenInfo.class + fromData:data2 + error:&error]; + XCTAssertNil(error); XCTAssertEqualObjects(kToken2, tokenInfo2.token); // Also check the cache data. XCTAssertEqual(weakKeychain.cachedKeychainData.count, 1); @@ -175,11 +178,11 @@ - (void)testKeyChainNoCorruptionWithUniqueService { // Now query the token and compare, they should not corrupt // each other. NSData *data1 = [weakKeychain dataForService:service1 account:account]; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" FIRMessagingTokenInfo *tokenInfo1 = - [NSKeyedUnarchiver unarchiveObjectWithData:data1]; -#pragma clang diagnostic pop + [NSKeyedUnarchiver unarchivedObjectOfClass:FIRMessagingTokenInfo.class + fromData:data1 + error:&error]; + XCTAssertNil(error); XCTAssertEqualObjects(kToken1, tokenInfo1.token); NSData *data2 = [weakKeychain dataForService:service2 account:account]; @@ -413,10 +416,12 @@ - (NSData *)tokenDataWithAuthorizedEntity:(NSString *)authorizedEntity token:token appVersion:@"1.0" firebaseAppID:kFirebaseAppID]; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - return [NSKeyedArchiver archivedDataWithRootObject:tokenInfo]; -#pragma clang diagnostic pop + NSError *error; + NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:tokenInfo + requiringSecureCoding:YES + error:&error]; + XCTAssertNil(error); + return archive; } @end diff --git a/FirebaseMessaging/Tests/UnitTests/FIRMessagingTokenInfoTest.m b/FirebaseMessaging/Tests/UnitTests/FIRMessagingTokenInfoTest.m index b29dda1ebf2..76dceb1c23d 100644 --- a/FirebaseMessaging/Tests/UnitTests/FIRMessagingTokenInfoTest.m +++ b/FirebaseMessaging/Tests/UnitTests/FIRMessagingTokenInfoTest.m @@ -76,11 +76,16 @@ - (void)tearDown { // yields the same values for all the fields. - (void)testTokenInfoEncodingAndDecoding { FIRMessagingTokenInfo *info = self.validTokenInfo; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:info]; - FIRMessagingTokenInfo *restoredInfo = [NSKeyedUnarchiver unarchiveObjectWithData:archive]; -#pragma clang diagnostic pop + NSError *error; + NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:info + requiringSecureCoding:YES + error:&error]; + XCTAssertNil(error); + NSSet *classes = [[NSSet alloc] initWithArray:@[ FIRMessagingTokenInfo.class, NSDate.class ]]; + FIRMessagingTokenInfo *restoredInfo = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes + fromData:archive + error:&error]; + XCTAssertNil(error); XCTAssertEqualObjects(restoredInfo.authorizedEntity, info.authorizedEntity); XCTAssertEqualObjects(restoredInfo.scope, info.scope); XCTAssertEqualObjects(restoredInfo.token, info.token); @@ -101,11 +106,16 @@ - (void)testTokenInfoEncodingAndDecodingWithMissingFields { token:kToken appVersion:nil firebaseAppID:nil]; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:sparseInfo]; - FIRMessagingTokenInfo *restoredInfo = [NSKeyedUnarchiver unarchiveObjectWithData:archive]; -#pragma clang diagnostic pop + NSError *error; + NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:sparseInfo + requiringSecureCoding:YES + error:&error]; + XCTAssertNil(error); + NSSet *classes = [[NSSet alloc] initWithArray:@[ FIRMessagingTokenInfo.class, NSDate.class ]]; + FIRMessagingTokenInfo *restoredInfo = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes + fromData:archive + error:&error]; + XCTAssertNil(error); XCTAssertEqualObjects(restoredInfo.authorizedEntity, sparseInfo.authorizedEntity); XCTAssertEqualObjects(restoredInfo.scope, sparseInfo.scope); XCTAssertEqualObjects(restoredInfo.token, sparseInfo.token);