Commit eee00efa authored by mrefaat's avatar mrefaat Committed by Commit Bot

Block URLs with Chrome Bundle URL scheme from Launching in iframes.

More context in crbug.com/822518

Bug: 850760, 822518
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: I66e86fdc9813456ead16b1c43c41ac218ff2ac0a
Reviewed-on: https://chromium-review.googlesource.com/1147861
Commit-Queue: Mohammad Refaat <mrefaat@chromium.org>
Reviewed-by: default avatarPeter Lee <pkl@chromium.org>
Reviewed-by: default avatarDanyao Wang <danyao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#578489}
parent b4311e1d
......@@ -32,6 +32,7 @@ source_set("unit_tests") {
deps = [
":app_launcher",
"//base",
"//ios/chrome/browser",
"//ios/chrome/browser/web:web_internal",
"//ios/web/public/test/fakes",
"//testing/gtest",
......
......@@ -8,8 +8,10 @@
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#import "base/strings/sys_string_conversions.h"
#include "components/reading_list/core/reading_list_model.h"
#import "ios/chrome/browser/app_launcher/app_launcher_tab_helper_delegate.h"
#import "ios/chrome/browser/chrome_url_util.h"
#include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
#import "ios/chrome/browser/tabs/legacy_tab_helper.h"
#import "ios/chrome/browser/tabs/tab.h"
......@@ -48,6 +50,14 @@ bool IsValidAppUrl(const GURL& app_url) {
return true;
}
// Returns True if |app_url| has a Chrome bundle URL scheme.
bool HasChromeAppScheme(const GURL& app_url) {
NSArray* chrome_schemes =
[[ChromeAppConstants sharedInstance] getAllBundleURLSchemes];
NSString* app_url_scheme = base::SysUTF8ToNSString(app_url.scheme());
return [chrome_schemes containsObject:app_url_scheme];
}
// This enum used by the Applauncher to log to UMA, if App launching request was
// allowed or blocked.
// These values are persisted to logs. Entries should not be renumbered and
......@@ -155,18 +165,18 @@ bool AppLauncherTabHelper::ShouldAllowRequest(
return true;
}
ExternalURLRequestStatus request_status = ExternalURLRequestStatus::kCount;
if (request_info.target_frame_is_main) {
// TODO(crbug.com/852489): Check if the source frame should also be
// considered.
request_status = ExternalURLRequestStatus::kMainFrameRequestAllowed;
} else {
request_status = request_info.has_user_gesture
? ExternalURLRequestStatus::kSubFrameRequestAllowed
: ExternalURLRequestStatus::kSubFrameRequestBlocked;
ExternalURLRequestStatus request_status =
ExternalURLRequestStatus::kMainFrameRequestAllowed;
// TODO(crbug.com/852489): Check if the source frame should also be
// considered.
if (!request_info.target_frame_is_main) {
request_status = ExternalURLRequestStatus::kSubFrameRequestAllowed;
// Don't allow navigations from iframe to apps if there is no user gesture
// or the URL scheme is for Chrome app.
if (!request_info.has_user_gesture || HasChromeAppScheme(request_url)) {
request_status = ExternalURLRequestStatus::kSubFrameRequestBlocked;
}
}
DCHECK_NE(request_status, ExternalURLRequestStatus::kCount);
UMA_HISTOGRAM_ENUMERATION("WebController.ExternalURLRequestBlocking",
request_status, ExternalURLRequestStatus::kCount);
// Request is blocked.
......
......@@ -8,6 +8,7 @@
#include "base/compiler_specific.h"
#import "ios/chrome/browser/app_launcher/app_launcher_tab_helper_delegate.h"
#import "ios/chrome/browser/chrome_url_util.h"
#import "ios/chrome/browser/web/app_launcher_abuse_detector.h"
#import "ios/web/public/test/fakes/test_navigation_manager.h"
#import "ios/web/public/test/fakes/test_web_state.h"
......@@ -219,4 +220,27 @@ TEST_F(AppLauncherTabHelperTest, InsecureUrls) {
/*has_user_gesture=*/false));
EXPECT_EQ(0U, delegate_.countOfAppsLaunched);
}
// Tests that URLs with Chrome Bundle schemes are blocked on iframes.
TEST_F(AppLauncherTabHelperTest, ChromeBundleUrlScheme) {
// Get the test bundle URL Scheme.
NSString* scheme = [[ChromeAppConstants sharedInstance] getBundleURLScheme];
NSString* url = [NSString stringWithFormat:@"%@://www.google.com", scheme];
EXPECT_FALSE(TestShouldAllowRequest(url,
/*target_frame_is_main=*/false,
/*has_user_gesture=*/false));
EXPECT_EQ(0U, delegate_.countOfAppsLaunched);
EXPECT_FALSE(TestShouldAllowRequest(url,
/*target_frame_is_main=*/false,
/*has_user_gesture=*/true));
EXPECT_EQ(0U, delegate_.countOfAppsLaunched);
// Chrome Bundle URL scheme is only allowed from main frames.
EXPECT_FALSE(TestShouldAllowRequest(url,
/*target_frame_is_main=*/true,
/*has_user_gesture=*/false));
EXPECT_EQ(1U, delegate_.countOfAppsLaunched);
}
} // namespace
......@@ -35,6 +35,9 @@ bool IsHandledProtocol(const std::string& scheme);
// Returns the URL scheme that launches Chrome.
- (NSString*)getBundleURLScheme;
// Returns all the URL schemes that are registered on the Application Bundle.
- (NSArray*)getAllBundleURLSchemes;
// Method to set the scheme to callback Chrome iOS for testing.
- (void)setCallbackSchemeForTesting:(NSString*)callbackScheme;
......
......@@ -51,6 +51,7 @@ bool IsHandledProtocol(const std::string& scheme) {
@implementation ChromeAppConstants {
NSString* _callbackScheme;
NSArray* _schemes;
}
+ (ChromeAppConstants*)sharedInstance {
......@@ -63,20 +64,27 @@ bool IsHandledProtocol(const std::string& scheme) {
NSSet* allowableSchemes =
[NSSet setWithObjects:@"googlechrome", @"chromium",
@"ios-chrome-unittests.http", nil];
NSArray* schemes = [self getAllBundleURLSchemes];
for (NSString* scheme in schemes) {
if ([allowableSchemes containsObject:scheme])
_callbackScheme = [scheme copy];
}
}
DCHECK([_callbackScheme length]);
return _callbackScheme;
}
- (NSArray*)getAllBundleURLSchemes {
if (!_schemes) {
NSDictionary* info = [[NSBundle mainBundle] infoDictionary];
NSArray* urlTypes = [info objectForKey:@"CFBundleURLTypes"];
for (NSDictionary* urlType in urlTypes) {
DCHECK([urlType isKindOfClass:[NSDictionary class]]);
NSArray* schemes =
base::mac::ObjCCastStrict<NSArray>(urlType[@"CFBundleURLSchemes"]);
for (NSString* scheme in schemes) {
if ([allowableSchemes containsObject:scheme])
_callbackScheme = [scheme copy];
}
_schemes = [base::mac::ObjCCastStrict<NSArray>(
urlType[@"CFBundleURLSchemes"]) copy];
}
}
DCHECK([_callbackScheme length]);
return _callbackScheme;
return _schemes;
}
- (void)setCallbackSchemeForTesting:(NSString*)scheme {
......
......@@ -72,4 +72,15 @@ TEST_F(ChromeURLUtilTest, GetBundleURLScheme) {
[constants setCallbackSchemeForTesting:originalScheme];
}
TEST_F(ChromeURLUtilTest, GetAllBundleURLSchemes) {
// Verifies that there is at least 3 scheme (regular, secure and callback).
ChromeAppConstants* constants = [ChromeAppConstants sharedInstance];
NSArray* schemes = [constants getAllBundleURLSchemes];
EXPECT_GT([schemes count], 2U);
// Verifies that at least the main unit test scheme is in returned schemes.
NSString* unittestScheme = @"ios-chrome-unittests.http";
EXPECT_TRUE([schemes containsObject:unittestScheme]);
}
} // namespace
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment