| 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 | 8 |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 12 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
| 13 #include "extensions/browser/content_hash_fetcher.h" | 13 #include "extensions/browser/content_hash_fetcher.h" |
| 14 #include "extensions/browser/content_hash_reader.h" | 14 #include "extensions/browser/content_hash_reader.h" |
| 15 #include "extensions/browser/content_verifier_delegate.h" | 15 #include "extensions/browser/content_verifier_delegate.h" |
| 16 #include "extensions/browser/content_verifier_io_data.h" | 16 #include "extensions/browser/content_verifier_io_data.h" |
| 17 #include "extensions/browser/extension_registry.h" | 17 #include "extensions/browser/extension_registry.h" |
| 18 #include "extensions/common/constants.h" | 18 #include "extensions/common/constants.h" |
| 19 #include "extensions/common/extension_l10n_util.h" | 19 #include "extensions/common/extension_l10n_util.h" |
| 20 | 20 |
| 21 namespace extensions { | 21 namespace extensions { |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 ContentVerifier::TestObserver* g_test_observer = NULL; | 25 ContentVerifier::TestObserver* g_test_observer = NULL; |
| 26 | 26 |
| 27 // This function converts paths like "//foo/bar", "./foo/bar", and |
| 28 // "/foo/bar" to "foo/bar". It also converts path separators to "/". |
| 29 base::FilePath NormalizeRelativePath(const base::FilePath& path) { |
| 30 if (path.ReferencesParent()) |
| 31 return base::FilePath(); |
| 32 |
| 33 std::vector<base::FilePath::StringType> parts; |
| 34 path.GetComponents(&parts); |
| 35 if (parts.empty()) |
| 36 return base::FilePath(); |
| 37 |
| 38 // Remove the first component if it is '.' or '/' or '//'. |
| 39 const base::FilePath::StringType separators( |
| 40 base::FilePath::kSeparators, base::FilePath::kSeparatorsLength); |
| 41 if (!parts[0].empty() && |
| 42 (parts[0] == base::FilePath::kCurrentDirectory || |
| 43 parts[0].find_first_not_of(separators) == std::string::npos)) |
| 44 parts.erase(parts.begin()); |
| 45 |
| 46 // Note that elsewhere we always normalize path separators to '/' so this |
| 47 // should work for all platforms. |
| 48 return base::FilePath( |
| 49 base::JoinString(parts, base::FilePath::StringType(1, '/'))); |
| 50 } |
| 51 |
| 27 } // namespace | 52 } // namespace |
| 28 | 53 |
| 29 // static | 54 // static |
| 30 void ContentVerifier::SetObserverForTests(TestObserver* observer) { | 55 void ContentVerifier::SetObserverForTests(TestObserver* observer) { |
| 31 g_test_observer = observer; | 56 g_test_observer = observer; |
| 32 } | 57 } |
| 33 | 58 |
| 34 ContentVerifier::ContentVerifier(content::BrowserContext* context, | 59 ContentVerifier::ContentVerifier(content::BrowserContext* context, |
| 35 ContentVerifierDelegate* delegate) | 60 ContentVerifierDelegate* delegate) |
| 36 : shutdown_(false), | 61 : shutdown_(false), |
| (...skipping 29 matching lines...) Expand all Loading... |
| 66 const std::string& extension_id, | 91 const std::string& extension_id, |
| 67 const base::FilePath& extension_root, | 92 const base::FilePath& extension_root, |
| 68 const base::FilePath& relative_path) { | 93 const base::FilePath& relative_path) { |
| 69 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | 94 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 70 | 95 |
| 71 const ContentVerifierIOData::ExtensionData* data = | 96 const ContentVerifierIOData::ExtensionData* data = |
| 72 io_data_->GetData(extension_id); | 97 io_data_->GetData(extension_id); |
| 73 if (!data) | 98 if (!data) |
| 74 return NULL; | 99 return NULL; |
| 75 | 100 |
| 101 base::FilePath normalized_path = NormalizeRelativePath(relative_path); |
| 102 |
| 76 std::set<base::FilePath> paths; | 103 std::set<base::FilePath> paths; |
| 77 paths.insert(relative_path); | 104 paths.insert(normalized_path); |
| 78 if (!ShouldVerifyAnyPaths(extension_id, extension_root, paths)) | 105 if (!ShouldVerifyAnyPaths(extension_id, extension_root, paths)) |
| 79 return NULL; | 106 return NULL; |
| 80 | 107 |
| 81 // TODO(asargent) - we can probably get some good performance wins by having | 108 // TODO(asargent) - we can probably get some good performance wins by having |
| 82 // a cache of ContentHashReader's that we hold onto past the end of each job. | 109 // a cache of ContentHashReader's that we hold onto past the end of each job. |
| 83 return new ContentVerifyJob( | 110 return new ContentVerifyJob( |
| 84 new ContentHashReader(extension_id, data->version, extension_root, | 111 new ContentHashReader(extension_id, data->version, extension_root, |
| 85 relative_path, delegate_->GetPublicKey()), | 112 normalized_path, delegate_->GetPublicKey()), |
| 86 base::Bind(&ContentVerifier::VerifyFailed, this, extension_id)); | 113 base::Bind(&ContentVerifier::VerifyFailed, this, extension_id)); |
| 87 } | 114 } |
| 88 | 115 |
| 89 void ContentVerifier::VerifyFailed(const std::string& extension_id, | 116 void ContentVerifier::VerifyFailed(const std::string& extension_id, |
| 90 ContentVerifyJob::FailureReason reason) { | 117 ContentVerifyJob::FailureReason reason) { |
| 91 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { | 118 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { |
| 92 content::BrowserThread::PostTask( | 119 content::BrowserThread::PostTask( |
| 93 content::BrowserThread::UI, | 120 content::BrowserThread::UI, |
| 94 FROM_HERE, | 121 FROM_HERE, |
| 95 base::Bind(&ContentVerifier::VerifyFailed, this, extension_id, reason)); | 122 base::Bind(&ContentVerifier::VerifyFailed, this, extension_id, reason)); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 109 | 136 |
| 110 if (reason == ContentVerifyJob::MISSING_ALL_HASHES) { | 137 if (reason == ContentVerifyJob::MISSING_ALL_HASHES) { |
| 111 // If we failed because there were no hashes yet for this extension, just | 138 // If we failed because there were no hashes yet for this extension, just |
| 112 // request some. | 139 // request some. |
| 113 fetcher_->DoFetch(extension, true /* force */); | 140 fetcher_->DoFetch(extension, true /* force */); |
| 114 } else { | 141 } else { |
| 115 delegate_->VerifyFailed(extension_id, reason); | 142 delegate_->VerifyFailed(extension_id, reason); |
| 116 } | 143 } |
| 117 } | 144 } |
| 118 | 145 |
| 119 static base::FilePath MakeImagePathRelative(const base::FilePath& path) { | |
| 120 if (path.ReferencesParent()) | |
| 121 return base::FilePath(); | |
| 122 | |
| 123 std::vector<base::FilePath::StringType> parts; | |
| 124 path.GetComponents(&parts); | |
| 125 if (parts.empty()) | |
| 126 return base::FilePath(); | |
| 127 | |
| 128 // Remove the first component if it is '.' or '/' or '//'. | |
| 129 const base::FilePath::StringType separators( | |
| 130 base::FilePath::kSeparators, base::FilePath::kSeparatorsLength); | |
| 131 if (!parts[0].empty() && | |
| 132 (parts[0] == base::FilePath::kCurrentDirectory || | |
| 133 parts[0].find_first_not_of(separators) == std::string::npos)) | |
| 134 parts.erase(parts.begin()); | |
| 135 | |
| 136 // Note that elsewhere we always normalize path separators to '/' so this | |
| 137 // should work for all platforms. | |
| 138 return base::FilePath( | |
| 139 base::JoinString(parts, base::FilePath::StringType(1, '/'))); | |
| 140 } | |
| 141 | |
| 142 void ContentVerifier::OnExtensionLoaded( | 146 void ContentVerifier::OnExtensionLoaded( |
| 143 content::BrowserContext* browser_context, | 147 content::BrowserContext* browser_context, |
| 144 const Extension* extension) { | 148 const Extension* extension) { |
| 145 if (shutdown_) | 149 if (shutdown_) |
| 146 return; | 150 return; |
| 147 | 151 |
| 148 ContentVerifierDelegate::Mode mode = delegate_->ShouldBeVerified(*extension); | 152 ContentVerifierDelegate::Mode mode = delegate_->ShouldBeVerified(*extension); |
| 149 if (mode != ContentVerifierDelegate::NONE) { | 153 if (mode != ContentVerifierDelegate::NONE) { |
| 150 // The browser image paths from the extension may not be relative (eg | 154 // The browser image paths from the extension may not be relative (eg |
| 151 // they might have leading '/' or './'), so we strip those to make | 155 // they might have leading '/' or './'), so we strip those to make |
| 152 // comparing to actual relative paths work later on. | 156 // comparing to actual relative paths work later on. |
| 153 std::set<base::FilePath> original_image_paths = | 157 std::set<base::FilePath> original_image_paths = |
| 154 delegate_->GetBrowserImagePaths(extension); | 158 delegate_->GetBrowserImagePaths(extension); |
| 155 | 159 |
| 156 scoped_ptr<std::set<base::FilePath>> image_paths( | 160 scoped_ptr<std::set<base::FilePath>> image_paths( |
| 157 new std::set<base::FilePath>); | 161 new std::set<base::FilePath>); |
| 158 for (const auto& path : original_image_paths) { | 162 for (const auto& path : original_image_paths) { |
| 159 image_paths->insert(MakeImagePathRelative(path)); | 163 image_paths->insert(NormalizeRelativePath(path)); |
| 160 } | 164 } |
| 161 | 165 |
| 162 scoped_ptr<ContentVerifierIOData::ExtensionData> data( | 166 scoped_ptr<ContentVerifierIOData::ExtensionData> data( |
| 163 new ContentVerifierIOData::ExtensionData( | 167 new ContentVerifierIOData::ExtensionData( |
| 164 image_paths.Pass(), | 168 image_paths.Pass(), |
| 165 extension->version() ? *extension->version() : base::Version())); | 169 extension->version() ? *extension->version() : base::Version())); |
| 166 content::BrowserThread::PostTask(content::BrowserThread::IO, | 170 content::BrowserThread::PostTask(content::BrowserThread::IO, |
| 167 FROM_HERE, | 171 FROM_HERE, |
| 168 base::Bind(&ContentVerifierIOData::AddData, | 172 base::Bind(&ContentVerifierIOData::AddData, |
| 169 io_data_, | 173 io_data_, |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 !extension_l10n_util::ShouldSkipValidation( | 280 !extension_l10n_util::ShouldSkipValidation( |
| 277 locales_dir, full_path.DirName(), *all_locales)) | 281 locales_dir, full_path.DirName(), *all_locales)) |
| 278 continue; | 282 continue; |
| 279 } | 283 } |
| 280 return true; | 284 return true; |
| 281 } | 285 } |
| 282 return false; | 286 return false; |
| 283 } | 287 } |
| 284 | 288 |
| 285 } // namespace extensions | 289 } // namespace extensions |
| OLD | NEW |