From e15ab82e3f3cc1c52173fc85c9128ffec4db4a3c Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Sat, 18 Feb 2023 01:01:22 -0500 Subject: [PATCH] Implement NSSecureCoding on MTRErrorHolder. Otherwise the errors we create cannot be usefully encoded/decoded. Fixes https://github.com/project-chip/connectedhomeip/issues/22388 --- src/darwin/Framework/CHIP/MTRError.mm | 40 ++++++++++++++++++- .../CHIPTests/MTRSetupPayloadParserTests.m | 22 ++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/darwin/Framework/CHIP/MTRError.mm b/src/darwin/Framework/CHIP/MTRError.mm index 00bd61d30bb995..b71416f16b1df1 100644 --- a/src/darwin/Framework/CHIP/MTRError.mm +++ b/src/darwin/Framework/CHIP/MTRError.mm @@ -30,7 +30,7 @@ // Class for holding on to a CHIP_ERROR that we can use as the value // in a dictionary. -@interface MTRErrorHolder : NSObject +@interface MTRErrorHolder : NSObject @property (nonatomic, readonly) CHIP_ERROR error; - (instancetype)init NS_UNAVAILABLE; @@ -299,4 +299,42 @@ - (instancetype)initWithError:(CHIP_ERROR)error return self; } +#pragma mark - NSSecureCoding + +static NSString * const MTRErrorHolderCodingKeyErrorNumber = @"MTREH.ck.errorNumber"; + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + // We don't try to save our file/line info, because that's pointing to our + // process memory, so there is no really good way to decode it on the other + // side without leaking the filename string. + [coder encodeObject:@(self.error.AsInteger()) forKey:MTRErrorHolderCodingKeyErrorNumber]; +} + +- (instancetype _Nullable)initWithCoder:(NSCoder *)decoder +{ + using namespace chip; + + NSNumber * errorNumber = [decoder decodeObjectOfClass:[NSNumber class] forKey:MTRErrorHolderCodingKeyErrorNumber]; + if (decoder == nil) { + return nil; + } + + // Use unsignedLongLongValue so we are not making assumptions about the size + // of ChipError::StorageType + auto error = static_cast(errorNumber.unsignedLongLongValue); + + return [self initWithError:ChipError(error)]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"[error: %s]", self.error.AsString()]; +} + @end diff --git a/src/darwin/Framework/CHIPTests/MTRSetupPayloadParserTests.m b/src/darwin/Framework/CHIPTests/MTRSetupPayloadParserTests.m index f52aac1c2a297a..1b1a047acd98d5 100644 --- a/src/darwin/Framework/CHIPTests/MTRSetupPayloadParserTests.m +++ b/src/darwin/Framework/CHIPTests/MTRSetupPayloadParserTests.m @@ -76,6 +76,28 @@ - (void)testOnboardingPayloadParser_QRCode_WrongVersion XCTAssertNil(payload); XCTAssertNotNil(error); + + // Use the fact that this is actually a Matter error to test our + // NSSecureCoding implementation. + XCTAssertNotNil(error.userInfo); + XCTAssertNotNil(error.userInfo[@"underlyingError"]); + + XCTAssertTrue([[error description] containsString:@"MTRSetupPayload.mm"]); + XCTAssertTrue([[error description] containsString:@"0x0000002F"]); + + NSError * encodingError; + NSData * encoded = [NSKeyedArchiver archivedDataWithRootObject:error requiringSecureCoding:YES error:&encodingError]; + XCTAssertNotNil(encoded); + XCTAssertNil(encodingError); + + NSSet * classes = [NSSet setWithObjects:[NSError class], NSClassFromString(@"MTRErrorHolder"), nil]; + NSError * decodingError; + NSError * decoded = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:encoded error:&decodingError]; + XCTAssertNotNil(decoded); + XCTAssertNil(decodingError); + + XCTAssertFalse([[decoded description] containsString:@"MTRSetupPayload.mm"]); + XCTAssertTrue([[error description] containsString:@"0x0000002F"]); } - (void)testOnboardingPayloadParser_NFC_NoError