OLD | NEW |
---|---|
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/ui/webui/extensions/extension_error_handler.h" | 5 #include "chrome/browser/ui/webui/extensions/extension_error_handler.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
10 #include "base/location.h" | 10 #include "base/location.h" |
11 #include "base/strings/string16.h" | 11 #include "base/strings/string16.h" |
12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
13 #include "base/values.h" | 13 #include "base/values.h" |
14 #include "chrome/browser/extensions/extension_service.h" | 14 #include "chrome/browser/extensions/extension_service.h" |
15 #include "chrome/browser/extensions/extension_system.h" | 15 #include "chrome/browser/extensions/extension_system.h" |
16 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
17 #include "chrome/common/extensions/extension.h" | 17 #include "chrome/common/extensions/extension.h" |
18 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
19 #include "content/public/browser/web_ui.h" | 19 #include "content/public/browser/web_ui.h" |
20 #include "content/public/browser/web_ui_data_source.h" | 20 #include "content/public/browser/web_ui_data_source.h" |
21 #include "extensions/browser/extension_error.h" | 21 #include "extensions/browser/extension_error.h" |
22 #include "extensions/browser/manifest_highlighter.h" | 22 #include "extensions/browser/file_highlighter.h" |
23 #include "extensions/common/constants.h" | |
23 #include "grit/generated_resources.h" | 24 #include "grit/generated_resources.h" |
24 #include "ui/base/l10n/l10n_util.h" | 25 #include "ui/base/l10n/l10n_util.h" |
25 | 26 |
26 namespace extensions { | 27 namespace extensions { |
27 | 28 |
28 namespace { | 29 namespace { |
29 | 30 |
30 // Keys for objects passed to and from extension error UI. | 31 // Keys for objects passed to and from extension error UI. |
31 const char kFileTypeKey[] = "fileType"; | 32 const char kFileTypeKey[] = "fileType"; |
32 const char kManifestFileType[] = "manifest"; | 33 const char kManifestFileType[] = "manifest"; |
33 const char kPathSuffixKey[] = "pathSuffix"; | 34 const char kPathSuffixKey[] = "pathSuffix"; |
35 const char kSourceFileType[] = "source"; | |
34 const char kTitleKey[] = "title"; | 36 const char kTitleKey[] = "title"; |
35 | 37 |
36 const char kBeforeHighlightKey[] = "beforeHighlight"; | |
37 const char kHighlightKey[] = "highlight"; | |
38 const char kAfterHighlightKey[] = "afterHighlight"; | |
39 | |
40 // Populate a DictionaryValue with the highlighted portions for the callback to | |
41 // ExtensionErrorOverlay, given the components. | |
42 void HighlightDictionary(base::DictionaryValue* dict, | |
43 const ManifestHighlighter& highlighter) { | |
44 std::string before_feature = highlighter.GetBeforeFeature(); | |
45 if (!before_feature.empty()) | |
46 dict->SetString(kBeforeHighlightKey, base::UTF8ToUTF16(before_feature)); | |
47 | |
48 std::string feature = highlighter.GetFeature(); | |
49 if (!feature.empty()) | |
50 dict->SetString(kHighlightKey, base::UTF8ToUTF16(feature)); | |
51 | |
52 std::string after_feature = highlighter.GetAfterFeature(); | |
53 if (!after_feature.empty()) | |
54 dict->SetString(kAfterHighlightKey, base::UTF8ToUTF16(after_feature)); | |
55 } | |
56 | |
57 } // namespace | 38 } // namespace |
58 | 39 |
59 ExtensionErrorHandler::ExtensionErrorHandler(Profile* profile) | 40 ExtensionErrorHandler::ExtensionErrorHandler(Profile* profile) |
60 : profile_(profile) { | 41 : profile_(profile) { |
61 } | 42 } |
62 | 43 |
63 ExtensionErrorHandler::~ExtensionErrorHandler() { | 44 ExtensionErrorHandler::~ExtensionErrorHandler() { |
64 } | 45 } |
65 | 46 |
66 void ExtensionErrorHandler::GetLocalizedValues( | 47 void ExtensionErrorHandler::GetLocalizedValues( |
67 content::WebUIDataSource* source) { | 48 content::WebUIDataSource* source) { |
68 source->AddString( | 49 source->AddString( |
69 "extensionErrorsManifestErrors", | 50 "extensionErrorsManifestErrors", |
70 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERRORS_MANIFEST_ERRORS)); | 51 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERRORS_MANIFEST_ERRORS)); |
71 source->AddString( | 52 source->AddString( |
53 "extensionErrorsRuntimeErrors", | |
54 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERRORS_RUNTIME_ERRORS)); | |
55 source->AddString( | |
72 "extensionErrorsShowMore", | 56 "extensionErrorsShowMore", |
73 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERRORS_SHOW_MORE)); | 57 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERRORS_SHOW_MORE)); |
74 source->AddString( | 58 source->AddString( |
75 "extensionErrorsShowFewer", | 59 "extensionErrorsShowFewer", |
76 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERRORS_SHOW_FEWER)); | 60 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERRORS_SHOW_FEWER)); |
77 source->AddString( | 61 source->AddString( |
78 "extensionErrorViewSource", | 62 "extensionErrorViewSource", |
79 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERROR_VIEW_SOURCE)); | 63 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERROR_VIEW_SOURCE)); |
64 source->AddString( | |
65 "extensionErrorContext", | |
66 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERROR_CONTEXT)); | |
67 source->AddString( | |
68 "extensionErrorStackTrace", | |
69 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERROR_STACK_TRACE)); | |
70 source->AddString( | |
71 "extensionErrorAnonymousFunction", | |
72 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERROR_ANONYMOUS_FUNCTION)); | |
80 } | 73 } |
81 | 74 |
82 void ExtensionErrorHandler::RegisterMessages() { | 75 void ExtensionErrorHandler::RegisterMessages() { |
83 web_ui()->RegisterMessageCallback( | 76 web_ui()->RegisterMessageCallback( |
84 "extensionErrorRequestFileSource", | 77 "extensionErrorRequestFileSource", |
85 base::Bind(&ExtensionErrorHandler::HandleRequestFileSource, | 78 base::Bind(&ExtensionErrorHandler::HandleRequestFileSource, |
86 base::Unretained(this))); | 79 base::Unretained(this))); |
87 } | 80 } |
88 | 81 |
89 void ExtensionErrorHandler::HandleRequestFileSource( | 82 void ExtensionErrorHandler::HandleRequestFileSource( |
90 const base::ListValue* args) { | 83 const base::ListValue* args) { |
91 // There should only be one argument, a dictionary. Use this instead of a list | 84 // There should only be one argument, a dictionary. Use this instead of a list |
92 // because it's more descriptive, harder to accidentally break with minor | 85 // because it's more descriptive, harder to accidentally break with minor |
93 // modifications, and supports optional arguments more easily. | 86 // modifications, and supports optional arguments more easily. |
94 CHECK_EQ(1u, args->GetSize()); | 87 CHECK_EQ(1u, args->GetSize()); |
95 | 88 |
96 const base::DictionaryValue* dict = NULL; | 89 const base::DictionaryValue* dict = NULL; |
97 | 90 |
98 // Four required arguments: extension_id, path_suffix, error_message, and | 91 // Three required arguments: extension_id, path_suffix, and error_message. |
99 // file_type. | |
100 std::string extension_id; | 92 std::string extension_id; |
101 base::FilePath::StringType path_suffix; | 93 base::FilePath::StringType path_suffix; |
102 base::string16 error_message; | 94 base::string16 error_message; |
103 std::string file_type; | |
104 | 95 |
105 if (!args->GetDictionary(0, &dict) || | 96 if (!args->GetDictionary(0, &dict) || |
106 !dict->GetString(kFileTypeKey, &file_type) || | |
107 !dict->GetString(kPathSuffixKey, &path_suffix) || | 97 !dict->GetString(kPathSuffixKey, &path_suffix) || |
108 !dict->GetString(ExtensionError::kExtensionIdKey, &extension_id) || | 98 !dict->GetString(ExtensionError::kExtensionIdKey, &extension_id) || |
109 !dict->GetString(ExtensionError::kMessageKey, &error_message)) { | 99 !dict->GetString(ExtensionError::kMessageKey, &error_message)) { |
110 NOTREACHED(); | 100 NOTREACHED(); |
111 return; | 101 return; |
112 } | 102 } |
113 | 103 |
114 const Extension* extension = | 104 const Extension* extension = |
115 ExtensionSystem::Get(Profile::FromWebUI(web_ui()))-> | 105 ExtensionSystem::Get(Profile::FromWebUI(web_ui()))-> |
116 extension_service()->GetExtensionById(extension_id, | 106 extension_service()->GetExtensionById(extension_id, |
117 true /* include disabled */ ); | 107 true /* include disabled */ ); |
118 base::FilePath path = extension->path().Append(path_suffix); | 108 base::FilePath path = extension->path().Append(path_suffix); |
Finnur
2013/09/09 09:15:56
In the event of a compromised caller (sending in v
Devlin
2013/09/09 16:56:03
It's possible that, if the caller is compromised,
Finnur
2013/09/09 18:05:43
The person controlling a compromised renderer does
Devlin
2013/09/09 18:26:14
Thanks for the explanation :) Fixed in 23875013.
| |
119 | 109 |
120 // Setting the title and the error message is the same for all file types. | 110 // Setting the title and the error message is the same for all file types. |
121 scoped_ptr<base::DictionaryValue> results(new base::DictionaryValue); | 111 scoped_ptr<base::DictionaryValue> results(new base::DictionaryValue); |
122 results->SetString(kTitleKey, | 112 results->SetString(kTitleKey, |
123 base::UTF8ToUTF16(extension->name()) + | 113 base::UTF8ToUTF16(extension->name()) + |
124 base::ASCIIToUTF16(": ") + | 114 base::ASCIIToUTF16(": ") + |
125 path.BaseName().LossyDisplayName()); | 115 path.BaseName().LossyDisplayName()); |
126 results->SetString(ExtensionError::kMessageKey, error_message); | 116 results->SetString(ExtensionError::kMessageKey, error_message); |
127 | 117 |
128 base::Closure closure; | 118 base::Closure closure; |
129 std::string* contents = NULL; | 119 std::string* contents = NULL; |
130 | 120 |
131 if (file_type == kManifestFileType) { | 121 if (path_suffix == kManifestFilename) { |
132 std::string manifest_key; | 122 std::string manifest_key; |
133 if (!dict->GetString(ManifestError::kManifestKeyKey, &manifest_key)) { | 123 if (!dict->GetString(ManifestError::kManifestKeyKey, &manifest_key)) { |
134 NOTREACHED(); | 124 NOTREACHED(); |
135 return; | 125 return; |
136 } | 126 } |
137 | 127 |
138 // A "specific" location is optional. | 128 // A "specific" location is optional. |
139 std::string specific; | 129 std::string specific; |
140 dict->GetString(ManifestError::kManifestSpecificKey, &specific); | 130 dict->GetString(ManifestError::kManifestSpecificKey, &specific); |
141 | 131 |
142 contents = new std::string; // Owned by GetManifestFileCallback( ) | 132 contents = new std::string; // Owned by GetManifestFileCallback( ) |
Finnur
2013/09/09 09:15:56
It looks like this leaks as I don't really see thi
Devlin
2013/09/09 16:56:03
|contents| is base::Owned by the callback. This m
Finnur
2013/09/09 18:05:43
Thanks, I overlooked that.
| |
143 closure = base::Bind(&ExtensionErrorHandler::GetManifestFileCallback, | 133 closure = base::Bind(&ExtensionErrorHandler::GetManifestFileCallback, |
144 base::Unretained(this), | 134 base::Unretained(this), |
145 base::Owned(results.release()), | 135 base::Owned(results.release()), |
146 manifest_key, | 136 manifest_key, |
147 specific, | 137 specific, |
148 base::Owned(contents)); | 138 base::Owned(contents)); |
149 } else { | 139 } else { |
150 // currently, only manifest file types supported. | 140 int line_number = 0; |
151 NOTREACHED(); | 141 dict->GetInteger(RuntimeError::kLineNumberKey, &line_number); |
152 return; | 142 |
143 contents = new std::string; // Owned by GetSourceFileCallback() | |
Finnur
2013/09/09 09:15:56
Same problem here: GetSourceFileCallback passes th
Devlin
2013/09/09 16:56:03
See above :)
| |
144 closure = base::Bind(&ExtensionErrorHandler::GetSourceFileCallback, | |
145 base::Unretained(this), | |
146 base::Owned(results.release()), | |
147 line_number, | |
148 base::Owned(contents)); | |
153 } | 149 } |
154 | 150 |
155 content::BrowserThread::PostBlockingPoolTaskAndReply( | 151 content::BrowserThread::PostBlockingPoolTaskAndReply( |
156 FROM_HERE, | 152 FROM_HERE, |
157 base::Bind(base::IgnoreResult(&base::ReadFileToString), | 153 base::Bind(base::IgnoreResult(&base::ReadFileToString), |
158 path, | 154 path, |
159 contents), | 155 contents), |
160 closure); | 156 closure); |
161 } | 157 } |
162 | 158 |
163 void ExtensionErrorHandler::GetManifestFileCallback( | 159 void ExtensionErrorHandler::GetManifestFileCallback( |
164 base::DictionaryValue* results, | 160 base::DictionaryValue* results, |
165 const std::string& key, | 161 const std::string& key, |
166 const std::string& specific, | 162 const std::string& specific, |
167 std::string* contents) { | 163 std::string* contents) { |
168 ManifestHighlighter highlighter(*contents, key, specific); | 164 ManifestHighlighter highlighter(*contents, key, specific); |
169 HighlightDictionary(results, highlighter); | 165 highlighter.SetHighlightedRegions(results); |
170 web_ui()->CallJavascriptFunction( | 166 web_ui()->CallJavascriptFunction( |
171 "extensions.ExtensionErrorOverlay.requestFileSourceResponse", *results); | 167 "extensions.ExtensionErrorOverlay.requestFileSourceResponse", *results); |
172 } | 168 } |
169 | |
170 void ExtensionErrorHandler::GetSourceFileCallback( | |
171 base::DictionaryValue* results, | |
172 int line_number, | |
173 std::string* contents) { | |
174 SourceHighlighter highlighter(*contents, line_number); | |
175 highlighter.SetHighlightedRegions(results); | |
176 web_ui()->CallJavascriptFunction( | |
177 "extensions.ExtensionErrorOverlay.requestFileSourceResponse", *results); | |
178 } | |
173 | 179 |
174 } // namespace extensions | 180 } // namespace extensions |
OLD | NEW |