Commit 899c3bff authored by Mathieu Perreault's avatar Mathieu Perreault Committed by Commit Bot

[Local NTP] Add config.js as top-level instead of dynamically added.

To load the NTP faster, we include config.js data in the local ntp
page's initial resources instead of later added by local_ntp.js

To achieve this, we refactor into the SearchConfigProvider and cache
the config data. It will be recomputed on Search provider change.

We also now declare the CSP as part of a <meta> tag instead of headers,
since in URLDataSource the headers are created on the IO thread and
the response on the UI thread. Doing everything in the local_ntp.html
response avoids races nicely.

Bug: 868432
Change-Id: Iab38ca2b2e032a58c2d404938065a612b08cc69a
Reviewed-on: https://chromium-review.googlesource.com/1154687Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Commit-Queue: Mathieu Perreault <mathp@chromium.org>
Cr-Commit-Position: refs/heads/master@{#579553}
parent 638112da
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
<link rel="stylesheet" href="chrome-search://local-ntp/local-ntp.css"></link> <link rel="stylesheet" href="chrome-search://local-ntp/local-ntp.css"></link>
<link rel="stylesheet" href="chrome-search://local-ntp/voice.css"></link> <link rel="stylesheet" href="chrome-search://local-ntp/voice.css"></link>
<link rel="stylesheet" href="chrome-search://local-ntp/custom-backgrounds.css"></link> <link rel="stylesheet" href="chrome-search://local-ntp/custom-backgrounds.css"></link>
<meta http-equiv="Content-Security-Policy"
content="{{CONTENT_SECURITY_POLICY}}">
<script src="chrome-search://local-ntp/config.js"
{{CONFIG_DATA_INTEGRITY}}></script>
<script src="chrome-search://local-ntp/custom-backgrounds.js" <script src="chrome-search://local-ntp/custom-backgrounds.js"
{{LOCAL_NTP_CUSTOM_BG_INTEGRITY}}></script> {{LOCAL_NTP_CUSTOM_BG_INTEGRITY}}></script>
<script src="chrome-search://local-ntp/local-ntp.js" <script src="chrome-search://local-ntp/local-ntp.js"
......
...@@ -1092,20 +1092,11 @@ function init() { ...@@ -1092,20 +1092,11 @@ function init() {
} }
function loadConfig() {
var configScript = document.createElement('script');
configScript.type = 'text/javascript';
configScript.src = 'chrome-search://local-ntp/config.js';
configScript.onload = init;
document.head.appendChild(configScript);
}
/** /**
* Binds event listeners. * Binds event listeners.
*/ */
function listen() { function listen() {
document.addEventListener('DOMContentLoaded', loadConfig); document.addEventListener('DOMContentLoaded', init);
} }
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#include "components/strings/grit/components_strings.h" #include "components/strings/grit/components_strings.h"
#include "content/public/browser/browser_accessibility_state.h" #include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "crypto/sha2.h"
#include "net/base/url_util.h" #include "net/base/url_util.h"
#include "net/url_request/url_request.h" #include "net/url_request/url_request.h"
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
...@@ -247,43 +248,6 @@ std::unique_ptr<base::DictionaryValue> GetTranslatedStrings(bool is_google) { ...@@ -247,43 +248,6 @@ std::unique_ptr<base::DictionaryValue> GetTranslatedStrings(bool is_google) {
return translated_strings; return translated_strings;
} }
// Returns a JS dictionary of configuration data for the local NTP.
std::string GetConfigData(bool is_google, const GURL& google_base_url) {
base::DictionaryValue config_data;
config_data.Set("translatedStrings", GetTranslatedStrings(is_google));
config_data.SetBoolean("isGooglePage", is_google);
config_data.SetString("googleBaseUrl", google_base_url.spec());
config_data.SetBoolean(
"isAccessibleBrowser",
content::BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser());
bool is_voice_search_enabled =
base::FeatureList::IsEnabled(features::kVoiceSearchOnLocalNtp);
config_data.SetBoolean("isVoiceSearchEnabled", is_voice_search_enabled);
config_data.SetBoolean("isMDUIEnabled", features::IsMDUIEnabled());
config_data.SetBoolean("isMDIconsEnabled", features::IsMDIconsEnabled());
if (is_google) {
config_data.SetBoolean("isCustomLinksEnabled",
features::IsCustomLinksEnabled());
config_data.SetBoolean("isCustomBackgroundsEnabled",
features::IsCustomBackgroundsEnabled());
}
// Serialize the dictionary.
std::string js_text;
JSONStringValueSerializer serializer(&js_text);
serializer.Serialize(config_data);
std::string config_data_js;
config_data_js.append("var configData = ");
config_data_js.append(js_text);
config_data_js.append(";");
return config_data_js;
}
std::string GetThemeCSS(Profile* profile) { std::string GetThemeCSS(Profile* profile) {
SkColor background_color = SkColor background_color =
ThemeService::GetThemeProviderForProfile(profile) ThemeService::GetThemeProviderForProfile(profile)
...@@ -480,29 +444,6 @@ bool ShouldServiceRequestIOThread(const GURL& url, ...@@ -480,29 +444,6 @@ bool ShouldServiceRequestIOThread(const GURL& url,
return false; return false;
} }
std::string GetContentSecurityPolicyScriptSrcIOThread() {
#if !defined(GOOGLE_CHROME_BUILD)
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kLocalNtpReload)) {
// While live-editing the local NTP files, turn off CSP.
return "script-src * 'unsafe-inline';";
}
#endif // !defined(GOOGLE_CHROME_BUILD)
return base::StringPrintf(
"script-src 'strict-dynamic' 'sha256-%s' 'sha256-%s' 'sha256-%s';",
LOCAL_NTP_JS_INTEGRITY, VOICE_JS_INTEGRITY,
CUSTOM_BACKGROUNDS_JS_INTEGRITY);
}
std::string GetContentSecurityPolicyChildSrcIOThread() {
// Allow embedding of the most visited iframe, as well as the account
// switcher and the notifications dropdown from the One Google Bar, and/or
// the iframe for interactive Doodles.
return base::StringPrintf("child-src %s https://*.google.com/;",
chrome::kChromeSearchMostVisitedUrl);
}
std::string GetErrorDict(const ErrorInfo& error) { std::string GetErrorDict(const ErrorInfo& error) {
base::DictionaryValue error_info; base::DictionaryValue error_info;
error_info.SetBoolean("auth_error", error_info.SetBoolean("auth_error",
...@@ -521,30 +462,74 @@ std::string GetErrorDict(const ErrorInfo& error) { ...@@ -521,30 +462,74 @@ std::string GetErrorDict(const ErrorInfo& error) {
} // namespace } // namespace
class LocalNtpSource::GoogleSearchProviderTracker // Keeps the search engine configuration data to be included on the Local NTP,
// and will also keep track of any changes in search engine provider to
// recompute this data.
class LocalNtpSource::SearchConfigurationProvider
: public TemplateURLServiceObserver { : public TemplateURLServiceObserver {
public: public:
explicit GoogleSearchProviderTracker(TemplateURLService* service) explicit SearchConfigurationProvider(TemplateURLService* service)
: service_(service), is_google_(false) { : service_(service) {
DCHECK(service_); DCHECK(service_);
service_->AddObserver(this); service_->AddObserver(this);
is_google_ = search::DefaultSearchProviderIsGoogle(service_); UpdateConfigData();
google_base_url_ = GURL(service_->search_terms_data().GoogleBaseURLValue());
} }
~GoogleSearchProviderTracker() override { ~SearchConfigurationProvider() override {
if (service_) if (service_)
service_->RemoveObserver(this); service_->RemoveObserver(this);
} }
bool DefaultSearchProviderIsGoogle() const { return is_google_; } const std::string& config_data_js() const { return config_data_js_; }
const std::string& config_data_integrity() const {
const GURL& GetGoogleBaseUrl() const { return google_base_url_; } return config_data_integrity_;
}
private: private:
// Updates the configuration data for the local NTP.
void UpdateConfigData() {
bool is_google = search::DefaultSearchProviderIsGoogle(service_);
const GURL google_base_url =
GURL(service_->search_terms_data().GoogleBaseURLValue());
base::DictionaryValue config_data;
config_data.Set("translatedStrings", GetTranslatedStrings(is_google));
config_data.SetBoolean("isGooglePage", is_google);
config_data.SetString("googleBaseUrl", google_base_url.spec());
config_data.SetBoolean("isAccessibleBrowser",
content::BrowserAccessibilityState::GetInstance()
->IsAccessibleBrowser());
bool is_voice_search_enabled =
base::FeatureList::IsEnabled(features::kVoiceSearchOnLocalNtp);
config_data.SetBoolean("isVoiceSearchEnabled", is_voice_search_enabled);
config_data.SetBoolean("isMDUIEnabled", features::IsMDUIEnabled());
config_data.SetBoolean("isMDIconsEnabled", features::IsMDIconsEnabled());
if (is_google) {
config_data.SetBoolean("isCustomLinksEnabled",
features::IsCustomLinksEnabled());
config_data.SetBoolean("isCustomBackgroundsEnabled",
features::IsCustomBackgroundsEnabled());
}
// Serialize the dictionary.
std::string js_text;
JSONStringValueSerializer serializer(&js_text);
serializer.Serialize(config_data);
config_data_js_ = "var configData = ";
config_data_js_.append(js_text);
config_data_js_.append(";");
std::string config_sha256 = crypto::SHA256HashString(config_data_js_);
base::Base64Encode(config_sha256, &config_data_integrity_);
}
void OnTemplateURLServiceChanged() override { void OnTemplateURLServiceChanged() override {
is_google_ = search::DefaultSearchProviderIsGoogle(service_); // The search provider may have changed, keep the config data valid.
google_base_url_ = GURL(service_->search_terms_data().GoogleBaseURLValue()); UpdateConfigData();
} }
void OnTemplateURLServiceShuttingDown() override { void OnTemplateURLServiceShuttingDown() override {
...@@ -554,8 +539,8 @@ class LocalNtpSource::GoogleSearchProviderTracker ...@@ -554,8 +539,8 @@ class LocalNtpSource::GoogleSearchProviderTracker
TemplateURLService* service_; TemplateURLService* service_;
bool is_google_; std::string config_data_js_;
GURL google_base_url_; std::string config_data_integrity_;
}; };
class LocalNtpSource::DesktopLogoObserver { class LocalNtpSource::DesktopLogoObserver {
...@@ -697,8 +682,8 @@ LocalNtpSource::LocalNtpSource(Profile* profile) ...@@ -697,8 +682,8 @@ LocalNtpSource::LocalNtpSource(Profile* profile)
TemplateURLService* template_url_service = TemplateURLService* template_url_service =
TemplateURLServiceFactory::GetForProfile(profile_); TemplateURLServiceFactory::GetForProfile(profile_);
if (template_url_service) { if (template_url_service) {
google_tracker_ = search_config_provider_ =
std::make_unique<GoogleSearchProviderTracker>(template_url_service); std::make_unique<SearchConfigurationProvider>(template_url_service);
} }
} }
...@@ -716,9 +701,7 @@ void LocalNtpSource::StartDataRequest( ...@@ -716,9 +701,7 @@ void LocalNtpSource::StartDataRequest(
std::string stripped_path = StripParameters(path); std::string stripped_path = StripParameters(path);
if (stripped_path == kConfigDataFilename) { if (stripped_path == kConfigDataFilename) {
std::string config_data_js = std::string config_data_js = search_config_provider_->config_data_js();
GetConfigData(google_tracker_->DefaultSearchProviderIsGoogle(),
google_tracker_->GetGoogleBaseUrl());
callback.Run(base::RefCountedString::TakeString(&config_data_js)); callback.Run(base::RefCountedString::TakeString(&config_data_js));
return; return;
} }
...@@ -851,6 +834,7 @@ void LocalNtpSource::StartDataRequest( ...@@ -851,6 +834,7 @@ void LocalNtpSource::StartDataRequest(
std::string html = ui::ResourceBundle::GetSharedInstance() std::string html = ui::ResourceBundle::GetSharedInstance()
.GetRawDataResource(IDR_LOCAL_NTP_HTML) .GetRawDataResource(IDR_LOCAL_NTP_HTML)
.as_string(); .as_string();
std::string local_ntp_integrity = std::string local_ntp_integrity =
base::StringPrintf(kIntegrityFormat, LOCAL_NTP_JS_INTEGRITY); base::StringPrintf(kIntegrityFormat, LOCAL_NTP_JS_INTEGRITY);
base::ReplaceFirstSubstringAfterOffset(&html, 0, "{{LOCAL_NTP_INTEGRITY}}", base::ReplaceFirstSubstringAfterOffset(&html, 0, "{{LOCAL_NTP_INTEGRITY}}",
...@@ -866,6 +850,16 @@ void LocalNtpSource::StartDataRequest( ...@@ -866,6 +850,16 @@ void LocalNtpSource::StartDataRequest(
base::ReplaceFirstSubstringAfterOffset(&html, 0, base::ReplaceFirstSubstringAfterOffset(&html, 0,
"{{LOCAL_NTP_CUSTOM_BG_INTEGRITY}}", "{{LOCAL_NTP_CUSTOM_BG_INTEGRITY}}",
local_ntp_custom_bg_integrity); local_ntp_custom_bg_integrity);
std::string config_data_integrity = base::StringPrintf(
kIntegrityFormat,
search_config_provider_->config_data_integrity().c_str());
base::ReplaceFirstSubstringAfterOffset(
&html, 0, "{{CONFIG_DATA_INTEGRITY}}", config_data_integrity);
base::ReplaceFirstSubstringAfterOffset(
&html, 0, "{{CONTENT_SECURITY_POLICY}}", GetContentSecurityPolicy());
callback.Run(base::RefCountedString::TakeString(&html)); callback.Run(base::RefCountedString::TakeString(&html));
return; return;
} }
...@@ -915,16 +909,42 @@ bool LocalNtpSource::ShouldServiceRequest( ...@@ -915,16 +909,42 @@ bool LocalNtpSource::ShouldServiceRequest(
return ShouldServiceRequestIOThread(url, resource_context, render_process_id); return ShouldServiceRequestIOThread(url, resource_context, render_process_id);
} }
std::string LocalNtpSource::GetContentSecurityPolicyScriptSrc() const { bool LocalNtpSource::ShouldAddContentSecurityPolicy() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); // The Content Security Policy is served as a meta tag in local NTP html.
// We disable the HTTP Header version here to avoid a conflicting policy. See
return GetContentSecurityPolicyScriptSrcIOThread(); // GetContentSecurityPolicy.
return false;
} }
std::string LocalNtpSource::GetContentSecurityPolicyChildSrc() const { std::string LocalNtpSource::GetContentSecurityPolicy() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
#if !defined(GOOGLE_CHROME_BUILD)
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kLocalNtpReload)) {
// While live-editing the local NTP files, turn off CSP.
return "script-src * 'unsafe-inline';";
}
#endif // !defined(GOOGLE_CHROME_BUILD)
// Allow embedding of the most visited iframe, as well as the account
// switcher and the notifications dropdown from the One Google Bar, and/or
// the iframe for interactive Doodles.
std::string child_src_csp =
base::StringPrintf("child-src %s https://*.google.com/;",
chrome::kChromeSearchMostVisitedUrl);
// Restrict scripts in the main page to those listed here. However,
// 'strict-dynamic' allows those scripts to load dependencies not listed here.
std::string script_src_csp = base::StringPrintf(
"script-src 'strict-dynamic' 'sha256-%s' 'sha256-%s' 'sha256-%s' "
"'sha256-%s';",
LOCAL_NTP_JS_INTEGRITY, VOICE_JS_INTEGRITY,
CUSTOM_BACKGROUNDS_JS_INTEGRITY,
search_config_provider_->config_data_integrity().c_str());
return GetContentSecurityPolicyChildSrcIOThread(); return GetContentSecurityPolicyObjectSrc() +
GetContentSecurityPolicyStyleSrc() + GetContentSecurityPolicyImgSrc() +
child_src_csp + script_src_csp;
} }
void LocalNtpSource::OnCollectionInfoAvailable() { void LocalNtpSource::OnCollectionInfoAvailable() {
......
...@@ -47,7 +47,7 @@ class LocalNtpSource : public content::URLDataSource, ...@@ -47,7 +47,7 @@ class LocalNtpSource : public content::URLDataSource,
explicit LocalNtpSource(Profile* profile); explicit LocalNtpSource(Profile* profile);
private: private:
class GoogleSearchProviderTracker; class SearchConfigurationProvider;
class DesktopLogoObserver; class DesktopLogoObserver;
struct NtpBackgroundRequest { struct NtpBackgroundRequest {
...@@ -85,8 +85,10 @@ class LocalNtpSource : public content::URLDataSource, ...@@ -85,8 +85,10 @@ class LocalNtpSource : public content::URLDataSource,
bool ShouldServiceRequest(const GURL& url, bool ShouldServiceRequest(const GURL& url,
content::ResourceContext* resource_context, content::ResourceContext* resource_context,
int render_process_id) const override; int render_process_id) const override;
std::string GetContentSecurityPolicyScriptSrc() const override; bool ShouldAddContentSecurityPolicy() const override;
std::string GetContentSecurityPolicyChildSrc() const override;
// The Content Security Policy for the Local NTP.
std::string GetContentSecurityPolicy() const;
// Overridden from NtpBackgroundServiceObserver: // Overridden from NtpBackgroundServiceObserver:
void OnCollectionInfoAvailable() override; void OnCollectionInfoAvailable() override;
...@@ -123,7 +125,7 @@ class LocalNtpSource : public content::URLDataSource, ...@@ -123,7 +125,7 @@ class LocalNtpSource : public content::URLDataSource,
search_provider_logos::LogoService* logo_service_; search_provider_logos::LogoService* logo_service_;
std::unique_ptr<DesktopLogoObserver> logo_observer_; std::unique_ptr<DesktopLogoObserver> logo_observer_;
std::unique_ptr<GoogleSearchProviderTracker> google_tracker_; std::unique_ptr<SearchConfigurationProvider> search_config_provider_;
base::WeakPtrFactory<LocalNtpSource> weak_ptr_factory_; base::WeakPtrFactory<LocalNtpSource> weak_ptr_factory_;
......
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