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

Side by Side Diff: extensions/browser/content_verify_job_unittest.cc

Issue 2771953003: Fix content verification code for undreadable and deleted files. (Closed)
Patch Set: Fix deleted file case and also make sure crbug 404802 does not regress 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
(Empty)
1 // Copyright 2017 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.
4
5 #include "base/files/file_path.h"
6 #include "base/files/file_util.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/memory/weak_ptr.h"
Devlin 2017/03/29 15:51:57 needed?
lazyboy 2017/03/29 17:12:50 No, removed.
9 #include "base/path_service.h"
10 #include "base/run_loop.h"
11 #include "base/version.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "extensions/browser/content_hash_reader.h"
15 #include "extensions/browser/extensions_test.h"
16 #include "extensions/common/constants.h"
17 #include "extensions/common/extension_paths.h"
18 #include "extensions/common/file_util.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "third_party/zlib/google/zip.h"
21
22 namespace extensions {
23
24 namespace {
25
26 extensions::ContentHashReader* CreateContentHashReader(
Devlin 2017/03/29 15:51:57 nit: return a refptr
lazyboy 2017/03/29 17:12:50 Done.
27 const Extension& extension,
28 base::FilePath& extension_resource_path) {
29 return new ContentHashReader(
30 extension.id(), *extension.version(), extension.path(),
31 extension_resource_path,
32 ContentVerifierKey(kWebstoreSignaturesPublicKey,
33 kWebstoreSignaturesPublicKeySize));
34 }
35
36 void DoNothingWithReasonParam(
37 extensions::ContentVerifyJob::FailureReason reason) {}
Devlin 2017/03/29 15:51:57 nit: no extensions:: prefix (also the rest of this
lazyboy 2017/03/29 17:12:50 Done.
38
39 class JobTestObserver : public extensions::ContentVerifyJob::TestObserver {
40 public:
41 JobTestObserver(const std::string& extension_id,
42 const base::FilePath& relative_path)
43 : extension_id_(extension_id), relative_path_(relative_path) {
44 extensions::ContentVerifyJob::SetObserverForTests(this);
45 }
46 ~JobTestObserver() {
47 extensions::ContentVerifyJob::SetObserverForTests(nullptr);
48 }
49
50 void JobStarted(const std::string& extension_id,
51 const base::FilePath& relative_path) override {}
52
53 void JobFinished(const std::string& extension_id,
54 const base::FilePath& relative_path,
55 ContentVerifyJob::FailureReason reason) override {
56 if (extension_id != extension_id_ || relative_path != relative_path_)
57 return;
58 failure_reason_ = reason;
59 run_loop_.Quit();
60 }
61
62 extensions::ContentVerifyJob::FailureReason WaitAndGetFailureReason() {
63 // Run() returns immediately if Quit() has already been called.
64 run_loop_.Run();
65 return failure_reason_;
Devlin 2017/03/29 15:51:56 maybe make failure_reason_ a base::Optional<>, and
lazyboy 2017/03/29 17:12:50 Done.
66 }
67
68 private:
69 base::RunLoop run_loop_;
70 std::string extension_id_;
71 base::FilePath relative_path_;
72 extensions::ContentVerifyJob::FailureReason failure_reason_;
73
74 DISALLOW_COPY_AND_ASSIGN(JobTestObserver);
75 };
76
77 } // namespace
78
79 class ContentVerifyJobUnittest : public ExtensionsTest {
80 public:
81 ContentVerifyJobUnittest() {}
82 ~ContentVerifyJobUnittest() override {}
83
84 void SetUp() override {
85 ExtensionsTest::SetUp();
86
87 // Needed for ContentVerifyJob::Start().
88 browser_threads_.reset(new content::TestBrowserThreadBundle(
Devlin 2017/03/29 15:51:57 prefer base::MakeUnique
lazyboy 2017/03/29 17:12:50 Done.
89 content::TestBrowserThreadBundle::REAL_IO_THREAD));
90 }
91
92 // Helper to get files from our subdirectory in the general extensions test
93 // data dir.
94 base::FilePath GetTestPath(const base::FilePath& relative_path) {
95 base::FilePath base_path;
96 EXPECT_TRUE(PathService::Get(extensions::DIR_TEST_DATA, &base_path));
97 base_path = base_path.AppendASCII("content_hash_fetcher");
98 return base_path.Append(relative_path);
99 }
100
101 // Unzips the extension source from |extension_zip| into a temporary
102 // directory and loads it. Returns the resuling Extension object.
103 // |destination| points to the path where the extension was extracted.
104 scoped_refptr<Extension> UnzipToTempDirAndLoad(
105 const base::FilePath& extension_zip,
106 base::FilePath* destination) {
107 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
108 *destination = temp_dir_.GetPath();
109 EXPECT_TRUE(zip::Unzip(extension_zip, *destination));
110
111 std::string error;
112 scoped_refptr<Extension> extension = file_util::LoadExtension(
113 *destination, Manifest::INTERNAL, 0 /* flags */, &error);
114 EXPECT_NE(nullptr, extension.get()) << " error:'" << error << "'";
115 return extension;
116 }
117
118 private:
119 base::ScopedTempDir temp_dir_;
120 std::unique_ptr<content::TestBrowserThreadBundle> browser_threads_;
121
122 DISALLOW_COPY_AND_ASSIGN(ContentVerifyJobUnittest);
123 };
124
125 // Tests that deleted legitimate files trigger content verification failure.
126 // Also tests that non-existent file request does not trigger content
127 // verification failure.
128 TEST_F(ContentVerifyJobUnittest, DeletedAndMissingFiles) {
129 base::FilePath unzipped_path;
130 base::FilePath test_dir_base =
131 GetTestPath(base::FilePath(FILE_PATH_LITERAL("with_verified_contents")));
Devlin 2017/03/29 15:51:57 I don't see this - did you forget to add it to the
lazyboy 2017/03/29 17:12:50 Yes, added now.
132 scoped_refptr<Extension> extension = UnzipToTempDirAndLoad(
133 test_dir_base.AppendASCII("source_all.zip"), &unzipped_path);
134 ASSERT_TRUE(extension.get());
135 // Make sure there is a verified_contents.json file there as this test cannot
136 // fetch it.
137 EXPECT_TRUE(
138 base::PathExists(file_util::GetVerifiedContentsPath(extension->path())));
139
140 const base::FilePath::CharType kExistentResource[] =
141 FILE_PATH_LITERAL("background.js");
142 base::FilePath existent_resource_path(kExistentResource);
143 {
144 // Make sure background.js passes verification correctly.
145 JobTestObserver observer(extension->id(), existent_resource_path);
146
147 scoped_refptr<ContentHashReader> content_hash_reader =
148 CreateContentHashReader(*extension.get(), existent_resource_path);
149 scoped_refptr<ContentVerifyJob> verify_job = new ContentVerifyJob(
150 content_hash_reader.get(), base::Bind(&DoNothingWithReasonParam));
151 verify_job->Start();
152 {
153 // Simulate serving background.js.
154 std::string background_contents;
155 base::ReadFileToString(
156 unzipped_path.Append(base::FilePath(kExistentResource)),
157 &background_contents);
158 verify_job->BytesRead(background_contents.size(),
159 base::string_as_array(&background_contents));
160 verify_job->DoneReading();
161 }
162 ContentVerifyJob::FailureReason reason = observer.WaitAndGetFailureReason();
163 // Expect no content-verification failure.
164 EXPECT_EQ(ContentVerifyJob::NONE, reason);
165 }
166
167 {
168 // Once background.js is deleted, verification will result in HASH_MISMATCH.
169 JobTestObserver observer(extension->id(), existent_resource_path);
170 // Now delete the existent file.
171 EXPECT_TRUE(base::DeleteFile(
172 unzipped_path.Append(base::FilePath(kExistentResource)), false));
173
174 scoped_refptr<ContentHashReader> content_hash_reader =
175 CreateContentHashReader(*extension.get(), existent_resource_path);
176 scoped_refptr<ContentVerifyJob> verify_job = new ContentVerifyJob(
177 content_hash_reader.get(), base::Bind(&DoNothingWithReasonParam));
178 verify_job->Start();
179 {
180 // Simulate serving deleted background.js.
181 std::string tmp;
182 verify_job->BytesRead(0, base::string_as_array(&tmp));
183 verify_job->DoneReading();
184 }
185 ContentVerifyJob::FailureReason reason = observer.WaitAndGetFailureReason();
186 // Expect content-verification failure.
Devlin 2017/03/29 15:51:56 nitty nit: comment probably unnecessary with the c
lazyboy 2017/03/29 17:12:50 Done.
187 EXPECT_EQ(ContentVerifyJob::HASH_MISMATCH, reason);
188 }
189
190 {
191 // Now ask for a non-existent resource non-existent.js. Verification should
192 // skip this file as it is not listed in our verified_contents.json file.
193 const base::FilePath::CharType kNonExistentResource[] =
194 FILE_PATH_LITERAL("non-existent.js");
195 base::FilePath non_existent_resource_path(kNonExistentResource);
196 JobTestObserver observer(extension->id(), non_existent_resource_path);
197
198 scoped_refptr<ContentHashReader> content_hash_reader =
199 CreateContentHashReader(*extension.get(), non_existent_resource_path);
200 scoped_refptr<ContentVerifyJob> verify_job = new ContentVerifyJob(
201 content_hash_reader.get(), base::Bind(&DoNothingWithReasonParam));
202 verify_job->Start();
203 {
204 // Simulate non existent file read.
205 std::string tmp;
206 verify_job->BytesRead(0, base::string_as_array(&tmp));
207 verify_job->DoneReading();
208 }
209 ContentVerifyJob::FailureReason reason = observer.WaitAndGetFailureReason();
210 // Expect no content-verification failure.
211 EXPECT_EQ(ContentVerifyJob::NONE, reason);
212 }
213 }
Devlin 2017/03/29 15:51:57 Since we're adding unit tests for this (yay! :)),
lazyboy 2017/03/29 17:12:50 Good idea, added.
214
215 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698