Skip managed bookmarks at the BookmarkChangeProcessor.
[chromium-blink-merge.git] / extensions / browser / content_verifier.cc
blob52321c9267ac9e6cdc3e366a47584026e7b58d66
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
3 // found in the LICENSE file.
5 #include "extensions/browser/content_verifier.h"
7 #include <algorithm>
9 #include "base/files/file_path.h"
10 #include "base/stl_util.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "extensions/browser/content_hash_fetcher.h"
13 #include "extensions/browser/content_hash_reader.h"
14 #include "extensions/browser/content_verifier_delegate.h"
15 #include "extensions/browser/content_verifier_io_data.h"
16 #include "extensions/browser/extension_registry.h"
17 #include "extensions/common/constants.h"
18 #include "extensions/common/extension_l10n_util.h"
20 namespace extensions {
22 ContentVerifier::ContentVerifier(content::BrowserContext* context,
23 ContentVerifierDelegate* delegate)
24 : shutdown_(false),
25 context_(context),
26 delegate_(delegate),
27 fetcher_(new ContentHashFetcher(
28 context,
29 delegate,
30 base::Bind(&ContentVerifier::OnFetchComplete, this))),
31 observer_(this),
32 io_data_(new ContentVerifierIOData) {
35 ContentVerifier::~ContentVerifier() {
38 void ContentVerifier::Start() {
39 ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
40 observer_.Add(registry);
43 void ContentVerifier::Shutdown() {
44 shutdown_ = true;
45 content::BrowserThread::PostTask(
46 content::BrowserThread::IO,
47 FROM_HERE,
48 base::Bind(&ContentVerifierIOData::Clear, io_data_));
49 observer_.RemoveAll();
50 fetcher_.reset();
53 ContentVerifyJob* ContentVerifier::CreateJobFor(
54 const std::string& extension_id,
55 const base::FilePath& extension_root,
56 const base::FilePath& relative_path) {
57 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
59 const ContentVerifierIOData::ExtensionData* data =
60 io_data_->GetData(extension_id);
61 if (!data)
62 return NULL;
64 std::set<base::FilePath> paths;
65 paths.insert(relative_path);
66 if (!ShouldVerifyAnyPaths(extension_id, extension_root, paths))
67 return NULL;
69 // TODO(asargent) - we can probably get some good performance wins by having
70 // a cache of ContentHashReader's that we hold onto past the end of each job.
71 return new ContentVerifyJob(
72 new ContentHashReader(extension_id,
73 data->version,
74 extension_root,
75 relative_path,
76 delegate_->PublicKey()),
77 base::Bind(&ContentVerifier::VerifyFailed, this, extension_id));
80 void ContentVerifier::VerifyFailed(const std::string& extension_id,
81 ContentVerifyJob::FailureReason reason) {
82 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
83 content::BrowserThread::PostTask(
84 content::BrowserThread::UI,
85 FROM_HERE,
86 base::Bind(&ContentVerifier::VerifyFailed, this, extension_id, reason));
87 return;
89 if (shutdown_)
90 return;
92 VLOG(1) << "VerifyFailed " << extension_id << " reason:" << reason;
94 ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
95 const Extension* extension =
96 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
98 if (!extension)
99 return;
101 if (reason == ContentVerifyJob::MISSING_ALL_HASHES) {
102 // If we failed because there were no hashes yet for this extension, just
103 // request some.
104 fetcher_->DoFetch(extension, true /* force */);
105 } else {
106 delegate_->VerifyFailed(extension_id);
110 void ContentVerifier::OnExtensionLoaded(
111 content::BrowserContext* browser_context,
112 const Extension* extension) {
113 if (shutdown_)
114 return;
116 ContentVerifierDelegate::Mode mode = delegate_->ShouldBeVerified(*extension);
117 if (mode != ContentVerifierDelegate::NONE) {
118 scoped_ptr<ContentVerifierIOData::ExtensionData> data(
119 new ContentVerifierIOData::ExtensionData(
120 delegate_->GetBrowserImagePaths(extension),
121 extension->version() ? *extension->version() : base::Version()));
122 content::BrowserThread::PostTask(content::BrowserThread::IO,
123 FROM_HERE,
124 base::Bind(&ContentVerifierIOData::AddData,
125 io_data_,
126 extension->id(),
127 base::Passed(&data)));
128 fetcher_->ExtensionLoaded(extension);
132 void ContentVerifier::OnExtensionUnloaded(
133 content::BrowserContext* browser_context,
134 const Extension* extension,
135 UnloadedExtensionInfo::Reason reason) {
136 if (shutdown_)
137 return;
138 content::BrowserThread::PostTask(
139 content::BrowserThread::IO,
140 FROM_HERE,
141 base::Bind(
142 &ContentVerifierIOData::RemoveData, io_data_, extension->id()));
143 if (fetcher_)
144 fetcher_->ExtensionUnloaded(extension);
147 void ContentVerifier::OnFetchCompleteHelper(const std::string& extension_id,
148 bool shouldVerifyAnyPathsResult) {
149 if (shouldVerifyAnyPathsResult)
150 delegate_->VerifyFailed(extension_id);
153 void ContentVerifier::OnFetchComplete(
154 const std::string& extension_id,
155 bool success,
156 bool was_force_check,
157 const std::set<base::FilePath>& hash_mismatch_paths) {
158 if (shutdown_)
159 return;
161 VLOG(1) << "OnFetchComplete " << extension_id << " success:" << success;
163 ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
164 const Extension* extension =
165 registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
166 if (!delegate_ || !extension)
167 return;
169 ContentVerifierDelegate::Mode mode = delegate_->ShouldBeVerified(*extension);
170 if (was_force_check && !success &&
171 mode == ContentVerifierDelegate::ENFORCE_STRICT) {
172 // We weren't able to get verified_contents.json or weren't able to compute
173 // hashes.
174 delegate_->VerifyFailed(extension_id);
175 } else {
176 content::BrowserThread::PostTaskAndReplyWithResult(
177 content::BrowserThread::IO,
178 FROM_HERE,
179 base::Bind(&ContentVerifier::ShouldVerifyAnyPaths,
180 this,
181 extension_id,
182 extension->path(),
183 hash_mismatch_paths),
184 base::Bind(
185 &ContentVerifier::OnFetchCompleteHelper, this, extension_id));
189 bool ContentVerifier::ShouldVerifyAnyPaths(
190 const std::string& extension_id,
191 const base::FilePath& extension_root,
192 const std::set<base::FilePath>& relative_paths) {
193 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
194 const ContentVerifierIOData::ExtensionData* data =
195 io_data_->GetData(extension_id);
196 if (!data)
197 return false;
199 const std::set<base::FilePath>& browser_images = data->browser_image_paths;
201 base::FilePath locales_dir = extension_root.Append(kLocaleFolder);
202 scoped_ptr<std::set<std::string> > all_locales;
204 for (std::set<base::FilePath>::const_iterator i = relative_paths.begin();
205 i != relative_paths.end();
206 ++i) {
207 const base::FilePath& relative_path = *i;
209 if (relative_path == base::FilePath(kManifestFilename))
210 continue;
212 if (ContainsKey(browser_images, relative_path))
213 continue;
215 base::FilePath full_path = extension_root.Append(relative_path);
216 if (locales_dir.IsParent(full_path)) {
217 if (!all_locales) {
218 // TODO(asargent) - see if we can cache this list longer to avoid
219 // having to fetch it more than once for a given run of the
220 // browser. Maybe it can never change at runtime? (Or if it can, maybe
221 // there is an event we can listen for to know to drop our cache).
222 all_locales.reset(new std::set<std::string>);
223 extension_l10n_util::GetAllLocales(all_locales.get());
226 // Since message catalogs get transcoded during installation, we want
227 // to skip those paths.
228 if (full_path.DirName().DirName() == locales_dir &&
229 !extension_l10n_util::ShouldSkipValidation(
230 locales_dir, full_path.DirName(), *all_locales))
231 continue;
233 return true;
235 return false;
238 } // namespace extensions