Skip to content

Commit d28849c

Browse files
authored
[#8485] Added URL Recovery for IAM URLs (#8486)
* URL strings in in-app messages are sanitized and, when possible, recovered before they’re used in the `NSURL` initializer * Added validation for image URLs, which must use the HTTPS scheme, according to the Firebase Console * Updated `FIRIAMFetchResponseParserTests` to test URL validation and recovery
1 parent f7bd6b5 commit d28849c

File tree

3 files changed

+82
-7
lines changed

3 files changed

+82
-7
lines changed

Diff for: FirebaseInAppMessaging/Sources/Data/FIRIAMFetchResponseParser.m

+26-6
Original file line numberDiff line numberDiff line change
@@ -287,12 +287,10 @@ - (FIRIAMMessageDefinition *)convertToMessageDefinitionWithMessageDict:(NSDictio
287287
return nil;
288288
}
289289

290-
NSURL *imageURL = (imageURLStr.length == 0) ? nil : [NSURL URLWithString:imageURLStr];
291-
NSURL *landscapeImageURL =
292-
(landscapeImageURLStr.length == 0) ? nil : [NSURL URLWithString:landscapeImageURLStr];
293-
NSURL *actionURL = (actionURLStr.length == 0) ? nil : [NSURL URLWithString:actionURLStr];
294-
NSURL *secondaryActionURL =
295-
(secondaryActionURLStr.length == 0) ? nil : [NSURL URLWithString:secondaryActionURLStr];
290+
NSURL *imageURL = [self imageURLFromURLString:imageURLStr];
291+
NSURL *landscapeImageURL = [self imageURLFromURLString:landscapeImageURLStr];
292+
NSURL *actionURL = [self urlFromURLString:actionURLStr];
293+
NSURL *secondaryActionURL = [self urlFromURLString:secondaryActionURLStr];
296294
FIRIAMRenderingEffectSetting *renderEffect =
297295
[FIRIAMRenderingEffectSetting getDefaultRenderingEffectSetting];
298296
renderEffect.viewMode = mode;
@@ -376,6 +374,28 @@ - (FIRIAMMessageDefinition *)convertToMessageDefinitionWithMessageDict:(NSDictio
376374
return nil;
377375
}
378376
}
377+
378+
- (nullable NSURL *)imageURLFromURLString:(NSString *)string {
379+
NSURL *url = [self urlFromURLString:string];
380+
381+
// Image URLs must be valid HTTPS links, according to the Firebase Console.
382+
if (![url.scheme.lowercaseString isEqualToString:@"https"]) return nil;
383+
384+
return url;
385+
}
386+
387+
- (nullable NSURL *)urlFromURLString:(NSString *)string {
388+
NSString *sanitizedString = [self sanitizedURLStringFromString:string];
389+
390+
if (sanitizedString.length == 0) return nil;
391+
392+
return [NSURL URLWithString:sanitizedString];
393+
}
394+
395+
- (NSString *)sanitizedURLStringFromString:(NSString *)string {
396+
return [string stringByReplacingOccurrencesOfString:@" " withString:@""];
397+
}
398+
379399
@end
380400

381401
#endif // TARGET_OS_IOS || TARGET_OS_TV

Diff for: FirebaseInAppMessaging/Tests/Unit/FIRIAMFetchResponseParserTests.m

+9-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ - (void)testRegularConversion {
7272
XCTAssertEqualWithAccuracy([fetchWaitTime doubleValue],
7373
nextFetchEpochTimeInResponse / 1000 - currentMoment, 0.1);
7474

75-
XCTAssertEqual(6, [results count]);
75+
XCTAssertEqual(7, [results count]);
7676
XCTAssertEqual(0, discardCount);
7777

7878
FIRIAMMessageDefinition *first = results[0];
@@ -147,6 +147,14 @@ - (void)testRegularConversion {
147147
XCTAssertNotNil(sixth.experimentPayload);
148148
XCTAssertEqual(FIRIAMRenderAsModalView, sixth.renderData.renderingEffectSettings.viewMode);
149149
XCTAssertEqual(1, sixth.renderTriggers.count);
150+
151+
FIRIAMMessageDefinition *seventh = results[6];
152+
XCTAssertEqualObjects(@"https://example.com/recoverable_image_url",
153+
seventh.renderData.contentData.imageURL.absoluteString);
154+
XCTAssertEqualObjects(nil, seventh.renderData.contentData.landscapeImageURL.absoluteString);
155+
XCTAssertEqualObjects(@"http://example.com/recoverable_action_url_without_https",
156+
seventh.renderData.contentData.actionURL.absoluteString);
157+
XCTAssertEqualObjects(nil, seventh.renderData.contentData.secondaryActionURL.absoluteString);
150158
}
151159

152160
- (void)testParsingTestMessage {

Diff for: FirebaseInAppMessaging/Tests/Unit/TestJsonDataFromFetch.txt

+47
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,53 @@
258258
"fiamTrigger": "ON_FOREGROUND"
259259
}
260260
]
261+
},
262+
{
263+
"vanillaPayload": {
264+
"campaignId": "1234567890",
265+
"campaignStartTimeMillis": "1519934650000",
266+
"campaignEndTimeMillis": "9223372036854775807",
267+
"campaignName": "URL Validation"
268+
},
269+
"content": {
270+
"card": {
271+
"title": {
272+
"text": "Let’s check some weird URLs!",
273+
"hexColor": "#004953"
274+
},
275+
"portraitImageUrl": " https:// example.com/ recoverable_image_url ",
276+
"landscapeImageUrl": "http://example.com/image_url_without_https.jpg",
277+
"primaryActionButton": {
278+
"text": {
279+
"text": "Malformatted but Recoverable URL",
280+
"hexColor": "#000000"
281+
},
282+
"buttonHexColor": "#ffffff"
283+
},
284+
"secondaryActionButton": {
285+
"text": {
286+
"text": "Invalid URL",
287+
"hexColor": "#000000"
288+
},
289+
"buttonHexColor": "#ffffff"
290+
},
291+
"primaryAction": {
292+
"actionUrl": "http:// example.com / recoverable_action_url_without_https "
293+
},
294+
"secondaryAction": {
295+
"actionUrl": "NOT ^ A ^ URL"
296+
},
297+
"backgroundHexColor": "#ffffff"
298+
}
299+
},
300+
"priority": {
301+
"value": 1
302+
},
303+
"triggeringConditions": [
304+
{
305+
"fiamTrigger": "ON_FOREGROUND"
306+
}
307+
]
261308
}
262309
],
263310
"expirationEpochTimestampMillis": "1537896430193"

0 commit comments

Comments
 (0)