Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(699)

Side by Side Diff: chrome/browser/search/local_ntp_source.cc

Issue 2805133004: Local NTP: Deploy strict-dynamic CSP (Closed)
Patch Set: fix Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "chrome/browser/search/local_ntp_source.h" 5 #include "chrome/browser/search/local_ntp_source.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <memory> 9 #include <memory>
10 10
11 #include "base/base64.h"
11 #include "base/command_line.h" 12 #include "base/command_line.h"
12 #include "base/json/json_string_value_serializer.h" 13 #include "base/json/json_string_value_serializer.h"
13 #include "base/logging.h" 14 #include "base/logging.h"
14 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
15 #include "base/memory/ref_counted_memory.h" 16 #include "base/memory/ref_counted_memory.h"
16 #include "base/metrics/field_trial.h"
17 #include "base/strings/string_util.h" 17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
19 #include "base/values.h" 19 #include "base/values.h"
20 #include "build/build_config.h" 20 #include "build/build_config.h"
21 #include "chrome/browser/search/google_search_provider_service.h"
22 #include "chrome/browser/search/google_search_provider_service_factory.h"
21 #include "chrome/browser/search/instant_io_context.h" 23 #include "chrome/browser/search/instant_io_context.h"
22 #include "chrome/browser/search/local_files_ntp_source.h" 24 #include "chrome/browser/search/local_files_ntp_source.h"
23 #include "chrome/browser/search_engines/template_url_service_factory.h"
24 #include "chrome/browser/themes/theme_properties.h" 25 #include "chrome/browser/themes/theme_properties.h"
25 #include "chrome/browser/themes/theme_service.h" 26 #include "chrome/browser/themes/theme_service.h"
26 #include "chrome/browser/themes/theme_service_factory.h" 27 #include "chrome/browser/themes/theme_service_factory.h"
27 #include "chrome/common/chrome_switches.h" 28 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/url_constants.h" 29 #include "chrome/common/url_constants.h"
29 #include "chrome/grit/browser_resources.h" 30 #include "chrome/grit/browser_resources.h"
30 #include "chrome/grit/generated_resources.h" 31 #include "chrome/grit/generated_resources.h"
31 #include "chrome/grit/theme_resources.h" 32 #include "chrome/grit/theme_resources.h"
32 #include "components/search_engines/template_url_service.h"
33 #include "components/strings/grit/components_strings.h" 33 #include "components/strings/grit/components_strings.h"
34 #include "crypto/secure_hash.h"
35 #include "net/base/hash_value.h"
34 #include "net/url_request/url_request.h" 36 #include "net/url_request/url_request.h"
35 #include "third_party/skia/include/core/SkColor.h" 37 #include "third_party/skia/include/core/SkColor.h"
36 #include "ui/base/l10n/l10n_util.h" 38 #include "ui/base/l10n/l10n_util.h"
37 #include "ui/base/resource/resource_bundle.h" 39 #include "ui/base/resource/resource_bundle.h"
38 #include "ui/base/webui/web_ui_util.h" 40 #include "ui/base/webui/web_ui_util.h"
39 #include "ui/resources/grit/ui_resources.h" 41 #include "ui/resources/grit/ui_resources.h"
40 #include "url/gurl.h" 42 #include "url/gurl.h"
41 43
42 namespace { 44 namespace {
43 45
44 // Signifies a locally constructed resource, i.e. not from grit/. 46 // Signifies a locally constructed resource, i.e. not from grit/.
45 const int kLocalResource = -1; 47 const int kLocalResource = -1;
46 48
47 const char kConfigDataFilename[] = "config.js"; 49 const char kConfigDataFilename[] = "config.js";
48 const char kThemeCSSFilename[] = "theme.css"; 50 const char kThemeCSSFilename[] = "theme.css";
51 const char kMainHtmlFilename[] = "local-ntp.html";
49 52
50 const struct Resource{ 53 const struct Resource{
51 const char* filename; 54 const char* filename;
52 int identifier; 55 int identifier;
53 const char* mime_type; 56 const char* mime_type;
54 } kResources[] = { 57 } kResources[] = {
55 {"local-ntp.html", IDR_LOCAL_NTP_HTML, "text/html"}, 58 {kMainHtmlFilename, kLocalResource, "text/html"},
56 {"local-ntp.js", IDR_LOCAL_NTP_JS, "application/javascript"}, 59 {"local-ntp.js", IDR_LOCAL_NTP_JS, "application/javascript"},
57 {kConfigDataFilename, kLocalResource, "application/javascript"}, 60 {kConfigDataFilename, kLocalResource, "application/javascript"},
58 {kThemeCSSFilename, kLocalResource, "text/css"}, 61 {kThemeCSSFilename, kLocalResource, "text/css"},
59 {"local-ntp.css", IDR_LOCAL_NTP_CSS, "text/css"}, 62 {"local-ntp.css", IDR_LOCAL_NTP_CSS, "text/css"},
60 {"images/close_3_mask.png", IDR_CLOSE_3_MASK, "image/png"}, 63 {"images/close_3_mask.png", IDR_CLOSE_3_MASK, "image/png"},
61 {"images/close_4_button.png", IDR_CLOSE_4_BUTTON, "image/png"}, 64 {"images/close_4_button.png", IDR_CLOSE_4_BUTTON, "image/png"},
62 {"images/ntp_default_favicon.png", IDR_NTP_DEFAULT_FAVICON, "image/png"}, 65 {"images/ntp_default_favicon.png", IDR_NTP_DEFAULT_FAVICON, "image/png"},
63 }; 66 };
64 67
65 // Strips any query parameters from the specified path. 68 // Strips any query parameters from the specified path.
66 std::string StripParameters(const std::string& path) { 69 std::string StripParameters(const std::string& path) {
67 return path.substr(0, path.find("?")); 70 return path.substr(0, path.find("?"));
68 } 71 }
69 72
70 bool DefaultSearchProviderIsGoogle(Profile* profile) {
71 if (!profile)
72 return false;
73
74 TemplateURLService* template_url_service =
75 TemplateURLServiceFactory::GetForProfile(profile);
76 if (!template_url_service)
77 return false;
78
79 const TemplateURL* default_provider =
80 template_url_service->GetDefaultSearchProvider();
81 return default_provider &&
82 (default_provider->GetEngineType(
83 template_url_service->search_terms_data()) ==
84 SEARCH_ENGINE_GOOGLE);
85 }
86
87 // Adds a localized string keyed by resource id to the dictionary. 73 // Adds a localized string keyed by resource id to the dictionary.
88 void AddString(base::DictionaryValue* dictionary, 74 void AddString(base::DictionaryValue* dictionary,
89 const std::string& key, 75 const std::string& key,
90 int resource_id) { 76 int resource_id) {
91 dictionary->SetString(key, l10n_util::GetStringUTF16(resource_id)); 77 dictionary->SetString(key, l10n_util::GetStringUTF16(resource_id));
92 } 78 }
93 79
94 // Populates |translated_strings| dictionary for the local NTP. |is_google| 80 // Populates |translated_strings| dictionary for the local NTP. |is_google|
95 // indicates that this page is the Google local NTP. 81 // indicates that this page is the Google local NTP.
96 std::unique_ptr<base::DictionaryValue> GetTranslatedStrings(bool is_google) { 82 std::unique_ptr<base::DictionaryValue> GetTranslatedStrings(bool is_google) {
(...skipping 12 matching lines...) Expand all
109 AddString(translated_strings.get(), "title", IDS_NEW_TAB_TITLE); 95 AddString(translated_strings.get(), "title", IDS_NEW_TAB_TITLE);
110 if (is_google) { 96 if (is_google) {
111 AddString(translated_strings.get(), "searchboxPlaceholder", 97 AddString(translated_strings.get(), "searchboxPlaceholder",
112 IDS_GOOGLE_SEARCH_BOX_EMPTY_HINT); 98 IDS_GOOGLE_SEARCH_BOX_EMPTY_HINT);
113 } 99 }
114 100
115 return translated_strings; 101 return translated_strings;
116 } 102 }
117 103
118 // Returns a JS dictionary of configuration data for the local NTP. 104 // Returns a JS dictionary of configuration data for the local NTP.
119 std::string GetConfigData(Profile* profile) { 105 std::string GetConfigData(bool is_google) {
120 base::DictionaryValue config_data; 106 base::DictionaryValue config_data;
121 bool is_google = DefaultSearchProviderIsGoogle(profile);
122 config_data.Set("translatedStrings", GetTranslatedStrings(is_google)); 107 config_data.Set("translatedStrings", GetTranslatedStrings(is_google));
123 config_data.SetBoolean("isGooglePage", is_google); 108 config_data.SetBoolean("isGooglePage", is_google);
124 109
125 // Serialize the dictionary. 110 // Serialize the dictionary.
126 std::string js_text; 111 std::string js_text;
127 JSONStringValueSerializer serializer(&js_text); 112 JSONStringValueSerializer serializer(&js_text);
128 serializer.Serialize(config_data); 113 serializer.Serialize(config_data);
129 114
130 std::string config_data_js; 115 std::string config_data_js;
131 config_data_js.append("var configData = "); 116 config_data_js.append("var configData = ");
132 config_data_js.append(js_text); 117 config_data_js.append(js_text);
133 config_data_js.append(";"); 118 config_data_js.append(";");
134 return config_data_js; 119 return config_data_js;
135 } 120 }
136 121
122 std::string GetIntegritySha256Value(const std::string& data) {
123 // Compute the sha256 hash.
124 net::SHA256HashValue hash_value;
125 std::unique_ptr<crypto::SecureHash> hash(
126 crypto::SecureHash::Create(crypto::SecureHash::SHA256));
127 hash->Update(data.data(), data.size());
128 hash->Finish(&hash_value, sizeof(hash_value));
129
130 // Base64-encode it.
131 base::StringPiece hash_value_str(
132 reinterpret_cast<const char*>(hash_value.data), sizeof(hash_value));
133 std::string result;
134 base::Base64Encode(hash_value_str, &result);
135 return result;
136 }
137
137 std::string GetThemeCSS(Profile* profile) { 138 std::string GetThemeCSS(Profile* profile) {
138 SkColor background_color = 139 SkColor background_color =
139 ThemeService::GetThemeProviderForProfile(profile) 140 ThemeService::GetThemeProviderForProfile(profile)
140 .GetColor(ThemeProperties::COLOR_NTP_BACKGROUND); 141 .GetColor(ThemeProperties::COLOR_NTP_BACKGROUND);
141 142
142 return base::StringPrintf("body { background-color: #%02X%02X%02X; }", 143 return base::StringPrintf("body { background-color: #%02X%02X%02X; }",
143 SkColorGetR(background_color), 144 SkColorGetR(background_color),
144 SkColorGetG(background_color), 145 SkColorGetG(background_color),
145 SkColorGetB(background_color)); 146 SkColorGetB(background_color));
146 } 147 }
147 148
148 std::string GetLocalNtpPath() { 149 std::string GetLocalNtpPath() {
149 return std::string(chrome::kChromeSearchScheme) + "://" + 150 return std::string(chrome::kChromeSearchScheme) + "://" +
150 std::string(chrome::kChromeSearchLocalNtpHost) + "/"; 151 std::string(chrome::kChromeSearchLocalNtpHost) + "/";
151 } 152 }
152 153
153 } // namespace 154 } // namespace
154 155
155 LocalNtpSource::LocalNtpSource(Profile* profile) : profile_(profile) {} 156 LocalNtpSource::LocalNtpSource(Profile* profile)
157 : profile_(profile),
158 default_search_provider_observer_(this),
159 default_search_provider_is_google_(false) {
160 GoogleSearchProviderService* google_service =
161 GoogleSearchProviderServiceFactory::GetForProfile(profile_);
162 if (google_service) {
163 default_search_provider_observer_.Add(google_service);
164 default_search_provider_is_google_ =
165 google_service->DefaultSearchProviderIsGoogle();
166 }
167 }
156 168
157 LocalNtpSource::~LocalNtpSource() = default; 169 LocalNtpSource::~LocalNtpSource() = default;
158 170
159 std::string LocalNtpSource::GetSource() const { 171 std::string LocalNtpSource::GetSource() const {
160 return chrome::kChromeSearchLocalNtpHost; 172 return chrome::kChromeSearchLocalNtpHost;
161 } 173 }
162 174
163 void LocalNtpSource::StartDataRequest( 175 void LocalNtpSource::StartDataRequest(
164 const std::string& path, 176 const std::string& path,
165 const content::ResourceRequestInfo::WebContentsGetter& wc_getter, 177 const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
166 const content::URLDataSource::GotDataCallback& callback) { 178 const content::URLDataSource::GotDataCallback& callback) {
167 std::string stripped_path = StripParameters(path); 179 std::string stripped_path = StripParameters(path);
168 if (stripped_path == kConfigDataFilename) { 180 if (stripped_path == kConfigDataFilename) {
169 std::string config_data_js = GetConfigData(profile_); 181 std::string config_data_js =
182 GetConfigData(default_search_provider_is_google_);
170 callback.Run(base::RefCountedString::TakeString(&config_data_js)); 183 callback.Run(base::RefCountedString::TakeString(&config_data_js));
171 return; 184 return;
172 } 185 }
173 if (stripped_path == kThemeCSSFilename) { 186 if (stripped_path == kThemeCSSFilename) {
174 std::string theme_css = GetThemeCSS(profile_); 187 std::string theme_css = GetThemeCSS(profile_);
175 callback.Run(base::RefCountedString::TakeString(&theme_css)); 188 callback.Run(base::RefCountedString::TakeString(&theme_css));
176 return; 189 return;
177 } 190 }
178 191
179 #if !defined(GOOGLE_CHROME_BUILD) 192 #if !defined(GOOGLE_CHROME_BUILD)
180 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); 193 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
181 if (command_line->HasSwitch(switches::kLocalNtpReload)) { 194 if (command_line->HasSwitch(switches::kLocalNtpReload)) {
182 if (stripped_path == "local-ntp.html" || stripped_path == "local-ntp.js" || 195 if (stripped_path == "local-ntp.html" || stripped_path == "local-ntp.js" ||
183 stripped_path == "local-ntp.css") { 196 stripped_path == "local-ntp.css") {
184 base::ReplaceChars(stripped_path, "-", "_", &stripped_path); 197 base::ReplaceChars(stripped_path, "-", "_", &stripped_path);
185 local_ntp::SendLocalFileResource(stripped_path, callback); 198 local_ntp::SendLocalFileResource(stripped_path, callback);
186 return; 199 return;
187 } 200 }
188 } 201 }
189 #endif // !defined(GOOGLE_CHROME_BUILD) 202 #endif // !defined(GOOGLE_CHROME_BUILD)
190 203
204 if (stripped_path == kMainHtmlFilename) {
205 std::string html = ResourceBundle::GetSharedInstance()
206 .GetRawDataResource(IDR_LOCAL_NTP_HTML)
207 .as_string();
208 std::string config_sha256 =
209 "sha256-" + GetIntegritySha256Value(
210 GetConfigData(default_search_provider_is_google_));
211 base::ReplaceFirstSubstringAfterOffset(&html, 0, "{{CONFIG_INTEGRITY}}",
212 config_sha256);
213 callback.Run(base::RefCountedString::TakeString(&html));
214 return;
215 }
216
191 float scale = 1.0f; 217 float scale = 1.0f;
192 std::string filename; 218 std::string filename;
193 webui::ParsePathAndScale( 219 webui::ParsePathAndScale(
194 GURL(GetLocalNtpPath() + stripped_path), &filename, &scale); 220 GURL(GetLocalNtpPath() + stripped_path), &filename, &scale);
195 ui::ScaleFactor scale_factor = ui::GetSupportedScaleFactor(scale); 221 ui::ScaleFactor scale_factor = ui::GetSupportedScaleFactor(scale);
196 222
197 for (size_t i = 0; i < arraysize(kResources); ++i) { 223 for (size_t i = 0; i < arraysize(kResources); ++i) {
198 if (filename == kResources[i].filename) { 224 if (filename == kResources[i].filename) {
199 scoped_refptr<base::RefCountedMemory> response( 225 scoped_refptr<base::RefCountedMemory> response(
200 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( 226 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
201 kResources[i].identifier, scale_factor)); 227 kResources[i].identifier, scale_factor));
202 callback.Run(response.get()); 228 callback.Run(response.get());
203 return; 229 return;
204 } 230 }
205 } 231 }
206 callback.Run(NULL); 232 callback.Run(nullptr);
207 } 233 }
208 234
209 std::string LocalNtpSource::GetMimeType( 235 std::string LocalNtpSource::GetMimeType(
210 const std::string& path) const { 236 const std::string& path) const {
211 const std::string stripped_path = StripParameters(path); 237 const std::string stripped_path = StripParameters(path);
212 for (size_t i = 0; i < arraysize(kResources); ++i) { 238 for (size_t i = 0; i < arraysize(kResources); ++i) {
213 if (stripped_path == kResources[i].filename) 239 if (stripped_path == kResources[i].filename)
214 return kResources[i].mime_type; 240 return kResources[i].mime_type;
215 } 241 }
216 return std::string(); 242 return std::string();
217 } 243 }
218 244
219 bool LocalNtpSource::AllowCaching() const { 245 bool LocalNtpSource::AllowCaching() const {
220 // Some resources served by LocalNtpSource, i.e. config.js, are dynamically 246 // Some resources served by LocalNtpSource, i.e. config.js, are dynamically
221 // generated and could differ on each access. To avoid using old cached 247 // generated and could differ on each access. To avoid using old cached
222 // content on reload, disallow caching here. Otherwise, it fails to reflect 248 // content on reload, disallow caching here. Otherwise, it fails to reflect
223 // newly revised user configurations in the page. 249 // newly revised user configurations in the page.
224 return false; 250 return false;
225 } 251 }
226 252
227 bool LocalNtpSource::ShouldServiceRequest( 253 bool LocalNtpSource::ShouldServiceRequest(
228 const net::URLRequest* request) const { 254 const net::URLRequest* request) const {
229 DCHECK(request->url().host_piece() == chrome::kChromeSearchLocalNtpHost); 255 DCHECK(request->url().host_piece() == chrome::kChromeSearchLocalNtpHost);
230 if (!InstantIOContext::ShouldServiceRequest(request)) 256 if (!InstantIOContext::ShouldServiceRequest(request))
231 return false; 257 return false;
232 258
233 if (request->url().SchemeIs(chrome::kChromeSearchScheme)) { 259 if (request->url().SchemeIs(chrome::kChromeSearchScheme)) {
234 std::string filename; 260 std::string filename;
235 webui::ParsePathAndScale(request->url(), &filename, NULL); 261 webui::ParsePathAndScale(request->url(), &filename, nullptr);
236 for (size_t i = 0; i < arraysize(kResources); ++i) { 262 for (size_t i = 0; i < arraysize(kResources); ++i) {
237 if (filename == kResources[i].filename) 263 if (filename == kResources[i].filename)
238 return true; 264 return true;
239 } 265 }
240 } 266 }
241 return false; 267 return false;
242 } 268 }
243 269
270 std::string LocalNtpSource::GetContentSecurityPolicyScriptSrc() const {
271 // Note: This method is called on the IO thread.
272 #if !defined(GOOGLE_CHROME_BUILD)
273 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
274 if (command_line->HasSwitch(switches::kLocalNtpReload)) {
275 // While live-editing the local NTP files, turn off CSP.
276 return "script-src *;";
277 }
278 #endif // !defined(GOOGLE_CHROME_BUILD)
279
280 return "script-src 'strict-dynamic' "
281 "'sha256-" +
282 GetIntegritySha256Value(
283 GetConfigData(default_search_provider_is_google_)) +
284 "' "
285 "'sha256-g38WaUaxnOIWY7E2LtLZ5ff9r5sn1dBj80jevt/kmx0=';";
286 }
287
244 std::string LocalNtpSource::GetContentSecurityPolicyChildSrc() const { 288 std::string LocalNtpSource::GetContentSecurityPolicyChildSrc() const {
245 // Allow embedding of most visited iframes. 289 // Allow embedding of most visited iframes.
246 return base::StringPrintf("child-src %s;", 290 return base::StringPrintf("child-src %s;",
247 chrome::kChromeSearchMostVisitedUrl); 291 chrome::kChromeSearchMostVisitedUrl);
248 } 292 }
293
294 void LocalNtpSource::OnDefaultSearchProviderIsGoogleChanged(bool is_google) {
295 default_search_provider_is_google_ = is_google;
sfiera 2017/04/11 09:45:17 What thread is this method called from? If it's th
Marc Treib 2017/04/11 12:37:59 Threading in URLDataSource is kind of a mess :( T
sfiera 2017/04/11 14:07:35 Alright, thanks. This is ugly, but feels like the
296 }
297
298 void LocalNtpSource::OnGoogleSearchProviderServiceShuttingDown() {
299 default_search_provider_observer_.RemoveAll();
300 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698