OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/component_updater/component_patcher_operation.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/file_util.h" | |
11 #include "base/files/memory_mapped_file.h" | |
12 #include "base/json/json_file_value_serializer.h" | |
13 #include "base/memory/scoped_handle.h" | |
14 #include "base/path_service.h" | |
15 #include "base/strings/string_number_conversions.h" | |
16 #include "chrome/browser/component_updater/component_patcher.h" | |
17 #include "chrome/browser/component_updater/component_updater_service.h" | |
18 #include "chrome/common/extensions/extension_constants.h" | |
19 #include "crypto/secure_hash.h" | |
20 #include "crypto/sha2.h" | |
21 #include "crypto/signature_verifier.h" | |
22 #include "extensions/common/crx_file.h" | |
23 #include "third_party/zlib/google/zip.h" | |
24 | |
25 using crypto::SecureHash; | |
26 | |
27 namespace { | |
28 | |
29 const char kInput[] = "input"; | |
30 const char kOp[] = "op"; | |
31 const char kOutput[] = "output"; | |
32 const char kPatch[] = "patch"; | |
33 const char kSha256[] = "sha256"; | |
34 | |
35 } // namespace | |
36 | |
37 DeltaUpdateOp* CreateDeltaUpdateOp(base::DictionaryValue* command) { | |
38 std::string operation; | |
39 if (!command->GetString(kOp, &operation)) | |
40 return NULL; | |
41 if (operation == "copy") | |
42 return new DeltaUpdateOpCopy(); | |
43 else if (operation == "create") | |
44 return new DeltaUpdateOpCreate(); | |
45 else if (operation == "bsdiff") | |
46 return new DeltaUpdateOpPatchBsdiff(); | |
47 else if (operation == "courgette") | |
48 return new DeltaUpdateOpPatchCourgette(); | |
49 return NULL; | |
50 } | |
51 | |
52 DeltaUpdateOp::DeltaUpdateOp() {} | |
53 | |
54 DeltaUpdateOp::~DeltaUpdateOp() {} | |
55 | |
56 ComponentUnpacker::Error DeltaUpdateOp::Run(base::DictionaryValue* command_args, | |
57 const base::FilePath& input_dir, | |
58 const base::FilePath& unpack_dir, | |
59 ComponentPatcher* patcher, | |
60 ComponentInstaller* installer, | |
61 int* error) { | |
62 std::string output_rel_path; | |
63 if (!command_args->GetString(kOutput, &output_rel_path) || | |
64 !command_args->GetString(kSha256, &output_sha256_)) | |
65 return ComponentUnpacker::kDeltaBadCommands; | |
66 | |
67 output_abs_path_ = unpack_dir.Append( | |
68 base::FilePath::FromUTF8Unsafe(output_rel_path)); | |
69 ComponentUnpacker::Error parse_result = DoParseArguments( | |
70 command_args, input_dir, installer); | |
71 if (parse_result != ComponentUnpacker::kNone) | |
72 return parse_result; | |
73 | |
74 const base::FilePath parent = output_abs_path_.DirName(); | |
75 if (!file_util::DirectoryExists(parent)) { | |
76 if (!file_util::CreateDirectory(parent)) | |
77 return ComponentUnpacker::kIoError; | |
78 } | |
79 | |
80 ComponentUnpacker::Error run_result = DoRun(patcher, error); | |
81 if (run_result != ComponentUnpacker::kNone) | |
82 return run_result; | |
83 | |
84 return CheckHash(); | |
85 } | |
86 | |
87 // Uses the hash as a checksum to confirm that the file now residing in the | |
88 // output directory probably has the contents it should. | |
89 ComponentUnpacker::Error DeltaUpdateOp::CheckHash() { | |
90 std::vector<uint8> expected_hash; | |
91 if (!base::HexStringToBytes(output_sha256_, &expected_hash) || | |
92 expected_hash.size() != crypto::kSHA256Length) | |
93 return ComponentUnpacker::kDeltaVerificationFailure; | |
94 | |
95 base::MemoryMappedFile output_file_mmapped; | |
96 if (!output_file_mmapped.Initialize(output_abs_path_)) | |
97 return ComponentUnpacker::kDeltaVerificationFailure; | |
98 | |
99 uint8 actual_hash[crypto::kSHA256Length] = {0}; | |
100 const scoped_ptr<SecureHash> hasher(SecureHash::Create(SecureHash::SHA256)); | |
101 hasher->Update(output_file_mmapped.data(), output_file_mmapped.length()); | |
102 hasher->Finish(actual_hash, sizeof(actual_hash)); | |
103 if (memcmp(actual_hash, &expected_hash[0], sizeof(actual_hash))) | |
104 return ComponentUnpacker::kDeltaVerificationFailure; | |
105 | |
106 return ComponentUnpacker::kNone; | |
107 } | |
108 | |
109 DeltaUpdateOpCopy::DeltaUpdateOpCopy() {} | |
110 | |
111 ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments( | |
112 base::DictionaryValue* command_args, | |
113 const base::FilePath& input_dir, | |
114 ComponentInstaller* installer) { | |
115 std::string input_rel_path; | |
116 if (!command_args->GetString(kInput, &input_rel_path)) | |
117 return ComponentUnpacker::kDeltaBadCommands; | |
118 | |
119 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) | |
120 return ComponentUnpacker::kDeltaMissingExistingFile; | |
121 | |
122 return ComponentUnpacker::kNone; | |
123 } | |
124 | |
125 ComponentUnpacker::Error DeltaUpdateOpCopy::DoRun(ComponentPatcher*, | |
126 int* error) { | |
127 *error = 0; | |
128 if (!file_util::CopyFile(input_abs_path_, output_abs_path_)) | |
129 return ComponentUnpacker::kDeltaOperationFailure; | |
130 | |
131 return ComponentUnpacker::kNone; | |
132 } | |
133 | |
134 DeltaUpdateOpCreate::DeltaUpdateOpCreate() {} | |
135 | |
136 ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments( | |
137 base::DictionaryValue* command_args, | |
138 const base::FilePath& input_dir, | |
139 ComponentInstaller* installer) { | |
140 std::string patch_rel_path; | |
141 if (!command_args->GetString(kPatch, &patch_rel_path)) | |
142 return ComponentUnpacker::kDeltaBadCommands; | |
143 | |
144 patch_abs_path_ = input_dir.Append( | |
145 base::FilePath::FromUTF8Unsafe(patch_rel_path)); | |
146 | |
147 return ComponentUnpacker::kNone; | |
148 } | |
149 | |
150 ComponentUnpacker::Error DeltaUpdateOpCreate::DoRun(ComponentPatcher*, | |
151 int* error) { | |
152 *error = 0; | |
153 if (!file_util::Move(patch_abs_path_, output_abs_path_)) | |
154 return ComponentUnpacker::kDeltaOperationFailure; | |
155 | |
156 return ComponentUnpacker::kNone; | |
157 } | |
158 | |
159 DeltaUpdateOpPatchBsdiff::DeltaUpdateOpPatchBsdiff() {} | |
160 | |
161 ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoParseArguments( | |
162 base::DictionaryValue* command_args, | |
163 const base::FilePath& input_dir, | |
164 ComponentInstaller* installer) { | |
165 std::string patch_rel_path; | |
166 std::string input_rel_path; | |
167 if (!command_args->GetString(kPatch, &patch_rel_path) || | |
168 !command_args->GetString(kInput, &input_rel_path)) | |
169 return ComponentUnpacker::kDeltaBadCommands; | |
170 | |
171 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) | |
172 return ComponentUnpacker::kDeltaMissingExistingFile; | |
173 | |
174 patch_abs_path_ = input_dir.Append( | |
175 base::FilePath::FromUTF8Unsafe(patch_rel_path)); | |
176 | |
177 return ComponentUnpacker::kNone; | |
178 } | |
179 | |
180 ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoRun( | |
181 ComponentPatcher* patcher, | |
182 int* error) { | |
183 *error = 0; | |
184 return patcher->Patch(ComponentPatcher::kPatchTypeBsdiff, | |
185 input_abs_path_, | |
186 patch_abs_path_, | |
187 output_abs_path_, | |
188 error); | |
189 } | |
190 | |
191 DeltaUpdateOpPatchCourgette::DeltaUpdateOpPatchCourgette() {} | |
192 | |
193 ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoParseArguments( | |
194 base::DictionaryValue* command_args, | |
195 const base::FilePath& input_dir, | |
196 ComponentInstaller* installer) { | |
197 std::string patch_rel_path; | |
198 std::string input_rel_path; | |
199 if (!command_args->GetString(kPatch, &patch_rel_path) || | |
200 !command_args->GetString(kInput, &input_rel_path)) | |
201 return ComponentUnpacker::kDeltaBadCommands; | |
202 | |
203 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) | |
204 return ComponentUnpacker::kDeltaMissingExistingFile; | |
205 | |
206 patch_abs_path_ = input_dir.Append( | |
207 base::FilePath::FromUTF8Unsafe(patch_rel_path)); | |
208 | |
209 return ComponentUnpacker::kNone; | |
210 } | |
211 | |
212 ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoRun( | |
213 ComponentPatcher* patcher, | |
214 int* error) { | |
215 *error = 0; | |
216 return patcher->Patch(ComponentPatcher::kPatchTypeCourgette, | |
217 input_abs_path_, | |
218 patch_abs_path_, | |
219 output_abs_path_, | |
220 error); | |
221 } | |
222 | |
OLD | NEW |