1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/browser/extension_navigation_throttle.h"
#include "components/guest_view/browser/guest_view_base.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/url_constants.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/guest_view/web_view/web_view_guest.h"
#include "extensions/browser/url_request_util.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
#include "extensions/common/manifest_handlers/webview_info.h"
#include "extensions/common/permissions/api_permission.h"
#include "extensions/common/permissions/permissions_data.h"
#include "ui/base/page_transition_types.h"
namespace extensions {
ExtensionNavigationThrottle::ExtensionNavigationThrottle(
content::NavigationHandle* navigation_handle)
: content::NavigationThrottle(navigation_handle) {}
ExtensionNavigationThrottle::~ExtensionNavigationThrottle() {}
content::NavigationThrottle::ThrottleCheckResult
ExtensionNavigationThrottle::WillStartRequest() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
GURL url(navigation_handle()->GetURL());
content::WebContents* web_contents = navigation_handle()->GetWebContents();
ExtensionRegistry* registry =
ExtensionRegistry::Get(web_contents->GetBrowserContext());
if (navigation_handle()->IsInMainFrame()) {
// Block top-level navigations to blob: or filesystem: URLs with extension
// origin from non-extension processes. See https://crbug.com/645028.
bool is_nested_url = url.SchemeIsFileSystem() || url.SchemeIsBlob();
bool is_extension = false;
if (registry) {
is_extension = !!registry->enabled_extensions().GetExtensionOrAppByURL(
navigation_handle()->GetStartingSiteInstance()->GetSiteURL());
}
url::Origin origin(url);
if (is_nested_url && origin.scheme() == extensions::kExtensionScheme &&
!is_extension) {
// Relax this restriction for apps that use <webview>. See
// https://crbug.com/652077.
const extensions::Extension* extension =
registry->enabled_extensions().GetByID(origin.host());
bool has_webview_permission =
extension &&
extension->permissions_data()->HasAPIPermission(
extensions::APIPermission::kWebView);
if (!has_webview_permission)
return content::NavigationThrottle::CANCEL;
}
if (content::IsBrowserSideNavigationEnabled() &&
url.scheme() == extensions::kExtensionScheme) {
// This logic is performed for PlzNavigate sub-resources and for
// non-PlzNavigate in
// extensions::url_request_util::AllowCrossRendererResourceLoad.
const Extension* extension =
registry->enabled_extensions().GetExtensionOrAppByURL(url);
guest_view::GuestViewBase* guest =
guest_view::GuestViewBase::FromWebContents(web_contents);
if (guest) {
std::string owner_extension_id = guest->owner_host();
const Extension* owner_extension =
registry->enabled_extensions().GetByID(owner_extension_id);
std::string partition_domain, partition_id;
bool in_memory;
std::string resource_path = url.path();
bool is_guest = WebViewGuest::GetGuestPartitionConfigForSite(
navigation_handle()->GetStartingSiteInstance()->GetSiteURL(),
&partition_domain, &partition_id, &in_memory);
bool allowed = true;
url_request_util::AllowCrossRendererResourceLoadHelper(
is_guest, extension, owner_extension, partition_id, resource_path,
navigation_handle()->GetPageTransition(), &allowed);
if (!allowed)
return content::NavigationThrottle::BLOCK_REQUEST;
}
}
return content::NavigationThrottle::PROCEED;
}
// Now enforce web_accessible_resources for navigations. Top-level navigations
// should always be allowed.
// If the navigation is not to a chrome-extension:// URL, no need to perform
// any more checks.
if (!url.SchemeIs(extensions::kExtensionScheme))
return content::NavigationThrottle::PROCEED;
// The subframe which is navigated needs to have all of its ancestors be
// at the same origin, otherwise the resource needs to be explicitly listed
// in web_accessible_resources.
// Since the RenderFrameHost is not known until navigation has committed,
// we can't get it from NavigationHandle. However, this code only cares about
// the ancestor chain, so find the current RenderFrameHost and use it to
// traverse up to the main frame.
content::RenderFrameHost* navigating_frame = nullptr;
for (auto* frame : web_contents->GetAllFrames()) {
if (frame->GetFrameTreeNodeId() ==
navigation_handle()->GetFrameTreeNodeId()) {
navigating_frame = frame;
break;
}
}
DCHECK(navigating_frame);
// Traverse the chain of parent frames, checking if they are the same origin
// as the URL of this navigation.
content::RenderFrameHost* ancestor = navigating_frame->GetParent();
bool external_ancestor = false;
while (ancestor) {
if (ancestor->GetLastCommittedURL().GetOrigin() != url.GetOrigin()) {
// Ignore DevTools, as it is allowed to embed extension pages.
if (!ancestor->GetLastCommittedURL().SchemeIs(
content::kChromeDevToolsScheme)) {
external_ancestor = true;
break;
}
}
ancestor = ancestor->GetParent();
}
if (!external_ancestor)
return content::NavigationThrottle::PROCEED;
// Since there was at least one origin different than the navigation URL,
// explicitly check for the resource in web_accessible_resources.
std::string resource_path = url.path();
if (!registry)
return content::NavigationThrottle::BLOCK_REQUEST;
const extensions::Extension* extension =
registry->enabled_extensions().GetByID(url.host());
if (!extension)
return content::NavigationThrottle::BLOCK_REQUEST;
if (WebAccessibleResourcesInfo::IsResourceWebAccessible(extension,
resource_path)) {
return content::NavigationThrottle::PROCEED;
}
return content::NavigationThrottle::BLOCK_REQUEST;
}
} // namespace extensions
|