Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "components/safe_browsing_db/v4_get_hash_protocol_manager.h" | 5 #include "components/safe_browsing_db/v4_get_hash_protocol_manager.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/base64.h" | 10 #include "base/base64.h" |
| 11 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
| 12 #include "base/run_loop.h" | |
| 12 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
| 13 #include "base/test/simple_test_clock.h" | 14 #include "base/test/simple_test_clock.h" |
| 14 #include "base/time/time.h" | 15 #include "base/time/time.h" |
| 15 #include "components/safe_browsing_db/safebrowsing.pb.h" | 16 #include "components/safe_browsing_db/safebrowsing.pb.h" |
| 16 #include "components/safe_browsing_db/testing_util.h" | 17 #include "components/safe_browsing_db/testing_util.h" |
| 17 #include "components/safe_browsing_db/util.h" | 18 #include "components/safe_browsing_db/util.h" |
| 18 #include "net/base/escape.h" | 19 #include "net/base/escape.h" |
| 19 #include "net/base/load_flags.h" | 20 #include "net/base/load_flags.h" |
| 20 #include "net/base/net_errors.h" | 21 #include "net/base/net_errors.h" |
| 21 #include "net/url_request/test_url_fetcher_factory.h" | 22 #include "net/url_request/test_url_fetcher_factory.h" |
| 22 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/platform_test.h" |
| 23 | 24 |
| 24 using base::Time; | 25 using base::Time; |
| 25 using base::TimeDelta; | 26 using base::TimeDelta; |
| 26 | 27 |
| 27 namespace { | 28 namespace { |
| 28 | 29 |
| 29 const char kClient[] = "unittest"; | 30 const char kClient[] = "unittest"; |
| 30 const char kAppVer[] = "1.0"; | 31 const char kAppVer[] = "1.0"; |
| 31 const char kKeyParam[] = "test_key_param"; | 32 const char kKeyParam[] = "test_key_param"; |
| 32 | 33 |
| 33 } // namespace | 34 } // namespace |
| 34 | 35 |
| 35 namespace safe_browsing { | 36 namespace safe_browsing { |
| 36 | 37 |
| 37 class SafeBrowsingV4GetHashProtocolManagerTest : public testing::Test { | 38 namespace { |
| 38 protected: | 39 |
| 40 struct KeyValue { | |
| 41 std::string key; | |
| 42 std::string value; | |
| 43 | |
| 44 explicit KeyValue(const std::string key, const std::string value) | |
| 45 : key(key), value(value){}; | |
| 46 explicit KeyValue(const KeyValue& other) = default; | |
| 47 | |
| 48 private: | |
| 49 KeyValue(); | |
| 50 }; | |
| 51 | |
| 52 struct ResponseInfo { | |
| 53 FullHash full_hash; | |
| 54 UpdateListIdentifier list_id; | |
| 55 std::vector<KeyValue> key_values; | |
| 56 | |
| 57 explicit ResponseInfo(FullHash full_hash, UpdateListIdentifier list_id) | |
| 58 : full_hash(full_hash), list_id(list_id){}; | |
| 59 explicit ResponseInfo(const ResponseInfo& other) | |
| 60 : full_hash(other.full_hash), | |
| 61 list_id(other.list_id), | |
| 62 key_values(other.key_values){}; | |
| 63 | |
| 64 private: | |
| 65 ResponseInfo(); | |
| 66 }; | |
| 67 | |
| 68 } // namespace | |
| 69 | |
| 70 class V4GetHashProtocolManagerTest : public PlatformTest { | |
| 71 public: | |
| 72 void SetUp() override { | |
| 73 PlatformTest::SetUp(); | |
| 74 callback_called_ = false; | |
| 75 } | |
| 76 | |
| 39 std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager() { | 77 std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager() { |
| 40 V4ProtocolConfig config; | 78 V4ProtocolConfig config; |
| 41 config.client_name = kClient; | 79 config.client_name = kClient; |
| 42 config.version = kAppVer; | 80 config.version = kAppVer; |
| 43 config.key_param = kKeyParam; | 81 config.key_param = kKeyParam; |
| 44 return std::unique_ptr<V4GetHashProtocolManager>( | 82 base::hash_set<UpdateListIdentifier> stores_to_look( |
| 45 V4GetHashProtocolManager::Create(NULL, config)); | 83 {GetUrlMalwareId(), GetChromeUrlApiId()}); |
| 84 return V4GetHashProtocolManager::Create(NULL, stores_to_look, config); | |
| 46 } | 85 } |
| 47 | 86 |
| 48 std::string GetStockV4HashResponse() { | 87 static void SetupFetcherToReturnOKResponse( |
| 49 FindFullHashesResponse res; | 88 const net::TestURLFetcherFactory& factory, |
| 50 res.mutable_negative_cache_duration()->set_seconds(600); | 89 const std::vector<ResponseInfo>& infos) { |
| 51 ThreatMatch* m = res.add_matches(); | 90 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); |
| 52 m->set_threat_type(API_ABUSE); | 91 DCHECK(fetcher); |
| 53 m->set_platform_type(CHROME_PLATFORM); | 92 fetcher->set_status(net::URLRequestStatus()); |
| 54 m->set_threat_entry_type(URL); | 93 fetcher->set_response_code(200); |
| 55 m->mutable_cache_duration()->set_seconds(300); | 94 fetcher->SetResponseString(GetV4HashResponse(infos)); |
| 56 m->mutable_threat()->set_hash( | 95 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 57 SBFullHashToString(SBFullHashForString("Everything's shiny, Cap'n."))); | 96 } |
| 58 ThreatEntryMetadata::MetadataEntry* e = | |
| 59 m->mutable_threat_entry_metadata()->add_entries(); | |
| 60 e->set_key("permission"); | |
| 61 e->set_value("NOTIFICATIONS"); | |
| 62 | 97 |
| 63 // Serialize. | 98 static std::vector<ResponseInfo> GetStockV4HashResponseInfos() { |
| 64 std::string res_data; | 99 ResponseInfo info(FullHash("Everything's shiny, Cap'n."), |
| 65 res.SerializeToString(&res_data); | 100 GetChromeUrlApiId()); |
| 101 info.key_values.emplace_back("permission", "NOTIFICATIONS"); | |
| 102 std::vector<ResponseInfo> infos; | |
| 103 infos.push_back(info); | |
| 104 return infos; | |
| 105 } | |
| 66 | 106 |
| 67 return res_data; | 107 static std::string GetStockV4HashResponse() { |
| 108 return GetV4HashResponse(GetStockV4HashResponseInfos()); | |
| 68 } | 109 } |
| 69 | 110 |
| 70 void SetTestClock(base::Time now, V4GetHashProtocolManager* pm) { | 111 void SetTestClock(base::Time now, V4GetHashProtocolManager* pm) { |
| 71 base::SimpleTestClock* clock = new base::SimpleTestClock(); | 112 base::SimpleTestClock* clock = new base::SimpleTestClock(); |
| 72 clock->SetNow(now); | 113 clock->SetNow(now); |
| 73 pm->SetClockForTests(base::WrapUnique(clock)); | 114 pm->SetClockForTests(base::WrapUnique(clock)); |
| 74 } | 115 } |
| 116 | |
| 117 void ValidateGetV4ApiResults(const ThreatMetadata& expected_md, | |
| 118 const ThreatMetadata& actual_md) { | |
| 119 EXPECT_EQ(expected_md, actual_md); | |
| 120 callback_called_ = true; | |
| 121 } | |
| 122 | |
| 123 void ValidateGetV4HashResults( | |
| 124 const std::vector<FullHashInfo>& expected_results, | |
| 125 const std::vector<FullHashInfo>& actual_results) { | |
| 126 EXPECT_EQ(expected_results.size(), actual_results.size()); | |
| 127 for (size_t i = 0; i < actual_results.size(); i++) { | |
| 128 EXPECT_TRUE(expected_results[i] == actual_results[i]); | |
| 129 } | |
| 130 callback_called_ = true; | |
| 131 } | |
| 132 | |
| 133 bool callback_called() { return callback_called_; } | |
| 134 | |
| 135 private: | |
| 136 static std::string GetV4HashResponse( | |
| 137 std::vector<ResponseInfo> response_infos) { | |
| 138 FindFullHashesResponse res; | |
| 139 res.mutable_negative_cache_duration()->set_seconds(600); | |
| 140 for (const ResponseInfo& info : response_infos) { | |
| 141 ThreatMatch* m = res.add_matches(); | |
| 142 m->set_platform_type(info.list_id.platform_type); | |
| 143 m->set_threat_entry_type(info.list_id.threat_entry_type); | |
| 144 m->set_threat_type(info.list_id.threat_type); | |
| 145 m->mutable_cache_duration()->set_seconds(300); | |
| 146 m->mutable_threat()->set_hash(info.full_hash); | |
| 147 | |
| 148 for (const KeyValue& key_value : info.key_values) { | |
| 149 ThreatEntryMetadata::MetadataEntry* e = | |
| 150 m->mutable_threat_entry_metadata()->add_entries(); | |
| 151 e->set_key(key_value.key); | |
| 152 e->set_value(key_value.value); | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 // Serialize. | |
| 157 std::string res_data; | |
| 158 res.SerializeToString(&res_data); | |
| 159 | |
| 160 return res_data; | |
| 161 } | |
| 162 | |
| 163 bool callback_called_; | |
| 75 }; | 164 }; |
| 76 | 165 |
| 77 void ValidateGetV4HashResults( | 166 TEST_F(V4GetHashProtocolManagerTest, TestGetHashErrorHandlingNetwork) { |
| 78 const std::vector<SBFullHashResult>& expected_full_hashes, | |
| 79 const base::Time& expected_cache_expire, | |
| 80 const std::vector<SBFullHashResult>& full_hashes, | |
| 81 const base::Time& cache_expire) { | |
| 82 EXPECT_EQ(expected_cache_expire, cache_expire); | |
| 83 ASSERT_EQ(expected_full_hashes.size(), full_hashes.size()); | |
| 84 | |
| 85 for (unsigned int i = 0; i < expected_full_hashes.size(); ++i) { | |
| 86 const SBFullHashResult& expected = expected_full_hashes[i]; | |
| 87 const SBFullHashResult& actual = full_hashes[i]; | |
| 88 EXPECT_TRUE(SBFullHashEqual(expected.hash, actual.hash)); | |
| 89 EXPECT_EQ(expected.metadata, actual.metadata); | |
| 90 EXPECT_EQ(expected.cache_expire_after, actual.cache_expire_after); | |
| 91 } | |
| 92 } | |
| 93 | |
| 94 TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, | |
| 95 TestGetHashErrorHandlingNetwork) { | |
| 96 net::TestURLFetcherFactory factory; | 167 net::TestURLFetcherFactory factory; |
| 97 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | 168 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
| 98 | 169 |
| 99 std::vector<SBPrefix> prefixes; | 170 FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes; |
|
Nathan Parker
2016/09/09 21:26:22
nit: This is a long type name and a long var name.
vakh (use Gerrit instead)
2016/09/09 23:25:18
If you don't mind it too much, I actually prefer t
| |
| 100 std::vector<SBFullHashResult> expected_full_hashes; | 171 full_hash_to_store_and_hash_prefixes[FullHash("AFullHash")].push_back( |
| 101 base::Time expected_cache_expire; | 172 StoreAndHashPrefix(GetUrlSocEngId(), HashPrefix("AHashPrefix"))); |
|
Nathan Parker
2016/09/09 21:26:22
Is it ok to have the prefix not match the full has
vakh (use Gerrit instead)
2016/09/09 23:25:18
In general not. But in this case it is irrelevant
| |
| 102 | 173 std::vector<FullHashInfo> expected_results; |
| 103 pm->GetFullHashesWithApis( | 174 pm->GetFullHashes( |
| 104 prefixes, base::Bind(&ValidateGetV4HashResults, expected_full_hashes, | 175 full_hash_to_store_and_hash_prefixes, |
| 105 expected_cache_expire)); | 176 base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults, |
| 177 base::Unretained(this), expected_results)); | |
| 106 | 178 |
| 107 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); | 179 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); |
| 108 DCHECK(fetcher); | 180 DCHECK(fetcher); |
| 109 // Failed request status should result in error. | 181 // Failed request status should result in error. |
| 110 fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 182 fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
| 111 net::ERR_CONNECTION_RESET)); | 183 net::ERR_CONNECTION_RESET)); |
| 112 fetcher->set_response_code(200); | 184 fetcher->set_response_code(200); |
| 113 fetcher->SetResponseString(GetStockV4HashResponse()); | 185 fetcher->SetResponseString(GetStockV4HashResponse()); |
| 114 fetcher->delegate()->OnURLFetchComplete(fetcher); | 186 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 115 | 187 |
| 116 // Should have recorded one error, but back off multiplier is unchanged. | 188 // Should have recorded one error, but back off multiplier is unchanged. |
| 117 EXPECT_EQ(1ul, pm->gethash_error_count_); | 189 EXPECT_EQ(1ul, pm->gethash_error_count_); |
| 118 EXPECT_EQ(1ul, pm->gethash_back_off_mult_); | 190 EXPECT_EQ(1ul, pm->gethash_back_off_mult_); |
| 191 EXPECT_TRUE(callback_called()); | |
| 119 } | 192 } |
| 120 | 193 |
| 121 TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, | 194 TEST_F(V4GetHashProtocolManagerTest, TestGetHashErrorHandlingResponseCode) { |
| 122 TestGetHashErrorHandlingResponseCode) { | |
| 123 net::TestURLFetcherFactory factory; | 195 net::TestURLFetcherFactory factory; |
| 124 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | 196 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
| 125 | 197 |
| 126 std::vector<SBPrefix> prefixes; | 198 FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes; |
| 127 std::vector<SBFullHashResult> expected_full_hashes; | 199 full_hash_to_store_and_hash_prefixes[FullHash("AFullHash")].push_back( |
| 128 base::Time expected_cache_expire; | 200 StoreAndHashPrefix(GetUrlSocEngId(), HashPrefix("AHashPrefix"))); |
| 129 | 201 std::vector<FullHashInfo> expected_results; |
| 130 pm->GetFullHashesWithApis( | 202 pm->GetFullHashes( |
| 131 prefixes, base::Bind(&ValidateGetV4HashResults, expected_full_hashes, | 203 full_hash_to_store_and_hash_prefixes, |
| 132 expected_cache_expire)); | 204 base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults, |
| 205 base::Unretained(this), expected_results)); | |
| 133 | 206 |
| 134 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); | 207 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); |
| 135 DCHECK(fetcher); | 208 DCHECK(fetcher); |
| 136 fetcher->set_status(net::URLRequestStatus()); | 209 fetcher->set_status(net::URLRequestStatus()); |
| 137 // Response code of anything other than 200 should result in error. | 210 // Response code of anything other than 200 should result in error. |
| 138 fetcher->set_response_code(204); | 211 fetcher->set_response_code(204); |
| 139 fetcher->SetResponseString(GetStockV4HashResponse()); | 212 fetcher->SetResponseString(GetStockV4HashResponse()); |
| 140 fetcher->delegate()->OnURLFetchComplete(fetcher); | 213 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 141 | 214 |
| 142 // Should have recorded one error, but back off multiplier is unchanged. | 215 // Should have recorded one error, but back off multiplier is unchanged. |
| 143 EXPECT_EQ(1ul, pm->gethash_error_count_); | 216 EXPECT_EQ(1ul, pm->gethash_error_count_); |
| 144 EXPECT_EQ(1ul, pm->gethash_back_off_mult_); | 217 EXPECT_EQ(1ul, pm->gethash_back_off_mult_); |
| 218 EXPECT_TRUE(callback_called()); | |
| 145 } | 219 } |
| 146 | 220 |
| 147 TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashErrorHandlingOK) { | 221 TEST_F(V4GetHashProtocolManagerTest, TestGetHashErrorHandlingOK) { |
| 148 net::TestURLFetcherFactory factory; | 222 net::TestURLFetcherFactory factory; |
| 149 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | 223 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
| 150 | 224 |
| 151 base::Time now = base::Time::UnixEpoch(); | 225 base::Time now = base::Time::UnixEpoch(); |
| 152 SetTestClock(now, pm.get()); | 226 SetTestClock(now, pm.get()); |
| 153 | 227 |
| 154 std::vector<SBPrefix> prefixes; | 228 HashPrefix prefix("Everything"); |
| 155 std::vector<SBFullHashResult> expected_full_hashes; | 229 FullHash full_hash("Everything's shiny, Cap'n."); |
| 156 SBFullHashResult hash_result; | 230 FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes; |
| 157 hash_result.hash = SBFullHashForString("Everything's shiny, Cap'n."); | 231 full_hash_to_store_and_hash_prefixes[full_hash].push_back( |
| 158 hash_result.metadata.api_permissions.insert("NOTIFICATIONS"); | 232 StoreAndHashPrefix(GetChromeUrlApiId(), prefix)); |
| 159 hash_result.cache_expire_after = now + base::TimeDelta::FromSeconds(300); | 233 std::vector<FullHashInfo> expected_results; |
| 160 expected_full_hashes.push_back(hash_result); | 234 FullHashInfo fhi(full_hash, GetChromeUrlApiId(), |
| 161 base::Time expected_cache_expire = now + base::TimeDelta::FromSeconds(600); | 235 now + base::TimeDelta::FromSeconds(300)); |
| 236 fhi.metadata.api_permissions.insert("NOTIFICATIONS"); | |
| 237 expected_results.push_back(fhi); | |
| 162 | 238 |
| 163 pm->GetFullHashesWithApis( | 239 pm->GetFullHashes( |
| 164 prefixes, base::Bind(&ValidateGetV4HashResults, expected_full_hashes, | 240 full_hash_to_store_and_hash_prefixes, |
| 165 expected_cache_expire)); | 241 base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults, |
| 242 base::Unretained(this), expected_results)); | |
| 166 | 243 |
| 167 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); | 244 SetupFetcherToReturnOKResponse(factory, GetStockV4HashResponseInfos()); |
| 168 DCHECK(fetcher); | |
| 169 fetcher->set_status(net::URLRequestStatus()); | |
| 170 fetcher->set_response_code(200); | |
| 171 fetcher->SetResponseString(GetStockV4HashResponse()); | |
| 172 fetcher->delegate()->OnURLFetchComplete(fetcher); | |
| 173 | 245 |
| 174 // No error, back off multiplier is unchanged. | 246 // No error, back off multiplier is unchanged. |
| 175 EXPECT_EQ(0ul, pm->gethash_error_count_); | 247 EXPECT_EQ(0ul, pm->gethash_error_count_); |
| 176 EXPECT_EQ(1ul, pm->gethash_back_off_mult_); | 248 EXPECT_EQ(1ul, pm->gethash_back_off_mult_); |
| 249 | |
| 250 // Verify the state of the cache. | |
| 251 const FullHashCache* cache = pm->full_hash_cache_for_tests(); | |
| 252 // Check the cache. | |
| 253 ASSERT_EQ(1u, cache->size()); | |
| 254 EXPECT_EQ(1u, cache->count(prefix)); | |
| 255 const CachedHashPrefixInfo& cached_result = cache->at(prefix); | |
| 256 EXPECT_EQ(cached_result.negative_ttl, | |
| 257 now + base::TimeDelta::FromSeconds(600)); | |
| 258 ASSERT_EQ(1u, cached_result.full_hash_infos.size()); | |
| 259 EXPECT_EQ(FullHash("Everything's shiny, Cap'n."), | |
| 260 cached_result.full_hash_infos[0].full_hash); | |
| 261 EXPECT_TRUE(callback_called()); | |
| 177 } | 262 } |
| 178 | 263 |
| 179 TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashRequest) { | 264 TEST_F(V4GetHashProtocolManagerTest, |
| 265 TestResultsNotCachedForNegativeCacheDuration) { | |
| 266 net::TestURLFetcherFactory factory; | |
| 180 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | 267 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
| 181 | 268 |
| 269 HashPrefix prefix("Everything"); | |
| 270 std::vector<HashPrefix> prefixes_requested({prefix}); | |
| 271 base::Time negative_cache_expire; | |
| 272 FullHash full_hash("Everything's shiny, Cap'n."); | |
| 273 std::vector<FullHashInfo> fhis; | |
| 274 fhis.emplace_back(full_hash, GetChromeUrlApiId(), base::Time::UnixEpoch()); | |
| 275 | |
| 276 pm->UpdateCache(prefixes_requested, fhis, negative_cache_expire); | |
| 277 | |
| 278 // Verify the state of the cache. | |
| 279 const FullHashCache* cache = pm->full_hash_cache_for_tests(); | |
| 280 // Check the cache. | |
| 281 EXPECT_EQ(0u, cache->size()); | |
| 282 } | |
| 283 | |
| 284 TEST_F(V4GetHashProtocolManagerTest, TestGetHashRequest) { | |
| 285 HashPrefix one = "hashone"; | |
| 286 HashPrefix two = "hashtwo"; | |
| 287 std::vector<HashPrefix> prefixes_to_request = {one, two}; | |
| 288 | |
| 182 FindFullHashesRequest req; | 289 FindFullHashesRequest req; |
| 183 ThreatInfo* info = req.mutable_threat_info(); | 290 ThreatInfo* info = req.mutable_threat_info(); |
| 291 info->add_threat_types(MALWARE_THREAT); | |
| 184 info->add_threat_types(API_ABUSE); | 292 info->add_threat_types(API_ABUSE); |
| 293 | |
| 294 info->add_platform_types(GetCurrentPlatformType()); | |
| 185 info->add_platform_types(CHROME_PLATFORM); | 295 info->add_platform_types(CHROME_PLATFORM); |
| 296 | |
| 186 info->add_threat_entry_types(URL); | 297 info->add_threat_entry_types(URL); |
| 187 | 298 |
| 188 SBPrefix one = 1u; | 299 info->add_threat_entries()->set_hash(one); |
| 189 SBPrefix two = 2u; | 300 info->add_threat_entries()->set_hash(two); |
| 190 SBPrefix three = 3u; | |
| 191 std::string hash(reinterpret_cast<const char*>(&one), sizeof(SBPrefix)); | |
| 192 info->add_threat_entries()->set_hash(hash); | |
| 193 hash.clear(); | |
| 194 hash.append(reinterpret_cast<const char*>(&two), sizeof(SBPrefix)); | |
| 195 info->add_threat_entries()->set_hash(hash); | |
| 196 hash.clear(); | |
| 197 hash.append(reinterpret_cast<const char*>(&three), sizeof(SBPrefix)); | |
| 198 info->add_threat_entries()->set_hash(hash); | |
| 199 | 301 |
| 200 // Serialize and Base64 encode. | 302 // Serialize and Base64 encode. |
| 201 std::string req_data, req_base64; | 303 std::string req_data, req_base64; |
| 202 req.SerializeToString(&req_data); | 304 req.SerializeToString(&req_data); |
| 203 base::Base64Encode(req_data, &req_base64); | 305 base::Base64Encode(req_data, &req_base64); |
| 204 | 306 |
| 205 std::vector<PlatformType> platform; | 307 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
| 206 platform.push_back(CHROME_PLATFORM); | 308 EXPECT_EQ(req_base64, pm->GetHashRequest(prefixes_to_request)); |
| 207 std::vector<SBPrefix> prefixes; | |
| 208 prefixes.push_back(one); | |
| 209 prefixes.push_back(two); | |
| 210 prefixes.push_back(three); | |
| 211 EXPECT_EQ(req_base64, pm->GetHashRequest(prefixes, platform, API_ABUSE)); | |
| 212 } | 309 } |
| 213 | 310 |
| 214 TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponse) { | 311 TEST_F(V4GetHashProtocolManagerTest, TestParseHashResponse) { |
| 215 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | 312 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
| 216 | 313 |
| 217 base::Time now = base::Time::UnixEpoch(); | 314 base::Time now = base::Time::UnixEpoch(); |
| 218 SetTestClock(now, pm.get()); | 315 SetTestClock(now, pm.get()); |
| 219 | 316 |
| 317 FullHash full_hash("Everything's shiny, Cap'n."); | |
| 220 FindFullHashesResponse res; | 318 FindFullHashesResponse res; |
| 221 res.mutable_negative_cache_duration()->set_seconds(600); | 319 res.mutable_negative_cache_duration()->set_seconds(600); |
| 222 res.mutable_minimum_wait_duration()->set_seconds(400); | 320 res.mutable_minimum_wait_duration()->set_seconds(400); |
| 223 ThreatMatch* m = res.add_matches(); | 321 ThreatMatch* m = res.add_matches(); |
| 224 m->set_threat_type(API_ABUSE); | 322 m->set_threat_type(API_ABUSE); |
| 225 m->set_platform_type(CHROME_PLATFORM); | 323 m->set_platform_type(CHROME_PLATFORM); |
| 226 m->set_threat_entry_type(URL); | 324 m->set_threat_entry_type(URL); |
| 227 m->mutable_cache_duration()->set_seconds(300); | 325 m->mutable_cache_duration()->set_seconds(300); |
| 228 m->mutable_threat()->set_hash( | 326 m->mutable_threat()->set_hash(full_hash); |
| 229 SBFullHashToString(SBFullHashForString("Everything's shiny, Cap'n."))); | |
| 230 ThreatEntryMetadata::MetadataEntry* e = | 327 ThreatEntryMetadata::MetadataEntry* e = |
| 231 m->mutable_threat_entry_metadata()->add_entries(); | 328 m->mutable_threat_entry_metadata()->add_entries(); |
| 232 e->set_key("permission"); | 329 e->set_key("permission"); |
| 233 e->set_value("NOTIFICATIONS"); | 330 e->set_value("NOTIFICATIONS"); |
| 234 | 331 |
| 235 // Serialize. | 332 // Serialize. |
| 236 std::string res_data; | 333 std::string res_data; |
| 237 res.SerializeToString(&res_data); | 334 res.SerializeToString(&res_data); |
| 238 | 335 |
| 239 std::vector<SBFullHashResult> full_hashes; | 336 std::vector<FullHashInfo> full_hash_infos; |
| 240 base::Time cache_expire; | 337 base::Time cache_expire; |
| 241 EXPECT_TRUE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire)); | 338 EXPECT_TRUE(pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire)); |
| 242 | 339 |
| 243 EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire); | 340 EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire); |
| 244 EXPECT_EQ(1ul, full_hashes.size()); | 341 ASSERT_EQ(1ul, full_hash_infos.size()); |
| 245 EXPECT_TRUE(SBFullHashEqual(SBFullHashForString("Everything's shiny, Cap'n."), | 342 const FullHashInfo& fhi = full_hash_infos[0]; |
| 246 full_hashes[0].hash)); | 343 EXPECT_EQ(full_hash, fhi.full_hash); |
| 247 EXPECT_EQ(1ul, full_hashes[0].metadata.api_permissions.size()); | 344 EXPECT_EQ(GetChromeUrlApiId(), fhi.list_id); |
| 248 EXPECT_EQ(1ul, | 345 EXPECT_EQ(1ul, fhi.metadata.api_permissions.size()); |
| 249 full_hashes[0].metadata.api_permissions.count("NOTIFICATIONS")); | 346 EXPECT_EQ(1ul, fhi.metadata.api_permissions.count("NOTIFICATIONS")); |
| 250 EXPECT_EQ(now + | 347 EXPECT_EQ(now + base::TimeDelta::FromSeconds(300), fhi.positive_ttl); |
| 251 base::TimeDelta::FromSeconds(300), full_hashes[0].cache_expire_after); | |
| 252 EXPECT_EQ(now + base::TimeDelta::FromSeconds(400), pm->next_gethash_time_); | 348 EXPECT_EQ(now + base::TimeDelta::FromSeconds(400), pm->next_gethash_time_); |
| 253 } | 349 } |
| 254 | 350 |
| 255 // Adds an entry with an ignored ThreatEntryType. | 351 // Adds an entry with an ignored ThreatEntryType. |
| 256 TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, | 352 TEST_F(V4GetHashProtocolManagerTest, |
| 257 TestParseHashResponseWrongThreatEntryType) { | 353 TestParseHashResponseWrongThreatEntryType) { |
| 258 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | 354 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
| 259 | 355 |
| 260 base::Time now = base::Time::UnixEpoch(); | 356 base::Time now = base::Time::UnixEpoch(); |
| 261 SetTestClock(now, pm.get()); | 357 SetTestClock(now, pm.get()); |
| 262 | 358 |
| 263 FindFullHashesResponse res; | 359 FindFullHashesResponse res; |
| 264 res.mutable_negative_cache_duration()->set_seconds(600); | 360 res.mutable_negative_cache_duration()->set_seconds(600); |
| 265 res.add_matches()->set_threat_entry_type(EXECUTABLE); | 361 res.add_matches()->set_threat_entry_type(EXECUTABLE); |
| 266 | 362 |
| 267 // Serialize. | 363 // Serialize. |
| 268 std::string res_data; | 364 std::string res_data; |
| 269 res.SerializeToString(&res_data); | 365 res.SerializeToString(&res_data); |
| 270 | 366 |
| 271 std::vector<SBFullHashResult> full_hashes; | 367 std::vector<FullHashInfo> full_hash_infos; |
| 272 base::Time cache_expire; | 368 base::Time cache_expire; |
| 273 EXPECT_FALSE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire)); | 369 EXPECT_FALSE( |
| 370 pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire)); | |
| 274 | 371 |
| 275 EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire); | 372 EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire); |
| 276 // There should be no hash results. | 373 // There should be no hash results. |
| 277 EXPECT_EQ(0ul, full_hashes.size()); | 374 EXPECT_EQ(0ul, full_hash_infos.size()); |
| 278 } | 375 } |
| 279 | 376 |
| 280 // Adds entries with a ThreatPatternType metadata. | 377 // Adds entries with a ThreatPatternType metadata. |
| 281 TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, | 378 TEST_F(V4GetHashProtocolManagerTest, TestParseHashThreatPatternType) { |
| 282 TestParseHashThreatPatternType) { | |
| 283 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | 379 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
| 284 | 380 |
| 285 base::Time now = base::Time::UnixEpoch(); | 381 base::Time now = base::Time::UnixEpoch(); |
| 286 SetTestClock(now, pm.get()); | 382 SetTestClock(now, pm.get()); |
| 287 | 383 |
| 288 // Test social engineering pattern type. | 384 { |
|
Nathan Parker
2016/09/09 21:26:22
I'm glad you scoped these separately, and I think
vakh (use Gerrit instead)
2016/09/09 23:25:18
I'm usually in favor of keeping tests small and fo
| |
| 289 FindFullHashesResponse se_res; | 385 // Test social engineering pattern type. |
| 290 se_res.mutable_negative_cache_duration()->set_seconds(600); | 386 FindFullHashesResponse se_res; |
| 291 ThreatMatch* se = se_res.add_matches(); | 387 se_res.mutable_negative_cache_duration()->set_seconds(600); |
| 292 se->set_threat_type(SOCIAL_ENGINEERING_PUBLIC); | 388 ThreatMatch* se = se_res.add_matches(); |
| 293 se->set_platform_type(CHROME_PLATFORM); | 389 se->set_threat_type(SOCIAL_ENGINEERING_PUBLIC); |
| 294 se->set_threat_entry_type(URL); | 390 se->set_platform_type(CHROME_PLATFORM); |
| 295 SBFullHash hash_string = SBFullHashForString("Everything's shiny, Cap'n."); | 391 se->set_threat_entry_type(URL); |
| 296 se->mutable_threat()->set_hash(SBFullHashToString(hash_string)); | 392 FullHash full_hash("Everything's shiny, Cap'n."); |
| 297 ThreatEntryMetadata::MetadataEntry* se_meta = | 393 se->mutable_threat()->set_hash(full_hash); |
| 298 se->mutable_threat_entry_metadata()->add_entries(); | 394 ThreatEntryMetadata::MetadataEntry* se_meta = |
| 299 se_meta->set_key("se_pattern_type"); | 395 se->mutable_threat_entry_metadata()->add_entries(); |
| 300 se_meta->set_value("SOCIAL_ENGINEERING_LANDING"); | 396 se_meta->set_key("se_pattern_type"); |
| 397 se_meta->set_value("SOCIAL_ENGINEERING_LANDING"); | |
| 301 | 398 |
| 302 std::string se_data; | 399 std::string se_data; |
| 303 se_res.SerializeToString(&se_data); | 400 se_res.SerializeToString(&se_data); |
| 304 | 401 |
| 305 std::vector<SBFullHashResult> full_hashes; | 402 std::vector<FullHashInfo> full_hash_infos; |
| 306 base::Time cache_expire; | 403 base::Time cache_expire; |
| 307 EXPECT_TRUE(pm->ParseHashResponse(se_data, &full_hashes, &cache_expire)); | 404 EXPECT_TRUE( |
| 405 pm->ParseHashResponse(se_data, &full_hash_infos, &cache_expire)); | |
| 406 EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire); | |
| 308 | 407 |
| 309 EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire); | 408 ASSERT_EQ(1ul, full_hash_infos.size()); |
| 310 EXPECT_EQ(1ul, full_hashes.size()); | 409 const FullHashInfo& fhi = full_hash_infos[0]; |
| 311 EXPECT_TRUE(SBFullHashEqual(hash_string, full_hashes[0].hash)); | 410 EXPECT_EQ(full_hash, fhi.full_hash); |
| 312 EXPECT_EQ(ThreatPatternType::SOCIAL_ENGINEERING_LANDING, | 411 const UpdateListIdentifier list_id(CHROME_PLATFORM, URL, |
| 313 full_hashes[0].metadata.threat_pattern_type); | 412 SOCIAL_ENGINEERING_PUBLIC); |
| 413 EXPECT_EQ(list_id, fhi.list_id); | |
| 414 EXPECT_EQ(ThreatPatternType::SOCIAL_ENGINEERING_LANDING, | |
| 415 fhi.metadata.threat_pattern_type); | |
| 416 } | |
| 314 | 417 |
| 315 // Test potentially harmful application pattern type. | 418 { |
| 316 FindFullHashesResponse pha_res; | 419 // Test potentially harmful application pattern type. |
| 317 pha_res.mutable_negative_cache_duration()->set_seconds(600); | 420 FindFullHashesResponse pha_res; |
| 318 ThreatMatch* pha = pha_res.add_matches(); | 421 pha_res.mutable_negative_cache_duration()->set_seconds(600); |
| 319 pha->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION); | 422 ThreatMatch* pha = pha_res.add_matches(); |
| 320 pha->set_threat_entry_type(URL); | 423 pha->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION); |
| 321 pha->set_platform_type(CHROME_PLATFORM); | 424 pha->set_threat_entry_type(URL); |
| 322 hash_string = SBFullHashForString("Not to fret."); | 425 pha->set_platform_type(CHROME_PLATFORM); |
| 323 pha->mutable_threat()->set_hash(SBFullHashToString(hash_string)); | 426 FullHash full_hash("Not to fret."); |
| 324 ThreatEntryMetadata::MetadataEntry* pha_meta = | 427 pha->mutable_threat()->set_hash(full_hash); |
| 325 pha->mutable_threat_entry_metadata()->add_entries(); | 428 ThreatEntryMetadata::MetadataEntry* pha_meta = |
| 326 pha_meta->set_key("pha_pattern_type"); | 429 pha->mutable_threat_entry_metadata()->add_entries(); |
| 327 pha_meta->set_value("LANDING"); | 430 pha_meta->set_key("pha_pattern_type"); |
| 431 pha_meta->set_value("LANDING"); | |
| 328 | 432 |
| 329 std::string pha_data; | 433 std::string pha_data; |
| 330 pha_res.SerializeToString(&pha_data); | 434 pha_res.SerializeToString(&pha_data); |
| 331 full_hashes.clear(); | 435 std::vector<FullHashInfo> full_hash_infos; |
| 332 EXPECT_TRUE(pm->ParseHashResponse(pha_data, &full_hashes, &cache_expire)); | 436 base::Time cache_expire; |
| 333 EXPECT_EQ(1ul, full_hashes.size()); | 437 EXPECT_TRUE( |
| 334 EXPECT_TRUE(SBFullHashEqual(hash_string, full_hashes[0].hash)); | 438 pm->ParseHashResponse(pha_data, &full_hash_infos, &cache_expire)); |
| 335 EXPECT_EQ(ThreatPatternType::MALWARE_LANDING, | 439 EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire); |
| 336 full_hashes[0].metadata.threat_pattern_type); | |
| 337 | 440 |
| 338 // Test invalid pattern type. | 441 ASSERT_EQ(1ul, full_hash_infos.size()); |
| 339 FindFullHashesResponse invalid_res; | 442 const FullHashInfo& fhi = full_hash_infos[0]; |
| 340 invalid_res.mutable_negative_cache_duration()->set_seconds(600); | 443 EXPECT_EQ(full_hash, fhi.full_hash); |
| 341 ThreatMatch* invalid = invalid_res.add_matches(); | 444 const UpdateListIdentifier list_id(CHROME_PLATFORM, URL, |
| 342 invalid->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION); | 445 POTENTIALLY_HARMFUL_APPLICATION); |
| 343 invalid->set_threat_entry_type(URL); | 446 EXPECT_EQ(list_id, fhi.list_id); |
| 344 invalid->set_platform_type(CHROME_PLATFORM); | 447 EXPECT_EQ(ThreatPatternType::MALWARE_LANDING, |
| 345 invalid->mutable_threat()->set_hash(SBFullHashToString(hash_string)); | 448 fhi.metadata.threat_pattern_type); |
| 346 ThreatEntryMetadata::MetadataEntry* invalid_meta = | 449 } |
| 347 invalid->mutable_threat_entry_metadata()->add_entries(); | |
| 348 invalid_meta->set_key("pha_pattern_type"); | |
| 349 invalid_meta->set_value("INVALIDE_VALUE"); | |
| 350 | 450 |
| 351 std::string invalid_data; | 451 { |
| 352 invalid_res.SerializeToString(&invalid_data); | 452 // Test invalid pattern type. |
| 353 full_hashes.clear(); | 453 FullHash full_hash("Not to fret."); |
| 354 EXPECT_FALSE( | 454 FindFullHashesResponse invalid_res; |
| 355 pm->ParseHashResponse(invalid_data, &full_hashes, &cache_expire)); | 455 invalid_res.mutable_negative_cache_duration()->set_seconds(600); |
| 356 EXPECT_EQ(0ul, full_hashes.size()); | 456 ThreatMatch* invalid = invalid_res.add_matches(); |
| 457 invalid->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION); | |
| 458 invalid->set_threat_entry_type(URL); | |
| 459 invalid->set_platform_type(CHROME_PLATFORM); | |
| 460 invalid->mutable_threat()->set_hash(full_hash); | |
| 461 ThreatEntryMetadata::MetadataEntry* invalid_meta = | |
| 462 invalid->mutable_threat_entry_metadata()->add_entries(); | |
| 463 invalid_meta->set_key("pha_pattern_type"); | |
| 464 invalid_meta->set_value("INVALIDE_VALUE"); | |
| 465 | |
| 466 std::string invalid_data; | |
| 467 invalid_res.SerializeToString(&invalid_data); | |
| 468 std::vector<FullHashInfo> full_hash_infos; | |
| 469 base::Time cache_expire; | |
| 470 EXPECT_FALSE( | |
| 471 pm->ParseHashResponse(invalid_data, &full_hash_infos, &cache_expire)); | |
| 472 EXPECT_EQ(0ul, full_hash_infos.size()); | |
| 473 } | |
| 357 } | 474 } |
| 358 | 475 |
| 359 // Adds metadata with a key value that is not "permission". | 476 // Adds metadata with a key value that is not "permission". |
| 360 TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, | 477 TEST_F(V4GetHashProtocolManagerTest, |
| 361 TestParseHashResponseNonPermissionMetadata) { | 478 TestParseHashResponseNonPermissionMetadata) { |
| 362 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | 479 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
| 363 | 480 |
| 364 base::Time now = base::Time::UnixEpoch(); | 481 base::Time now = base::Time::UnixEpoch(); |
| 365 SetTestClock(now, pm.get()); | 482 SetTestClock(now, pm.get()); |
| 366 | 483 |
| 367 FindFullHashesResponse res; | 484 FindFullHashesResponse res; |
| 368 res.mutable_negative_cache_duration()->set_seconds(600); | 485 res.mutable_negative_cache_duration()->set_seconds(600); |
| 369 ThreatMatch* m = res.add_matches(); | 486 ThreatMatch* m = res.add_matches(); |
| 370 m->set_threat_type(API_ABUSE); | 487 m->set_threat_type(API_ABUSE); |
| 371 m->set_platform_type(CHROME_PLATFORM); | 488 m->set_platform_type(CHROME_PLATFORM); |
| 372 m->set_threat_entry_type(URL); | 489 m->set_threat_entry_type(URL); |
| 373 m->mutable_threat()->set_hash( | 490 m->mutable_threat()->set_hash(FullHash("Not to fret.")); |
| 374 SBFullHashToString(SBFullHashForString("Not to fret."))); | |
| 375 ThreatEntryMetadata::MetadataEntry* e = | 491 ThreatEntryMetadata::MetadataEntry* e = |
| 376 m->mutable_threat_entry_metadata()->add_entries(); | 492 m->mutable_threat_entry_metadata()->add_entries(); |
| 377 e->set_key("notpermission"); | 493 e->set_key("notpermission"); |
| 378 e->set_value("NOTGEOLOCATION"); | 494 e->set_value("NOTGEOLOCATION"); |
| 379 | 495 |
| 380 // Serialize. | 496 // Serialize. |
| 381 std::string res_data; | 497 std::string res_data; |
| 382 res.SerializeToString(&res_data); | 498 res.SerializeToString(&res_data); |
| 383 | 499 |
| 384 std::vector<SBFullHashResult> full_hashes; | 500 std::vector<FullHashInfo> full_hash_infos; |
| 385 base::Time cache_expire; | 501 base::Time cache_expire; |
| 386 EXPECT_FALSE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire)); | 502 EXPECT_FALSE( |
| 503 pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire)); | |
| 387 | 504 |
| 388 EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire); | 505 EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire); |
| 389 EXPECT_EQ(0ul, full_hashes.size()); | 506 EXPECT_EQ(0ul, full_hash_infos.size()); |
| 390 } | 507 } |
| 391 | 508 |
| 392 TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, | 509 TEST_F(V4GetHashProtocolManagerTest, |
| 393 TestParseHashResponseInconsistentThreatTypes) { | 510 TestParseHashResponseInconsistentThreatTypes) { |
| 394 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | 511 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
| 395 | 512 |
| 396 FindFullHashesResponse res; | 513 FindFullHashesResponse res; |
| 397 res.mutable_negative_cache_duration()->set_seconds(600); | 514 res.mutable_negative_cache_duration()->set_seconds(600); |
| 398 ThreatMatch* m1 = res.add_matches(); | 515 ThreatMatch* m1 = res.add_matches(); |
| 399 m1->set_threat_type(API_ABUSE); | 516 m1->set_threat_type(API_ABUSE); |
| 400 m1->set_platform_type(CHROME_PLATFORM); | 517 m1->set_platform_type(CHROME_PLATFORM); |
| 401 m1->set_threat_entry_type(URL); | 518 m1->set_threat_entry_type(URL); |
| 402 m1->mutable_threat()->set_hash( | 519 m1->mutable_threat()->set_hash(FullHash("Everything's shiny, Cap'n.")); |
| 403 SBFullHashToString(SBFullHashForString("Everything's shiny, Cap'n."))); | |
| 404 m1->mutable_threat_entry_metadata()->add_entries(); | 520 m1->mutable_threat_entry_metadata()->add_entries(); |
| 405 ThreatMatch* m2 = res.add_matches(); | 521 ThreatMatch* m2 = res.add_matches(); |
| 406 m2->set_threat_type(MALWARE_THREAT); | 522 m2->set_threat_type(MALWARE_THREAT); |
| 407 m2->set_threat_entry_type(URL); | 523 m2->set_threat_entry_type(URL); |
| 408 m2->mutable_threat()->set_hash( | 524 m2->mutable_threat()->set_hash(FullHash("Not to fret.")); |
| 409 SBFullHashToString(SBFullHashForString("Not to fret."))); | |
| 410 | 525 |
| 411 // Serialize. | 526 // Serialize. |
| 412 std::string res_data; | 527 std::string res_data; |
| 413 res.SerializeToString(&res_data); | 528 res.SerializeToString(&res_data); |
| 414 | 529 |
| 415 std::vector<SBFullHashResult> full_hashes; | 530 std::vector<FullHashInfo> full_hash_infos; |
| 416 base::Time cache_expire; | 531 base::Time cache_expire; |
| 417 EXPECT_FALSE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire)); | 532 EXPECT_FALSE( |
| 533 pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire)); | |
| 534 } | |
| 535 | |
| 536 // Checks that results are looked up correctly in the cache. | |
| 537 TEST_F(V4GetHashProtocolManagerTest, GetCachedResults) { | |
|
Nathan Parker
2016/09/09 21:26:22
An overall comment: I think it would be less fragi
| |
| 538 base::Time now = base::Time::UnixEpoch(); | |
| 539 FullHash full_hash("example.com/"); | |
|
Nathan Parker
2016/09/09 21:26:22
nit: A url-as-hash is sortof confusing
vakh (use Gerrit instead)
2016/09/09 23:25:18
Done.
| |
| 540 HashPrefix prefix("exam"); | |
| 541 FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes; | |
| 542 std::vector<HashPrefix> prefixes_to_request; | |
| 543 std::vector<FullHashInfo> cached_full_hash_infos; | |
| 544 full_hash_to_store_and_hash_prefixes[full_hash].push_back( | |
| 545 StoreAndHashPrefix(GetUrlMalwareId(), prefix)); | |
| 546 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | |
| 547 FullHashCache* cache = pm->full_hash_cache_for_tests(); | |
| 548 | |
| 549 // Test with an empty cache. (Case: 2) | |
| 550 pm->GetFullHashCachedResults(full_hash_to_store_and_hash_prefixes, now, | |
| 551 &prefixes_to_request, &cached_full_hash_infos); | |
| 552 EXPECT_TRUE(cache->empty()); | |
| 553 ASSERT_EQ(1ul, prefixes_to_request.size()); | |
| 554 EXPECT_EQ(prefix, prefixes_to_request[0]); | |
| 555 EXPECT_TRUE(cached_full_hash_infos.empty()); | |
| 556 | |
| 557 // Prefix has a cache entry but full hash is not there. (Case: 1-b-i) | |
| 558 CachedHashPrefixInfo* entry = &(*cache)[prefix]; | |
|
Nathan Parker
2016/09/09 21:26:21
Do all these cases need to be in one test? Could y
vakh (use Gerrit instead)
2016/09/09 23:25:18
Scoped each of the cases, and clear the cache befo
| |
| 559 entry->negative_ttl = now + base::TimeDelta::FromMinutes(5); | |
| 560 prefixes_to_request.clear(); | |
| 561 cached_full_hash_infos.clear(); | |
| 562 pm->GetFullHashCachedResults(full_hash_to_store_and_hash_prefixes, now, | |
| 563 &prefixes_to_request, &cached_full_hash_infos); | |
| 564 EXPECT_TRUE(prefixes_to_request.empty()); | |
| 565 EXPECT_TRUE(cached_full_hash_infos.empty()); | |
| 566 | |
| 567 // Expired negative cache entry. (Case: 1-b-ii) | |
| 568 entry->negative_ttl = now - base::TimeDelta::FromMinutes(5); | |
| 569 prefixes_to_request.clear(); | |
| 570 cached_full_hash_infos.clear(); | |
| 571 pm->GetFullHashCachedResults(full_hash_to_store_and_hash_prefixes, now, | |
| 572 &prefixes_to_request, &cached_full_hash_infos); | |
| 573 ASSERT_EQ(1ul, prefixes_to_request.size()); | |
| 574 EXPECT_EQ(prefix, prefixes_to_request[0]); | |
| 575 EXPECT_TRUE(cached_full_hash_infos.empty()); | |
| 576 | |
| 577 // Now put unexpired full hash in the cache. (Case: 1-a-i) | |
| 578 FullHashInfo fhi(full_hash, GetUrlMalwareId(), | |
| 579 now + base::TimeDelta::FromMinutes(3)); | |
| 580 entry->full_hash_infos.push_back(fhi); | |
| 581 prefixes_to_request.clear(); | |
| 582 cached_full_hash_infos.clear(); | |
| 583 pm->GetFullHashCachedResults(full_hash_to_store_and_hash_prefixes, now, | |
| 584 &prefixes_to_request, &cached_full_hash_infos); | |
| 585 EXPECT_TRUE(prefixes_to_request.empty()); | |
| 586 ASSERT_EQ(1ul, cached_full_hash_infos.size()); | |
| 587 EXPECT_EQ(full_hash, cached_full_hash_infos[0].full_hash); | |
| 588 | |
| 589 // Expire the full hash in the cache. (Case: 1-a-ii) | |
| 590 entry->full_hash_infos[0].positive_ttl = | |
| 591 now - base::TimeDelta::FromMinutes(3); | |
| 592 prefixes_to_request.clear(); | |
| 593 cached_full_hash_infos.clear(); | |
| 594 pm->GetFullHashCachedResults(full_hash_to_store_and_hash_prefixes, now, | |
| 595 &prefixes_to_request, &cached_full_hash_infos); | |
| 596 ASSERT_EQ(1ul, prefixes_to_request.size()); | |
| 597 EXPECT_EQ(prefix, prefixes_to_request[0]); | |
| 598 EXPECT_TRUE(cached_full_hash_infos.empty()); | |
| 599 } | |
| 600 | |
| 601 TEST_F(V4GetHashProtocolManagerTest, TestUpdatesAreMerged) { | |
| 602 // We'll add one of the requested FullHashInfo objects into the cache, and | |
| 603 // inject the other one as a response from the server. The result should | |
| 604 // include both FullHashInfo objects. | |
| 605 | |
| 606 net::TestURLFetcherFactory factory; | |
| 607 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | |
| 608 HashPrefix prefix_1("exam"); | |
| 609 FullHash full_hash_1("example.com/test"); | |
|
Nathan Parker
2016/09/09 21:26:22
nit: url-as-hash is confusing
vakh (use Gerrit instead)
2016/09/09 23:25:18
Done.
| |
| 610 HashPrefix prefix_2("Everything"); | |
| 611 FullHash full_hash_2("Everything's shiny, Cap'n."); | |
| 612 | |
| 613 base::Time now = Time::Now(); | |
| 614 SetTestClock(now, pm.get()); | |
| 615 | |
| 616 FullHashCache* cache = pm->full_hash_cache_for_tests(); | |
| 617 CachedHashPrefixInfo* entry = &(*cache)[prefix_1]; | |
| 618 entry->negative_ttl = now + base::TimeDelta::FromMinutes(100); | |
| 619 // Put one unexpired full hash in the cache for a store we'll look in. | |
| 620 entry->full_hash_infos.emplace_back(full_hash_1, GetUrlMalwareId(), | |
| 621 now + base::TimeDelta::FromSeconds(200)); | |
| 622 // Put one unexpired full hash in the cache for a store we'll not look in. | |
| 623 entry->full_hash_infos.emplace_back(full_hash_1, GetUrlSocEngId(), | |
| 624 now + base::TimeDelta::FromSeconds(200)); | |
| 625 | |
| 626 // Request full hash information from two stores. | |
| 627 FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes; | |
| 628 full_hash_to_store_and_hash_prefixes[full_hash_1].push_back( | |
| 629 StoreAndHashPrefix(GetUrlMalwareId(), prefix_1)); | |
| 630 full_hash_to_store_and_hash_prefixes[full_hash_2].push_back( | |
| 631 StoreAndHashPrefix(GetChromeUrlApiId(), prefix_2)); | |
| 632 | |
| 633 // Expect full hash information from both stores. | |
| 634 std::vector<FullHashInfo> expected_results; | |
| 635 expected_results.emplace_back(full_hash_1, GetUrlMalwareId(), | |
| 636 now + base::TimeDelta::FromSeconds(200)); | |
| 637 expected_results.emplace_back(full_hash_2, GetChromeUrlApiId(), | |
| 638 now + base::TimeDelta::FromSeconds(300)); | |
| 639 expected_results[1].metadata.api_permissions.insert("NOTIFICATIONS"); | |
| 640 | |
| 641 pm->GetFullHashes( | |
| 642 full_hash_to_store_and_hash_prefixes, | |
| 643 base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults, | |
| 644 base::Unretained(this), expected_results)); | |
| 645 | |
| 646 SetupFetcherToReturnOKResponse(factory, GetStockV4HashResponseInfos()); | |
| 647 | |
| 648 // No error, back off multiplier is unchanged. | |
| 649 EXPECT_EQ(0ul, pm->gethash_error_count_); | |
| 650 EXPECT_EQ(1ul, pm->gethash_back_off_mult_); | |
| 651 | |
| 652 // Verify the state of the cache. | |
| 653 ASSERT_EQ(2u, cache->size()); | |
| 654 const CachedHashPrefixInfo& cached_result_1 = cache->at(prefix_1); | |
| 655 EXPECT_EQ(cached_result_1.negative_ttl, | |
| 656 now + base::TimeDelta::FromMinutes(100)); | |
| 657 ASSERT_EQ(2u, cached_result_1.full_hash_infos.size()); | |
| 658 EXPECT_EQ(full_hash_1, cached_result_1.full_hash_infos[0].full_hash); | |
| 659 EXPECT_EQ(GetUrlMalwareId(), cached_result_1.full_hash_infos[0].list_id); | |
| 660 | |
| 661 const CachedHashPrefixInfo& cached_result_2 = cache->at(prefix_2); | |
| 662 EXPECT_EQ(cached_result_2.negative_ttl, | |
| 663 now + base::TimeDelta::FromSeconds(600)); | |
| 664 ASSERT_EQ(1u, cached_result_2.full_hash_infos.size()); | |
| 665 EXPECT_EQ(full_hash_2, cached_result_2.full_hash_infos[0].full_hash); | |
| 666 EXPECT_EQ(GetChromeUrlApiId(), cached_result_2.full_hash_infos[0].list_id); | |
| 667 EXPECT_TRUE(callback_called()); | |
| 668 } | |
| 669 | |
| 670 // The server responds back with full hash information containing metadata | |
| 671 // information for one of the full hashes for the URL in test. | |
| 672 TEST_F(V4GetHashProtocolManagerTest, TestGetFullHashesWithApisMergesMetadata) { | |
| 673 net::TestURLFetcherFactory factory; | |
| 674 const GURL url("https://www.example.com/more"); | |
| 675 ThreatMetadata expected_md; | |
| 676 expected_md.api_permissions.insert("NOTIFICATIONS"); | |
| 677 expected_md.api_permissions.insert("AUDIO_CAPTURE"); | |
| 678 std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); | |
| 679 pm->GetFullHashesWithApis( | |
| 680 url, base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4ApiResults, | |
| 681 base::Unretained(this), expected_md)); | |
| 682 | |
| 683 // The following two random looking strings value are two of the full hashes | |
| 684 // produced by UrlToFullHashes in v4_protocol_manager_util.h for the URL: | |
| 685 // "https://www.example.com/more" | |
| 686 std::vector<ResponseInfo> infos; | |
| 687 FullHash full_hash; | |
| 688 base::Base64Decode("1ZzJ0/7NjPkg6t0DAS8L5Jf7jA48Pn7opQcP4UXYeXc=", | |
| 689 &full_hash); | |
| 690 ResponseInfo info(full_hash, GetChromeUrlApiId()); | |
| 691 info.key_values.emplace_back("permission", "NOTIFICATIONS"); | |
| 692 infos.push_back(info); | |
| 693 | |
| 694 base::Base64Decode("4rPDSdcei1BiCOPnj9kgsy2O6Ua6X3iFBakqphB3ZfA=", | |
| 695 &full_hash); | |
| 696 info = ResponseInfo(full_hash, GetChromeUrlApiId()); | |
| 697 info.key_values.emplace_back("permission", "AUDIO_CAPTURE"); | |
| 698 infos.push_back(info); | |
| 699 | |
| 700 full_hash = FullHash("Everything's shiny, Cap'n."); | |
| 701 info = ResponseInfo(full_hash, GetChromeUrlApiId()); | |
| 702 info.key_values.emplace_back("permission", "GEOLOCATION"); | |
| 703 infos.push_back(info); | |
| 704 SetupFetcherToReturnOKResponse(factory, infos); | |
| 705 | |
| 706 EXPECT_TRUE(callback_called()); | |
| 418 } | 707 } |
| 419 | 708 |
| 420 } // namespace safe_browsing | 709 } // namespace safe_browsing |
| OLD | NEW |