1010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// found in the LICENSE file.
4010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
5010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#ifndef EXTENSIONS_BROWSER_CONTENT_VERIFY_JOB_H_
6010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#define EXTENSIONS_BROWSER_CONTENT_VERIFY_JOB_H_
7010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
8010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include <string>
9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/callback.h"
11010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/memory/ref_counted.h"
12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/threading/thread_checker.h"
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace base {
16010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class FilePath;
17010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
18010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace crypto {
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class SecureHash;
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace extensions {
24010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class ContentHashReader;
26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Objects of this class are responsible for verifying that the actual content
28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// read from an extension file matches an expected set of hashes. This class
29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// can be created on any thread but the rest of the methods should be called
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// from only one thread.
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class ContentVerifyJob : public base::RefCountedThreadSafe<ContentVerifyJob> {
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) public:
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  enum FailureReason {
34010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // No failure.
35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    NONE,
36010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Failed because there were no expected hashes at all (eg they haven't
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // been fetched yet).
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    MISSING_ALL_HASHES,
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Failed because this file wasn't found in the list of expected hashes.
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    NO_HASHES_FOR_FILE,
43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Some of the content read did not match the expected hash.
4534680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    HASH_MISMATCH,
4634680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
4734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    FAILURE_REASON_MAX
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  };
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  typedef base::Callback<void(FailureReason)> FailureCallback;
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The |failure_callback| will be called at most once if there was a failure.
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ContentVerifyJob(ContentHashReader* hash_reader,
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                   const FailureCallback& failure_callback);
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // This begins the process of getting expected hashes, so it should be called
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // as early as possible.
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void Start();
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Call this to add more bytes to verify. If at any point the read bytes
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // don't match the expected hashes, this will dispatch the failure
61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // callback. The failure callback will only be run once even if more bytes
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // are read. Make sure to call DoneReading so that any final bytes that were
63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // read that didn't align exactly on a block size boundary get their hash
64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // checked as well.
65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void BytesRead(int count, const char* data);
66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Call once when finished adding bytes via BytesRead.
68010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void DoneReading();
69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  class TestDelegate {
71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)   public:
72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // These methods will be called inside BytesRead/DoneReading respectively.
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // If either return something other than NONE, then the failure callback
74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // will be dispatched with that reason.
75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    virtual FailureReason BytesRead(const std::string& extension_id,
76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                    int count,
77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                    const char* data) = 0;
78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    virtual FailureReason DoneReading(const std::string& extension_id) = 0;
79010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  };
80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
811675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  class TestObserver {
821675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch   public:
831675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch    virtual void JobStarted(const std::string& extension_id,
841675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                            const base::FilePath& relative_path) = 0;
851675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch
861675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch    virtual void JobFinished(const std::string& extension_id,
871675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                             const base::FilePath& relative_path,
881675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch                             bool failed) = 0;
891675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  };
901675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  static void SetDelegateForTests(TestDelegate* delegate);
921675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  static void SetObserverForTests(TestObserver* observer);
93010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) private:
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ContentVerifyJob);
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual ~ContentVerifyJob();
98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  friend class base::RefCountedThreadSafe<ContentVerifyJob>;
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Called each time we're done adding bytes for the current block, and are
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // ready to finish the hash operation for those bytes and make sure it
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // matches what was expected for that block. Returns true if everything is
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // still ok so far, or false if a mismatch was detected.
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool FinishBlock();
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Dispatches the failure callback with the given reason.
107010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void DispatchFailureCallback(FailureReason reason);
108010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Called when our ContentHashReader has finished initializing.
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void OnHashesReady(bool success);
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Indicates whether the caller has told us they are done calling BytesRead.
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool done_reading_;
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Set to true once hash_reader_ has read its expected hashes.
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool hashes_ready_;
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // While we're waiting for the callback from the ContentHashReader, we need
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // to queue up bytes any bytes that are read.
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string queue_;
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // The total bytes we've read.
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int64 total_bytes_read_;
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // The index of the block we're currently on.
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int current_block_;
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // The hash we're building up for the bytes of |current_block_|.
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<crypto::SecureHash> current_hash_;
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // The number of bytes we've already input into |current_hash_|.
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int current_hash_byte_count_;
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_refptr<ContentHashReader> hash_reader_;
135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::TimeDelta time_spent_;
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Called once if verification fails.
139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  FailureCallback failure_callback_;
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Set to true if we detected a mismatch and called the failure callback.
142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool failed_;
143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // For ensuring methods on called on the right thread.
145010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::ThreadChecker thread_checker_;
146010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)};
147010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
148010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace extensions
149010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
150010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#endif  // EXTENSIONS_BROWSER_CONTENT_VERIFY_JOB_H_
151