| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/content_verifier.h" | 5 #include "extensions/browser/content_verifier.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 const std::string& extension_id, | 106 const std::string& extension_id, |
| 107 const base::FilePath& extension_root, | 107 const base::FilePath& extension_root, |
| 108 const base::FilePath& relative_path) { | 108 const base::FilePath& relative_path) { |
| 109 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 109 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 110 | 110 |
| 111 const ContentVerifierIOData::ExtensionData* data = | 111 const ContentVerifierIOData::ExtensionData* data = |
| 112 io_data_->GetData(extension_id); | 112 io_data_->GetData(extension_id); |
| 113 if (!data) | 113 if (!data) |
| 114 return NULL; | 114 return NULL; |
| 115 | 115 |
| 116 base::FilePath normalized_path = NormalizeRelativePath(relative_path); | 116 base::FilePath normalized_unix_path = NormalizeRelativePath(relative_path); |
| 117 | 117 |
| 118 std::set<base::FilePath> paths; | 118 std::set<base::FilePath> unix_paths; |
| 119 paths.insert(normalized_path); | 119 unix_paths.insert(normalized_unix_path); |
| 120 if (!ShouldVerifyAnyPaths(extension_id, extension_root, paths)) | 120 if (!ShouldVerifyAnyPaths(extension_id, extension_root, unix_paths)) |
| 121 return NULL; | 121 return NULL; |
| 122 | 122 |
| 123 // TODO(asargent) - we can probably get some good performance wins by having | 123 // TODO(asargent) - we can probably get some good performance wins by having |
| 124 // a cache of ContentHashReader's that we hold onto past the end of each job. | 124 // a cache of ContentHashReader's that we hold onto past the end of each job. |
| 125 return new ContentVerifyJob( | 125 return new ContentVerifyJob( |
| 126 new ContentHashReader(extension_id, data->version, extension_root, | 126 new ContentHashReader(extension_id, data->version, extension_root, |
| 127 normalized_path, delegate_->GetPublicKey()), | 127 normalized_unix_path, delegate_->GetPublicKey()), |
| 128 base::BindOnce(&ContentVerifier::VerifyFailed, this, extension_id)); | 128 base::BindOnce(&ContentVerifier::VerifyFailed, this, extension_id)); |
| 129 } | 129 } |
| 130 | 130 |
| 131 void ContentVerifier::VerifyFailed(const std::string& extension_id, | 131 void ContentVerifier::VerifyFailed(const std::string& extension_id, |
| 132 ContentVerifyJob::FailureReason reason) { | 132 ContentVerifyJob::FailureReason reason) { |
| 133 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { | 133 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { |
| 134 content::BrowserThread::PostTask( | 134 content::BrowserThread::PostTask( |
| 135 content::BrowserThread::UI, | 135 content::BrowserThread::UI, |
| 136 FROM_HERE, | 136 FROM_HERE, |
| 137 base::Bind(&ContentVerifier::VerifyFailed, this, extension_id, reason)); | 137 base::Bind(&ContentVerifier::VerifyFailed, this, extension_id, reason)); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 const std::string& extension_id, | 211 const std::string& extension_id, |
| 212 bool should_verify_any_paths_result) { | 212 bool should_verify_any_paths_result) { |
| 213 if (should_verify_any_paths_result) | 213 if (should_verify_any_paths_result) |
| 214 delegate_->VerifyFailed(extension_id, ContentVerifyJob::MISSING_ALL_HASHES); | 214 delegate_->VerifyFailed(extension_id, ContentVerifyJob::MISSING_ALL_HASHES); |
| 215 } | 215 } |
| 216 | 216 |
| 217 void ContentVerifier::OnFetchComplete( | 217 void ContentVerifier::OnFetchComplete( |
| 218 const std::string& extension_id, | 218 const std::string& extension_id, |
| 219 bool success, | 219 bool success, |
| 220 bool was_force_check, | 220 bool was_force_check, |
| 221 const std::set<base::FilePath>& hash_mismatch_paths) { | 221 const std::set<base::FilePath>& hash_mismatch_unix_paths) { |
| 222 if (g_test_observer) | 222 if (g_test_observer) |
| 223 g_test_observer->OnFetchComplete(extension_id, success); | 223 g_test_observer->OnFetchComplete(extension_id, success); |
| 224 | 224 |
| 225 if (shutdown_) | 225 if (shutdown_) |
| 226 return; | 226 return; |
| 227 | 227 |
| 228 VLOG(1) << "OnFetchComplete " << extension_id << " success:" << success; | 228 VLOG(1) << "OnFetchComplete " << extension_id << " success:" << success; |
| 229 | 229 |
| 230 ExtensionRegistry* registry = ExtensionRegistry::Get(context_); | 230 ExtensionRegistry* registry = ExtensionRegistry::Get(context_); |
| 231 const Extension* extension = | 231 const Extension* extension = |
| 232 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); | 232 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); |
| 233 if (!delegate_ || !extension) | 233 if (!delegate_ || !extension) |
| 234 return; | 234 return; |
| 235 | 235 |
| 236 ContentVerifierDelegate::Mode mode = delegate_->ShouldBeVerified(*extension); | 236 ContentVerifierDelegate::Mode mode = delegate_->ShouldBeVerified(*extension); |
| 237 if (was_force_check && !success && | 237 if (was_force_check && !success && |
| 238 mode == ContentVerifierDelegate::ENFORCE_STRICT) { | 238 mode == ContentVerifierDelegate::ENFORCE_STRICT) { |
| 239 // We weren't able to get verified_contents.json or weren't able to compute | 239 // We weren't able to get verified_contents.json or weren't able to compute |
| 240 // hashes. | 240 // hashes. |
| 241 delegate_->VerifyFailed(extension_id, ContentVerifyJob::MISSING_ALL_HASHES); | 241 delegate_->VerifyFailed(extension_id, ContentVerifyJob::MISSING_ALL_HASHES); |
| 242 } else { | 242 } else { |
| 243 content::BrowserThread::PostTaskAndReplyWithResult( | 243 content::BrowserThread::PostTaskAndReplyWithResult( |
| 244 content::BrowserThread::IO, | 244 content::BrowserThread::IO, FROM_HERE, |
| 245 FROM_HERE, | 245 base::Bind(&ContentVerifier::ShouldVerifyAnyPaths, this, extension_id, |
| 246 base::Bind(&ContentVerifier::ShouldVerifyAnyPaths, | 246 extension->path(), hash_mismatch_unix_paths), |
| 247 this, | 247 base::Bind(&ContentVerifier::OnFetchCompleteHelper, this, |
| 248 extension_id, | 248 extension_id)); |
| 249 extension->path(), | |
| 250 hash_mismatch_paths), | |
| 251 base::Bind( | |
| 252 &ContentVerifier::OnFetchCompleteHelper, this, extension_id)); | |
| 253 } | 249 } |
| 254 } | 250 } |
| 255 | 251 |
| 256 bool ContentVerifier::ShouldVerifyAnyPaths( | 252 bool ContentVerifier::ShouldVerifyAnyPaths( |
| 257 const std::string& extension_id, | 253 const std::string& extension_id, |
| 258 const base::FilePath& extension_root, | 254 const base::FilePath& extension_root, |
| 259 const std::set<base::FilePath>& relative_paths) { | 255 const std::set<base::FilePath>& relative_unix_paths) { |
| 260 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 256 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 261 const ContentVerifierIOData::ExtensionData* data = | 257 const ContentVerifierIOData::ExtensionData* data = |
| 262 io_data_->GetData(extension_id); | 258 io_data_->GetData(extension_id); |
| 263 if (!data) | 259 if (!data) |
| 264 return false; | 260 return false; |
| 265 | 261 |
| 266 const std::set<base::FilePath>& browser_images = *(data->browser_image_paths); | 262 const std::set<base::FilePath>& browser_images = *(data->browser_image_paths); |
| 267 | 263 |
| 268 base::FilePath locales_dir = extension_root.Append(kLocaleFolder); | 264 base::FilePath locales_dir = extension_root.Append(kLocaleFolder); |
| 269 std::unique_ptr<std::set<std::string>> all_locales; | 265 std::unique_ptr<std::set<std::string>> all_locales; |
| 270 | 266 |
| 271 for (std::set<base::FilePath>::const_iterator i = relative_paths.begin(); | 267 const base::FilePath manifest_file(kManifestFilename); |
| 272 i != relative_paths.end(); | 268 const base::FilePath messages_file(kMessagesFilename); |
| 273 ++i) { | 269 for (const base::FilePath& relative_unix_path : relative_unix_paths) { |
| 274 const base::FilePath& relative_path = *i; | 270 if (relative_unix_path == manifest_file) |
| 275 | |
| 276 if (relative_path == base::FilePath(kManifestFilename)) | |
| 277 continue; | 271 continue; |
| 278 | 272 |
| 279 if (base::ContainsKey(browser_images, relative_path)) | 273 if (base::ContainsKey(browser_images, relative_unix_path)) |
| 280 continue; | 274 continue; |
| 281 | 275 |
| 282 base::FilePath full_path = extension_root.Append(relative_path); | 276 base::FilePath full_path = |
| 277 extension_root.Append(relative_unix_path.NormalizePathSeparators()); |
| 283 if (locales_dir.IsParent(full_path)) { | 278 if (locales_dir.IsParent(full_path)) { |
| 284 if (!all_locales) { | 279 if (!all_locales) { |
| 285 // TODO(asargent) - see if we can cache this list longer to avoid | 280 // TODO(asargent) - see if we can cache this list longer to avoid |
| 286 // having to fetch it more than once for a given run of the | 281 // having to fetch it more than once for a given run of the |
| 287 // browser. Maybe it can never change at runtime? (Or if it can, maybe | 282 // browser. Maybe it can never change at runtime? (Or if it can, maybe |
| 288 // there is an event we can listen for to know to drop our cache). | 283 // there is an event we can listen for to know to drop our cache). |
| 289 all_locales.reset(new std::set<std::string>); | 284 all_locales.reset(new std::set<std::string>); |
| 290 extension_l10n_util::GetAllLocales(all_locales.get()); | 285 extension_l10n_util::GetAllLocales(all_locales.get()); |
| 291 } | 286 } |
| 292 | 287 |
| 293 // Since message catalogs get transcoded during installation, we want | 288 // Since message catalogs get transcoded during installation, we want |
| 294 // to skip those paths. | 289 // to skip those paths. See if this path looks like |
| 295 if (full_path.DirName().DirName() == locales_dir && | 290 // _locales/<some locale>/messages.json - if so then skip it. |
| 296 !extension_l10n_util::ShouldSkipValidation( | 291 if (full_path.BaseName() == messages_file && |
| 297 locales_dir, full_path.DirName(), *all_locales)) | 292 full_path.DirName().DirName() == locales_dir && |
| 293 base::ContainsKey(*all_locales, |
| 294 full_path.DirName().BaseName().MaybeAsASCII())) { |
| 298 continue; | 295 continue; |
| 296 } |
| 299 } | 297 } |
| 300 return true; | 298 return true; |
| 301 } | 299 } |
| 302 return false; | 300 return false; |
| 303 } | 301 } |
| 304 | 302 |
| 305 } // namespace extensions | 303 } // namespace extensions |
| OLD | NEW |