OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/activity_log/ad_network_database.h" | 5 #include "chrome/browser/extensions/activity_log/ad_network_database.h" |
6 | 6 |
7 #include "base/basictypes.h" | |
7 #include "base/lazy_instance.h" | 8 #include "base/lazy_instance.h" |
9 #include "base/memory/ref_counted_memory.h" | |
10 #include "crypto/secure_hash.h" | |
11 #include "crypto/sha2.h" | |
12 #include "grit/browser_resources.h" | |
13 #include "ui/base/resource/resource_bundle.h" | |
14 #include "url/gurl.h" | |
8 | 15 |
9 namespace extensions { | 16 namespace extensions { |
10 | 17 |
11 namespace { | 18 namespace { |
12 | 19 |
20 // We use a hash size of 8 for these for three reasons. | |
21 // 1. It saves us a bit on space, and, since we have to store these in memory | |
22 // (reading from disk would be far too slow because these checks are | |
23 // performed synchronously), that space is important. | |
24 // 2. Since we don't store full hashes, reconstructing the list is more | |
25 // difficult. This may mean we get a few incorrect hits, but the security is | |
26 // worth the (very small) amount of noise. | |
27 // 3. It fits nicely into a int64. | |
28 const size_t kUrlHashSize = 8u; | |
29 COMPILE_ASSERT(kUrlHashSize <= sizeof(int64), url_hashes_must_fit_into_a_int64); | |
30 | |
31 const size_t kChecksumHashSize = 32u; | |
32 | |
33 class AdNetworkDatabaseImpl : public AdNetworkDatabase { | |
34 public: | |
35 AdNetworkDatabaseImpl(); | |
36 virtual ~AdNetworkDatabaseImpl(); | |
37 | |
38 private: | |
39 // AdNetworkDatabase implementation. | |
40 virtual bool IsEnabled() const OVERRIDE { return enabled_; } | |
41 virtual bool IsAdNetwork(const GURL& url) const OVERRIDE; | |
42 | |
43 // Initialize the AdNetworkDatabase. This means initializing the set of | |
44 // hashes from the shared memory. If this succeeds, |enabled_| will be set | |
45 // to true. | |
46 void Init(); | |
47 | |
48 // The set of partial hashes for known ad networks. | |
49 base::hash_set<int64> entries_; | |
50 | |
51 // Whether or not the database is enabled. The database will not be enabled | |
52 // if Init() does not succeed in loading the hashes. | |
53 bool enabled_; | |
54 }; | |
55 | |
56 AdNetworkDatabaseImpl::AdNetworkDatabaseImpl() : enabled_(false) { | |
57 Init(); | |
58 } | |
59 | |
60 AdNetworkDatabaseImpl::~AdNetworkDatabaseImpl() {} | |
61 | |
62 void AdNetworkDatabaseImpl::Init() { | |
63 base::RefCountedStaticMemory* entries_memory = | |
64 ResourceBundle::GetSharedInstance().LoadDataResourceBytes( | |
65 IDR_AD_NETWORK_HASHES); | |
66 | |
67 const size_t size = entries_memory->size(); | |
68 const unsigned char* const front = entries_memory->front(); | |
69 if (size < kChecksumHashSize || | |
70 (size - kChecksumHashSize) % kUrlHashSize != 0) { | |
felt
2014/04/23 03:01:36
should this be a DCHECK?
Devlin
2014/04/23 18:16:55
Hmm... good question. If it were a normal file, t
| |
71 return; | |
72 } | |
73 | |
74 // The format of the data resource is fairly straight-forward: | |
75 // <32-bit checksum><list of 64-bit hashes of hosts>, with no linebreaks or | |
76 // other separations. | |
felt
2014/04/23 03:01:36
how are the list entries (the hashes) separated?
Devlin
2014/04/23 18:16:55
There's no deliminator between them, because they
felt
2014/04/23 20:15:22
ah right
| |
77 scoped_ptr<crypto::SecureHash> hash( | |
78 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); | |
79 | |
80 hash->Update(front + kChecksumHashSize, size - kChecksumHashSize); | |
81 char hash_value[kChecksumHashSize]; | |
82 hash->Finish(hash_value, kChecksumHashSize); | |
83 // If the checksum doesn't match, abort. | |
felt
2014/04/23 03:01:36
should this also be a DCHECK?
Devlin
2014/04/23 18:16:55
Done.
| |
84 if (memcmp(hash_value, front, kChecksumHashSize) != 0) | |
85 return; | |
86 | |
87 // Construct and insert all hashes. | |
88 for (const unsigned char* index = front + kChecksumHashSize; | |
89 index < front + size; | |
90 index += kUrlHashSize) { | |
91 int64 value = 0; | |
92 memcpy(&value, index, kUrlHashSize); | |
93 entries_.insert(value); | |
94 } | |
95 | |
96 enabled_ = true; | |
97 } | |
98 | |
99 bool AdNetworkDatabaseImpl::IsAdNetwork(const GURL& url) const { | |
100 int64 hash = 0; | |
101 crypto::SHA256HashString(url.host(), &hash, sizeof(hash)); | |
102 return entries_.count(hash) != 0; | |
103 } | |
104 | |
13 class AdNetworkDatabaseFactory { | 105 class AdNetworkDatabaseFactory { |
14 public: | 106 public: |
15 AdNetworkDatabaseFactory(); | 107 AdNetworkDatabaseFactory(); |
16 ~AdNetworkDatabaseFactory(); | 108 ~AdNetworkDatabaseFactory(); |
17 | 109 |
110 const AdNetworkDatabase* GetDatabase(); | |
18 void SetDatabase(scoped_ptr<AdNetworkDatabase> database); | 111 void SetDatabase(scoped_ptr<AdNetworkDatabase> database); |
19 | 112 |
20 const AdNetworkDatabase* database() const { return database_.get(); } | |
21 | |
22 private: | 113 private: |
23 scoped_ptr<AdNetworkDatabase> database_; | 114 scoped_ptr<AdNetworkDatabase> database_; |
24 }; | 115 }; |
25 | 116 |
26 AdNetworkDatabaseFactory::AdNetworkDatabaseFactory() {} | 117 AdNetworkDatabaseFactory::AdNetworkDatabaseFactory() {} |
27 AdNetworkDatabaseFactory::~AdNetworkDatabaseFactory() {} | 118 AdNetworkDatabaseFactory::~AdNetworkDatabaseFactory() {} |
28 | 119 |
120 const AdNetworkDatabase* AdNetworkDatabaseFactory::GetDatabase() { | |
121 // Construct a new database, if we don't have one. | |
122 if (!database_.get()) | |
123 database_.reset(new AdNetworkDatabaseImpl()); | |
124 | |
125 if (database_->IsEnabled()) | |
126 return database_.get(); | |
127 | |
128 return NULL; | |
129 } | |
130 | |
29 void AdNetworkDatabaseFactory::SetDatabase( | 131 void AdNetworkDatabaseFactory::SetDatabase( |
30 scoped_ptr<AdNetworkDatabase> database) { | 132 scoped_ptr<AdNetworkDatabase> database) { |
31 database_.reset(database.release()); | 133 database_.reset(database.release()); |
32 } | 134 } |
33 | 135 |
34 base::LazyInstance<AdNetworkDatabaseFactory> g_factory = | 136 base::LazyInstance<AdNetworkDatabaseFactory> g_factory = |
35 LAZY_INSTANCE_INITIALIZER; | 137 LAZY_INSTANCE_INITIALIZER; |
36 | 138 |
37 } // namespace | 139 } // namespace |
38 | 140 |
39 AdNetworkDatabase::~AdNetworkDatabase() {} | 141 AdNetworkDatabase::~AdNetworkDatabase() {} |
40 | 142 |
41 // static | 143 // static |
42 const AdNetworkDatabase* AdNetworkDatabase::Get() { | 144 const AdNetworkDatabase* AdNetworkDatabase::Get() { |
43 return g_factory.Get().database(); | 145 return g_factory.Get().GetDatabase(); |
44 } | 146 } |
45 | 147 |
46 // static | 148 // static |
47 void AdNetworkDatabase::SetForTesting(scoped_ptr<AdNetworkDatabase> database) { | 149 void AdNetworkDatabase::SetForTesting(scoped_ptr<AdNetworkDatabase> database) { |
48 g_factory.Get().SetDatabase(database.Pass()); | 150 g_factory.Get().SetDatabase(database.Pass()); |
49 } | 151 } |
50 | 152 |
51 } // namespace extensions | 153 } // namespace extensions |
OLD | NEW |