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