Skip to content

Commit

Permalink
Messaging: Adopt NSSecureCoding for internal classes (#12110)
Browse files Browse the repository at this point in the history
  • Loading branch information
paulb777 authored Nov 16, 2023
1 parent b891c92 commit c26a54a
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 63 deletions.
3 changes: 3 additions & 0 deletions FirebaseMessaging/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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).

Expand Down
2 changes: 1 addition & 1 deletion FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <NSCoding, NSCopying>
@interface FIRMessagingAPNSInfo : NSObject <NSSecureCoding, NSCopying>

/// The APNs device token, provided by the OS to the application delegate
@property(nonatomic, readonly, copy) NSData *deviceToken;
Expand Down
4 changes: 4 additions & 0 deletions FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -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]]) {
Expand Down
2 changes: 1 addition & 1 deletion FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <NSCoding>
@interface FIRMessagingTokenInfo : NSObject <NSSecureCoding>

/// The authorized entity (also known as Sender ID), associated with the token.
@property(nonatomic, readonly, copy) NSString *authorizedEntity;
Expand Down
43 changes: 11 additions & 32 deletions FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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];
}
Expand Down
17 changes: 11 additions & 6 deletions FirebaseMessaging/Tests/UnitTests/FIRMessagingAPNSInfoTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
31 changes: 18 additions & 13 deletions FirebaseMessaging/Tests/UnitTests/FIRMessagingAuthKeychainTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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

Expand Down
30 changes: 20 additions & 10 deletions FirebaseMessaging/Tests/UnitTests/FIRMessagingTokenInfoTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit c26a54a

Please sign in to comment.