OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 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 |