Skip to content

Commit 24864a1

Browse files
fix(ios): validate packager messages before parsing
1 parent f821613 commit 24864a1

3 files changed

Lines changed: 86 additions & 2 deletions

File tree

packages/react-native/React/DevSupport/RCTPackagerConnection.mm

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,14 +262,30 @@ - (void)reconnectingWebSocketDidOpen:(__unused RCTReconnectingWebSocket *)webSoc
262262

263263
- (void)reconnectingWebSocket:(RCTReconnectingWebSocket *)webSocket didReceiveMessage:(id)message
264264
{
265+
if (![message isKindOfClass:[NSString class]]) {
266+
RCTLogError(@"%@ received a packager message with an unsupported type %@", [self class], [message class]);
267+
return;
268+
}
269+
265270
NSError *error = nil;
266-
NSDictionary<NSString *, id> *msg = RCTJSONParse(message, &error);
271+
id parsedMessage = RCTJSONParse((NSString *)message, &error);
267272

268273
if (error) {
269-
RCTLogError(@"%@ failed to parse message with error %@\n<message>\n%@\n</message>", [self class], error, msg);
274+
RCTLogError(
275+
@"%@ failed to parse message with error %@\n<message>\n%@\n</message>", [self class], error, message);
270276
return;
271277
}
272278

279+
if (![parsedMessage isKindOfClass:[NSDictionary class]]) {
280+
RCTLogError(
281+
@"%@ received a packager message that was not a JSON object\n<message>\n%@\n</message>",
282+
[self class],
283+
message);
284+
return;
285+
}
286+
287+
NSDictionary<NSString *, id> *msg = parsedMessage;
288+
273289
if (!isSupportedVersion(msg[@"version"])) {
274290
RCTLogError(@"%@ received message with not supported version %@", [self class], msg[@"version"]);
275291
return;

packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
8145AE06241172D900A3F8DA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8145AE05241172D900A3F8DA /* LaunchScreen.storyboard */; };
1919
832F45BB2A8A6E1F0097B4E6 /* SwiftTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 832F45BA2A8A6E1F0097B4E6 /* SwiftTest.swift */; };
2020
A975CA6C2C05EADF0043F72A /* RCTNetworkTaskTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A975CA6B2C05EADE0043F72A /* RCTNetworkTaskTests.m */; };
21+
B4810BCE2F3D4A5B6C7D8E9F /* RCTPackagerConnectionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B4810BCD2F3D4A5B6C7D8E9F /* RCTPackagerConnectionTests.m */; };
2122
C175B6D9ED9336FB66637943 /* libPods-RNTester.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C706D402EE4AF9BE838CBA9 /* libPods-RNTester.a */; };
2223
CD10C7A5290BD4EB0033E1ED /* RCTEventEmitterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD10C7A4290BD4EB0033E1ED /* RCTEventEmitterTests.m */; };
2324
E62F11832A5C6580000BF1C8 /* FlexibleSizeExampleView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.mm */; };
@@ -96,6 +97,7 @@
9697
832F45BA2A8A6E1F0097B4E6 /* SwiftTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SwiftTest.swift; path = RNTester/SwiftTest.swift; sourceTree = "<group>"; };
9798
93A243F0D4D5C54911E811C4 /* libPods-RNTesterIntegrationTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNTesterIntegrationTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
9899
A975CA6B2C05EADE0043F72A /* RCTNetworkTaskTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTNetworkTaskTests.m; sourceTree = "<group>"; };
100+
B4810BCD2F3D4A5B6C7D8E9F /* RCTPackagerConnectionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTPackagerConnectionTests.m; sourceTree = "<group>"; };
99101
AC474BFB29BBD4A1002BDAED /* RNTester.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = RNTester.xctestplan; path = RNTester/RNTester.xctestplan; sourceTree = "<group>"; };
100102
B0E70A8A05E03E868F8703FE /* Pods-RNTesterIntegrationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTesterIntegrationTests.release.xcconfig"; path = "Target Support Files/Pods-RNTesterIntegrationTests/Pods-RNTesterIntegrationTests.release.xcconfig"; sourceTree = "<group>"; };
101103
CA59C9994B1822826D8983F0 /* Pods-RNTester.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTester.debug.xcconfig"; path = "Target Support Files/Pods-RNTester/Pods-RNTester.debug.xcconfig"; sourceTree = "<group>"; };
@@ -337,6 +339,7 @@
337339
F1A0B1C23D4E5F6071829301 /* RCTTurboModuleArrayBufferTests.mm */,
338340
E7DB20CF22B2BAA5005AC45F /* RCTMultipartStreamReaderTests.m */,
339341
A975CA6B2C05EADE0043F72A /* RCTNetworkTaskTests.m */,
342+
B4810BCD2F3D4A5B6C7D8E9F /* RCTPackagerConnectionTests.m */,
340343
E7DB20BE22B2BAA4005AC45F /* RCTNativeAnimatedNodesManagerTests.m */,
341344
E7DB20AD22B2BAA3005AC45F /* RCTPerformanceLoggerTests.m */,
342345
E7DB20C122B2BAA4005AC45F /* RCTUnicodeDecodeTests.m */,
@@ -741,6 +744,7 @@
741744
buildActionMask = 2147483647;
742745
files = (
743746
A975CA6C2C05EADF0043F72A /* RCTNetworkTaskTests.m in Sources */,
747+
B4810BCE2F3D4A5B6C7D8E9F /* RCTPackagerConnectionTests.m in Sources */,
744748
E7DB20DF22B2BAA6005AC45F /* RCTImageLoaderTests.m in Sources */,
745749
E7DB20D222B2BAA6005AC45F /* RCTModuleInitNotificationRaceTests.m in Sources */,
746750
E7DB20D522B2BAA6005AC45F /* RCTPerformanceLoggerTests.m in Sources */,
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#import <XCTest/XCTest.h>
9+
10+
#import <React/RCTPackagerClient.h>
11+
#import <React/RCTPackagerConnection.h>
12+
#import <React/RCTReconnectingWebSocket.h>
13+
14+
@interface RCTPackagerConnection (Testing)
15+
16+
- (void)reconnectingWebSocket:(RCTReconnectingWebSocket *)webSocket didReceiveMessage:(id)message;
17+
18+
@end
19+
20+
@interface RCTPackagerConnectionTests : XCTestCase
21+
22+
@end
23+
24+
@implementation RCTPackagerConnectionTests
25+
26+
- (void)testIgnoresBinaryMessages
27+
{
28+
RCTPackagerConnection *connection = [RCTPackagerConnection new];
29+
NSData *message = [@"{}" dataUsingEncoding:NSUTF8StringEncoding];
30+
31+
XCTAssertNoThrow([connection reconnectingWebSocket:nil didReceiveMessage:message]);
32+
}
33+
34+
- (void)testIgnoresNonObjectMessages
35+
{
36+
RCTPackagerConnection *connection = [RCTPackagerConnection new];
37+
38+
XCTAssertNoThrow([connection reconnectingWebSocket:nil didReceiveMessage:@"[]"]);
39+
}
40+
41+
- (void)testDispatchesValidNotification
42+
{
43+
XCTestExpectation *expectation = [self expectationWithDescription:@"Notification handler is called"];
44+
__block NSDictionary<NSString *, id> *receivedParams;
45+
RCTPackagerConnection *connection = [RCTPackagerConnection new];
46+
dispatch_queue_t queue = dispatch_queue_create("RCTPackagerConnectionTests", DISPATCH_QUEUE_SERIAL);
47+
48+
[connection addNotificationHandler:^(NSDictionary<NSString *, id> *params) {
49+
receivedParams = params;
50+
[expectation fulfill];
51+
}
52+
queue:queue
53+
forMethod:@"reload"];
54+
55+
NSString *message = [NSString stringWithFormat:
56+
@"{\"version\":%d,\"method\":\"reload\",\"params\":{\"value\":1}}",
57+
RCT_PACKAGER_CLIENT_PROTOCOL_VERSION];
58+
[connection reconnectingWebSocket:nil didReceiveMessage:message];
59+
60+
[self waitForExpectations:@[ expectation ] timeout:1.0];
61+
XCTAssertEqualObjects(receivedParams, (@{ @"value" : @1 }));
62+
}
63+
64+
@end

0 commit comments

Comments
 (0)