summaryrefslogtreecommitdiffstats
path: root/chromium/components/update_client/component_unpacker.h
blob: 312c96c9e0e7f42719ffb229e400a2537ea790ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_UPDATE_CLIENT_COMPONENT_UNPACKER_H_
#define COMPONENTS_UPDATE_CLIENT_COMPONENT_UNPACKER_H_

#include <stdint.h>

#include <memory>
#include <string>
#include <vector>

#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "components/update_client/update_client_errors.h"

// TODO(crbug.com/1349158): Remove this class once Puffin patches are fully
// implemented.

namespace crx_file {
enum class VerifierFormat;
}

namespace update_client {

class CrxInstaller;
class ComponentPatcher;
class Patcher;
class Unzipper;

// In charge of unpacking the component CRX package and verifying that it is
// well formed and the cryptographic signature is correct.
//
// This class should be used only by the component updater. It is inspired by
// and overlaps with code in the extension's SandboxedUnpacker.
// The main differences are:
// - The public key hash is full SHA256.
// - Does not use a sandboxed unpacker. A valid component is fully trusted.
// - The manifest can have different attributes and resources are not
//   transcoded.
//
// If the CRX is a delta CRX, the flow is:
//   [ComponentUpdater]      [ComponentPatcher]
//   Unpack
//     \_ Verify
//     \_ Unzip
//     \_ BeginPatching ---> DifferentialUpdatePatch
//                             ...
//   EndPatching <------------ ...
//     \_ EndUnpacking
//
// For a full CRX, the flow is:
//   [ComponentUpdater]
//   Unpack
//     \_ Verify
//     \_ Unzip
//     \_ BeginPatching
//          |
//          V
//   EndPatching
//     \_ EndUnpacking
//
// During unzip step we also check for verified_contents.json in the header
// of crx file and unpack it to metadata_ folder if it doesn't already contain
// verified_contents file.
// In both cases, if there is an error at any point, the remaining steps will
// be skipped and EndUnpacking will be called.
class ComponentUnpacker : public base::RefCountedThreadSafe<ComponentUnpacker> {
 public:
  // Contains the result of the unpacking.
  struct Result {
    Result();

    // Unpack error: 0 indicates success.
    UnpackerError error = UnpackerError::kNone;

    // Additional error information, such as errno or last error.
    int extended_error = 0;

    // Path of the unpacked files if the unpacking was successful.
    base::FilePath unpack_path;

    // The extracted public key of the package if the unpacking was successful.
    std::string public_key;
  };

  using Callback = base::OnceCallback<void(const Result& result)>;

  // Constructs an unpacker for a specific component unpacking operation.
  // |pk_hash| is the expected public developer key's SHA256 hash. If empty,
  // the unpacker accepts any developer key. |path| is the current location
  // of the CRX.
  ComponentUnpacker(const std::vector<uint8_t>& pk_hash,
                    const base::FilePath& path,
                    scoped_refptr<CrxInstaller> installer,
                    std::unique_ptr<Unzipper> unzipper,
                    scoped_refptr<Patcher> patcher,
                    crx_file::VerifierFormat crx_format);

  ComponentUnpacker(const ComponentUnpacker&) = delete;
  ComponentUnpacker& operator=(const ComponentUnpacker&) = delete;

  // Begins the actual unpacking of the files. May invoke a patcher and the
  // component installer if the package is a differential update.
  // Calls |callback| with the result.
  void Unpack(Callback callback);

 private:
  friend class base::RefCountedThreadSafe<ComponentUnpacker>;

  virtual ~ComponentUnpacker();

  // The first step of unpacking is to verify the file. Returns false if an
  // error is encountered, the file is malformed, or the file is incorrectly
  // signed.
  bool Verify();

  // The second step of unpacking is to unzip. Returns false if an early error
  // is encountered.
  bool BeginUnzipping();
  void EndUnzipping(bool error);

  // Decompresses verified contents fetched from the header of CRX.
  void UncompressVerifiedContents();

  // Stores the decompressed verified contents fetched from the header of CRX.
  void StoreVerifiedContentsInExtensionDir(
      const std::string& verified_contents);

  // The third step is to optionally patch files - this is a no-op for full
  // (non-differential) updates. This step is asynchronous.
  void BeginPatching();
  void EndPatching(UnpackerError error, int extended_error);

  // The final step is to do clean-up for things that can't be tidied as we go.
  // If there is an error at any step, the remaining steps are skipped and
  // EndUnpacking is called. EndUnpacking is responsible for calling the
  // callback provided in Unpack().
  void EndUnpacking();

  std::vector<uint8_t> pk_hash_;
  base::FilePath path_;
  base::FilePath unpack_path_;
  base::FilePath unpack_diff_path_;
  bool is_delta_;
  scoped_refptr<ComponentPatcher> patcher_;
  scoped_refptr<CrxInstaller> installer_;
  Callback callback_;
  std::unique_ptr<Unzipper> unzipper_;
  scoped_refptr<Patcher> patcher_tool_;
  crx_file::VerifierFormat crx_format_;
  UnpackerError error_;
  int extended_error_;
  std::string public_key_;

  // The compressed verified contents extracted from the CRX header.
  std::vector<uint8_t> compressed_verified_contents_;
};

}  // namespace update_client

#endif  // COMPONENTS_UPDATE_CLIENT_COMPONENT_UNPACKER_H_