blob: a9f34b8c6d21e2bd88f1ab55cf1de7ae265df27e [file] [log] [blame]
[email protected]de0fdca22014-08-19 05:26:091// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]2e114e732011-07-22 02:55:042// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
sorin52ac0882015-01-24 01:15:005#include "components/update_client/component_unpacker.h"
[email protected]2e114e732011-07-22 02:55:046
sorin5cb1f5492014-09-23 04:07:447#include <stdint.h>
[email protected]2e114e732011-07-22 02:55:048#include <string>
Sorin Jianua8ef73d2017-11-02 16:55:179#include <utility>
[email protected]2e114e732011-07-22 02:55:0410#include <vector>
11
[email protected]f5d27e32014-01-31 06:48:5312#include "base/bind.h"
[email protected]f5d27e32014-01-31 06:48:5313#include "base/files/file_path.h"
thestig819adcc82014-09-10 22:24:5314#include "base/files/file_util.h"
[email protected]0910bae2014-06-10 17:53:2115#include "base/files/scoped_file.h"
[email protected]9e1685a2014-02-13 15:08:3416#include "base/location.h"
[email protected]871bdf12013-10-26 10:52:0617#include "base/logging.h"
avi5dd91f82015-12-25 22:30:4618#include "base/macros.h"
[email protected]de0fdca22014-08-19 05:26:0919#include "base/numerics/safe_conversions.h"
[email protected]3ea1b182013-02-08 22:38:4120#include "base/strings/string_number_conversions.h"
[email protected]e7463412013-06-10 22:53:4621#include "base/strings/stringprintf.h"
Sorin Jianuebd652462017-07-23 02:00:5822#include "base/threading/sequenced_task_runner_handle.h"
waffles5918d5f2017-05-23 01:45:2823#include "components/crx_file/crx_verifier.h"
sorin52ac0882015-01-24 01:15:0024#include "components/update_client/component_patcher.h"
Joshua Pawlickid5409e12019-04-06 00:23:1125#include "components/update_client/patcher.h"
26#include "components/update_client/unzipper.h"
sorin52ac0882015-01-24 01:15:0027#include "components/update_client/update_client.h"
sorin7b8650522016-11-02 18:23:4128#include "components/update_client/update_client_errors.h"
[email protected]2e114e732011-07-22 02:55:0429
sorin52ac0882015-01-24 01:15:0030namespace update_client {
[email protected]055981f2014-01-17 20:22:3231
sorincbb7c092016-10-27 01:39:2032ComponentUnpacker::Result::Result() {}
33
Joshua Pawlickid5409e12019-04-06 00:23:1134ComponentUnpacker::ComponentUnpacker(const std::vector<uint8_t>& pk_hash,
35 const base::FilePath& path,
36 scoped_refptr<CrxInstaller> installer,
37 std::unique_ptr<Unzipper> unzipper,
38 scoped_refptr<Patcher> patcher,
39 crx_file::VerifierFormat crx_format)
sorincbb7c092016-10-27 01:39:2040 : pk_hash_(pk_hash),
41 path_(path),
42 is_delta_(false),
43 installer_(installer),
Joshua Pawlickid5409e12019-04-06 00:23:1144 unzipper_(std::move(unzipper)),
45 patcher_tool_(patcher),
Joshua Pawlickif4b33f382018-08-17 17:36:5146 crx_format_(crx_format),
sorin7b8650522016-11-02 18:23:4147 error_(UnpackerError::kNone),
Sorin Jianuebd652462017-07-23 02:00:5848 extended_error_(0) {}
sorincbb7c092016-10-27 01:39:2049
50ComponentUnpacker::~ComponentUnpacker() {}
51
Sorin Jianua8ef73d2017-11-02 16:55:1752void ComponentUnpacker::Unpack(Callback callback) {
53 callback_ = std::move(callback);
Joshua Pawlicki6d764422018-02-21 15:23:1054 if (!Verify() || !BeginUnzipping())
sorincbb7c092016-10-27 01:39:2055 EndUnpacking();
[email protected]f5d27e32014-01-31 06:48:5356}
57
58bool ComponentUnpacker::Verify() {
[email protected]fb53e652014-04-30 11:27:1959 VLOG(1) << "Verifying component: " << path_.value();
[email protected]f5d27e32014-01-31 06:48:5360 if (pk_hash_.empty() || path_.empty()) {
sorin7b8650522016-11-02 18:23:4161 error_ = UnpackerError::kInvalidParams;
[email protected]f5d27e32014-01-31 06:48:5362 return false;
[email protected]2e114e732011-07-22 02:55:0463 }
waffles5918d5f2017-05-23 01:45:2864 const std::vector<std::vector<uint8_t>> required_keys = {pk_hash_};
Joshua Pawlickif4b33f382018-08-17 17:36:5165 const crx_file::VerifierResult result =
66 crx_file::Verify(path_, crx_format_, required_keys,
67 std::vector<uint8_t>(), &public_key_, nullptr);
waffles5918d5f2017-05-23 01:45:2868 if (result != crx_file::VerifierResult::OK_FULL &&
69 result != crx_file::VerifierResult::OK_DELTA) {
sorin7b8650522016-11-02 18:23:4170 error_ = UnpackerError::kInvalidFile;
Sorin Jianu3091104c2017-06-26 18:07:2071 extended_error_ = static_cast<int>(result);
[email protected]f5d27e32014-01-31 06:48:5372 return false;
[email protected]2e114e732011-07-22 02:55:0473 }
waffles5918d5f2017-05-23 01:45:2874 is_delta_ = result == crx_file::VerifierResult::OK_DELTA;
[email protected]fb53e652014-04-30 11:27:1975 VLOG(1) << "Verification successful: " << path_.value();
[email protected]f5d27e32014-01-31 06:48:5376 return true;
77}
78
Joshua Pawlicki6d764422018-02-21 15:23:1079bool ComponentUnpacker::BeginUnzipping() {
sorincbb7c092016-10-27 01:39:2080 // Mind the reference to non-const type, passed as an argument below.
[email protected]f5d27e32014-01-31 06:48:5381 base::FilePath& destination = is_delta_ ? unpack_diff_path_ : unpack_path_;
[email protected]03d9afc02013-12-03 17:55:5282 if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
[email protected]f5d27e32014-01-31 06:48:5383 &destination)) {
[email protected]fb53e652014-04-30 11:27:1984 VLOG(1) << "Unable to create temporary directory for unpacking.";
sorin7b8650522016-11-02 18:23:4185 error_ = UnpackerError::kUnzipPathError;
[email protected]f5d27e32014-01-31 06:48:5386 return false;
87 }
sorincbb7c092016-10-27 01:39:2088 VLOG(1) << "Unpacking in: " << destination.value();
Joshua Pawlickid5409e12019-04-06 00:23:1189 unzipper_->Unzip(path_, destination,
90 base::BindOnce(&ComponentUnpacker::EndUnzipping, this));
Joshua Pawlicki6d764422018-02-21 15:23:1091 return true;
92}
93
94void ComponentUnpacker::EndUnzipping(bool result) {
95 if (!result) {
[email protected]fb53e652014-04-30 11:27:1996 VLOG(1) << "Unzipping failed.";
sorin7b8650522016-11-02 18:23:4197 error_ = UnpackerError::kUnzipFailed;
Joshua Pawlicki6d764422018-02-21 15:23:1098 EndUnpacking();
99 return;
[email protected]f5d27e32014-01-31 06:48:53100 }
[email protected]fb53e652014-04-30 11:27:19101 VLOG(1) << "Unpacked successfully";
Joshua Pawlicki6d764422018-02-21 15:23:10102 BeginPatching();
[email protected]f5d27e32014-01-31 06:48:53103}
104
[email protected]f5d27e32014-01-31 06:48:53105bool ComponentUnpacker::BeginPatching() {
106 if (is_delta_) { // Package is a diff package.
107 // Use a different temp directory for the patch output files.
108 if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
109 &unpack_path_)) {
sorin7b8650522016-11-02 18:23:41110 error_ = UnpackerError::kUnzipPathError;
[email protected]f5d27e32014-01-31 06:48:53111 return false;
112 }
Sorin Jianuebd652462017-07-23 02:00:58113 patcher_ = base::MakeRefCounted<ComponentPatcher>(
Joshua Pawlickid5409e12019-04-06 00:23:11114 unpack_diff_path_, unpack_path_, installer_, patcher_tool_);
Sorin Jianuebd652462017-07-23 02:00:58115 base::SequencedTaskRunnerHandle::Get()->PostTask(
[email protected]94a481b2014-03-28 19:41:55116 FROM_HERE,
Sorin Jianuebd652462017-07-23 02:00:58117 base::BindOnce(&ComponentPatcher::Start, patcher_,
Sorin Jianua8ef73d2017-11-02 16:55:17118 base::BindOnce(&ComponentUnpacker::EndPatching,
119 scoped_refptr<ComponentUnpacker>(this))));
[email protected]f5d27e32014-01-31 06:48:53120 } else {
Sorin Jianuebd652462017-07-23 02:00:58121 base::SequencedTaskRunnerHandle::Get()->PostTask(
122 FROM_HERE, base::BindOnce(&ComponentUnpacker::EndPatching,
123 scoped_refptr<ComponentUnpacker>(this),
124 UnpackerError::kNone, 0));
[email protected]f5d27e32014-01-31 06:48:53125 }
126 return true;
127}
128
sorin7b8650522016-11-02 18:23:41129void ComponentUnpacker::EndPatching(UnpackerError error, int extended_error) {
[email protected]f5d27e32014-01-31 06:48:53130 error_ = error;
131 extended_error_ = extended_error;
Ivan Kotenkov75b1c3a2017-10-24 14:47:24132 patcher_ = nullptr;
sorincbb7c092016-10-27 01:39:20133
134 EndUnpacking();
[email protected]f5d27e32014-01-31 06:48:53135}
136
sorincbb7c092016-10-27 01:39:20137void ComponentUnpacker::EndUnpacking() {
[email protected]f5d27e32014-01-31 06:48:53138 if (!unpack_diff_path_.empty())
139 base::DeleteFile(unpack_diff_path_, true);
sorin7b8650522016-11-02 18:23:41140 if (error_ != UnpackerError::kNone && !unpack_path_.empty())
[email protected]f5d27e32014-01-31 06:48:53141 base::DeleteFile(unpack_path_, true);
[email protected]f5d27e32014-01-31 06:48:53142
sorincbb7c092016-10-27 01:39:20143 Result result;
144 result.error = error_;
145 result.extended_error = extended_error_;
Minh X. Nguyenaafd7632017-10-19 21:12:35146 if (error_ == UnpackerError::kNone) {
sorincbb7c092016-10-27 01:39:20147 result.unpack_path = unpack_path_;
Minh X. Nguyenaafd7632017-10-19 21:12:35148 result.public_key = public_key_;
149 }
sorincbb7c092016-10-27 01:39:20150
Sorin Jianuebd652462017-07-23 02:00:58151 base::SequencedTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:17152 FROM_HERE, base::BindOnce(std::move(callback_), result));
[email protected]2e114e732011-07-22 02:55:04153}
[email protected]055981f2014-01-17 20:22:32154
sorin52ac0882015-01-24 01:15:00155} // namespace update_client