blob: e57d2f728f544693da83da9f91105e3665256447 [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();
Joshua Pawlicki9656e3922019-09-16 16:34:5160 if (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 }
Joshua Pawlicki9656e3922019-09-16 16:34:5164 std::vector<std::vector<uint8_t>> required_keys;
65 if (!pk_hash_.empty())
66 required_keys.push_back(pk_hash_);
Joshua Pawlickif4b33f382018-08-17 17:36:5167 const crx_file::VerifierResult result =
68 crx_file::Verify(path_, crx_format_, required_keys,
69 std::vector<uint8_t>(), &public_key_, nullptr);
waffles5918d5f2017-05-23 01:45:2870 if (result != crx_file::VerifierResult::OK_FULL &&
71 result != crx_file::VerifierResult::OK_DELTA) {
sorin7b8650522016-11-02 18:23:4172 error_ = UnpackerError::kInvalidFile;
Sorin Jianu3091104c2017-06-26 18:07:2073 extended_error_ = static_cast<int>(result);
[email protected]f5d27e32014-01-31 06:48:5374 return false;
[email protected]2e114e732011-07-22 02:55:0475 }
waffles5918d5f2017-05-23 01:45:2876 is_delta_ = result == crx_file::VerifierResult::OK_DELTA;
[email protected]fb53e652014-04-30 11:27:1977 VLOG(1) << "Verification successful: " << path_.value();
[email protected]f5d27e32014-01-31 06:48:5378 return true;
79}
80
Joshua Pawlicki6d764422018-02-21 15:23:1081bool ComponentUnpacker::BeginUnzipping() {
sorincbb7c092016-10-27 01:39:2082 // Mind the reference to non-const type, passed as an argument below.
[email protected]f5d27e32014-01-31 06:48:5383 base::FilePath& destination = is_delta_ ? unpack_diff_path_ : unpack_path_;
[email protected]03d9afc02013-12-03 17:55:5284 if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
[email protected]f5d27e32014-01-31 06:48:5385 &destination)) {
[email protected]fb53e652014-04-30 11:27:1986 VLOG(1) << "Unable to create temporary directory for unpacking.";
sorin7b8650522016-11-02 18:23:4187 error_ = UnpackerError::kUnzipPathError;
[email protected]f5d27e32014-01-31 06:48:5388 return false;
89 }
sorincbb7c092016-10-27 01:39:2090 VLOG(1) << "Unpacking in: " << destination.value();
Joshua Pawlickid5409e12019-04-06 00:23:1191 unzipper_->Unzip(path_, destination,
92 base::BindOnce(&ComponentUnpacker::EndUnzipping, this));
Joshua Pawlicki6d764422018-02-21 15:23:1093 return true;
94}
95
96void ComponentUnpacker::EndUnzipping(bool result) {
97 if (!result) {
[email protected]fb53e652014-04-30 11:27:1998 VLOG(1) << "Unzipping failed.";
sorin7b8650522016-11-02 18:23:4199 error_ = UnpackerError::kUnzipFailed;
Joshua Pawlicki6d764422018-02-21 15:23:10100 EndUnpacking();
101 return;
[email protected]f5d27e32014-01-31 06:48:53102 }
[email protected]fb53e652014-04-30 11:27:19103 VLOG(1) << "Unpacked successfully";
Joshua Pawlicki6d764422018-02-21 15:23:10104 BeginPatching();
[email protected]f5d27e32014-01-31 06:48:53105}
106
[email protected]f5d27e32014-01-31 06:48:53107bool ComponentUnpacker::BeginPatching() {
108 if (is_delta_) { // Package is a diff package.
109 // Use a different temp directory for the patch output files.
110 if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
111 &unpack_path_)) {
sorin7b8650522016-11-02 18:23:41112 error_ = UnpackerError::kUnzipPathError;
[email protected]f5d27e32014-01-31 06:48:53113 return false;
114 }
Sorin Jianuebd652462017-07-23 02:00:58115 patcher_ = base::MakeRefCounted<ComponentPatcher>(
Joshua Pawlickid5409e12019-04-06 00:23:11116 unpack_diff_path_, unpack_path_, installer_, patcher_tool_);
Sorin Jianuebd652462017-07-23 02:00:58117 base::SequencedTaskRunnerHandle::Get()->PostTask(
[email protected]94a481b2014-03-28 19:41:55118 FROM_HERE,
Sorin Jianuebd652462017-07-23 02:00:58119 base::BindOnce(&ComponentPatcher::Start, patcher_,
Sorin Jianua8ef73d2017-11-02 16:55:17120 base::BindOnce(&ComponentUnpacker::EndPatching,
121 scoped_refptr<ComponentUnpacker>(this))));
[email protected]f5d27e32014-01-31 06:48:53122 } else {
Sorin Jianuebd652462017-07-23 02:00:58123 base::SequencedTaskRunnerHandle::Get()->PostTask(
124 FROM_HERE, base::BindOnce(&ComponentUnpacker::EndPatching,
125 scoped_refptr<ComponentUnpacker>(this),
126 UnpackerError::kNone, 0));
[email protected]f5d27e32014-01-31 06:48:53127 }
128 return true;
129}
130
sorin7b8650522016-11-02 18:23:41131void ComponentUnpacker::EndPatching(UnpackerError error, int extended_error) {
[email protected]f5d27e32014-01-31 06:48:53132 error_ = error;
133 extended_error_ = extended_error;
Ivan Kotenkov75b1c3a2017-10-24 14:47:24134 patcher_ = nullptr;
sorincbb7c092016-10-27 01:39:20135
136 EndUnpacking();
[email protected]f5d27e32014-01-31 06:48:53137}
138
sorincbb7c092016-10-27 01:39:20139void ComponentUnpacker::EndUnpacking() {
[email protected]f5d27e32014-01-31 06:48:53140 if (!unpack_diff_path_.empty())
Lei Zhang091d4232019-10-15 21:12:51141 base::DeleteFileRecursively(unpack_diff_path_);
sorin7b8650522016-11-02 18:23:41142 if (error_ != UnpackerError::kNone && !unpack_path_.empty())
Lei Zhang091d4232019-10-15 21:12:51143 base::DeleteFileRecursively(unpack_path_);
[email protected]f5d27e32014-01-31 06:48:53144
sorincbb7c092016-10-27 01:39:20145 Result result;
146 result.error = error_;
147 result.extended_error = extended_error_;
Minh X. Nguyenaafd7632017-10-19 21:12:35148 if (error_ == UnpackerError::kNone) {
sorincbb7c092016-10-27 01:39:20149 result.unpack_path = unpack_path_;
Minh X. Nguyenaafd7632017-10-19 21:12:35150 result.public_key = public_key_;
151 }
sorincbb7c092016-10-27 01:39:20152
Sorin Jianuebd652462017-07-23 02:00:58153 base::SequencedTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:17154 FROM_HERE, base::BindOnce(std::move(callback_), result));
[email protected]2e114e732011-07-22 02:55:04155}
[email protected]055981f2014-01-17 20:22:32156
sorin52ac0882015-01-24 01:15:00157} // namespace update_client