| 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/database_manager.h" | 5 #include "components/safe_browsing_db/database_manager.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 negative_cache_expire_), | 54 negative_cache_expire_), |
| 55 base::TimeDelta::FromSeconds(delay_seconds_)); | 55 base::TimeDelta::FromSeconds(delay_seconds_)); |
| 56 } | 56 } |
| 57 | 57 |
| 58 void SetDelaySeconds(int delay) { | 58 void SetDelaySeconds(int delay) { |
| 59 delay_seconds_ = delay; | 59 delay_seconds_ = delay; |
| 60 } | 60 } |
| 61 | 61 |
| 62 void SetNegativeCacheDurationMins(base::Time now, | 62 void SetNegativeCacheDurationMins(base::Time now, |
| 63 int negative_cache_duration_mins) { | 63 int negative_cache_duration_mins) { |
| 64 negative_cache_expire_ = now + | 64 // Don't add a TimeDelta to the maximum time to avoid undefined behavior. |
| 65 base::TimeDelta::FromMinutes(negative_cache_duration_mins); | 65 negative_cache_expire_ = now.is_max() ? now : |
| 66 now + base::TimeDelta::FromMinutes(negative_cache_duration_mins); |
| 66 } | 67 } |
| 67 | 68 |
| 68 // Prepare the GetFullHash results for the next request. | 69 // Prepare the GetFullHash results for the next request. |
| 69 void AddGetFullHashResponse(const SBFullHashResult& full_hash_result) { | 70 void AddGetFullHashResponse(const SBFullHashResult& full_hash_result) { |
| 70 full_hashes_.push_back(full_hash_result); | 71 full_hashes_.push_back(full_hash_result); |
| 71 } | 72 } |
| 72 | 73 |
| 74 // Clear the GetFullHash results for the next request. |
| 75 void ClearFullHashResponse() { |
| 76 full_hashes_.clear(); |
| 77 } |
| 78 |
| 73 // Returns the prefixes that were sent in the last request. | 79 // Returns the prefixes that were sent in the last request. |
| 74 const std::vector<SBPrefix>& GetRequestPrefixes() { return prefixes_; } | 80 const std::vector<SBPrefix>& GetRequestPrefixes() { return prefixes_; } |
| 75 | 81 |
| 76 private: | 82 private: |
| 77 std::vector<SBPrefix> prefixes_; | 83 std::vector<SBPrefix> prefixes_; |
| 78 std::vector<SBFullHashResult> full_hashes_; | 84 std::vector<SBFullHashResult> full_hashes_; |
| 79 base::Time negative_cache_expire_; | 85 base::Time negative_cache_expire_; |
| 80 int delay_seconds_; | 86 int delay_seconds_; |
| 81 }; | 87 }; |
| 82 | 88 |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>( | 262 TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>( |
| 257 db_manager_->v4_get_hash_protocol_manager_); | 263 db_manager_->v4_get_hash_protocol_manager_); |
| 258 base::Time now = base::Time::UnixEpoch(); | 264 base::Time now = base::Time::UnixEpoch(); |
| 259 SBFullHashResult full_hash_result; | 265 SBFullHashResult full_hash_result; |
| 260 full_hash_result.hash = SBFullHashForString("example.com/"); | 266 full_hash_result.hash = SBFullHashForString("example.com/"); |
| 261 full_hash_result.metadata.api_permissions.push_back("GEOLOCATION"); | 267 full_hash_result.metadata.api_permissions.push_back("GEOLOCATION"); |
| 262 full_hash_result.cache_expire_after = now + base::TimeDelta::FromMinutes(3); | 268 full_hash_result.cache_expire_after = now + base::TimeDelta::FromMinutes(3); |
| 263 pm->AddGetFullHashResponse(full_hash_result); | 269 pm->AddGetFullHashResponse(full_hash_result); |
| 264 pm->SetNegativeCacheDurationMins(now, 5); | 270 pm->SetNegativeCacheDurationMins(now, 5); |
| 265 | 271 |
| 266 EXPECT_TRUE(db_manager_->api_cache_.empty()); | 272 EXPECT_TRUE(db_manager_->v4_full_hash_cache_.empty()); |
| 267 EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client)); | 273 EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client)); |
| 268 base::RunLoop().RunUntilIdle(); | 274 base::RunLoop().RunUntilIdle(); |
| 269 | 275 |
| 270 EXPECT_TRUE(client.callback_invoked()); | 276 EXPECT_TRUE(client.callback_invoked()); |
| 271 const std::vector<std::string>& permissions = client.GetBlockedPermissions(); | 277 const std::vector<std::string>& permissions = client.GetBlockedPermissions(); |
| 272 EXPECT_EQ(1ul, permissions.size()); | 278 EXPECT_EQ(1ul, permissions.size()); |
| 273 EXPECT_EQ("GEOLOCATION", permissions[0]); | 279 EXPECT_EQ("GEOLOCATION", permissions[0]); |
| 274 | 280 |
| 275 // Check the cache. | 281 // Check the cache. |
| 282 const SafeBrowsingDatabaseManager::PrefixToFullHashResultsMap& cache = |
| 283 db_manager_->v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE]; |
| 276 // Generated from the sorted output of UrlToFullHashes in util.h. | 284 // Generated from the sorted output of UrlToFullHashes in util.h. |
| 277 std::vector<SBPrefix> expected_prefixes = | 285 std::vector<SBPrefix> expected_prefixes = |
| 278 {1237562338, 2871045197, 3553205461, 3766933875}; | 286 {1237562338, 2871045197, 3553205461, 3766933875}; |
| 279 EXPECT_EQ(expected_prefixes.size(), db_manager_->api_cache_.size()); | 287 EXPECT_EQ(expected_prefixes.size(), |
| 288 db_manager_->v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE].size()); |
| 280 | 289 |
| 281 auto entry = db_manager_->api_cache_.find(expected_prefixes[0]); | 290 auto entry = cache.find(expected_prefixes[0]); |
| 282 EXPECT_NE(db_manager_->api_cache_.end(), entry); | 291 EXPECT_NE(cache.end(), entry); |
| 283 EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after); | 292 EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after); |
| 284 EXPECT_EQ(0ul, entry->second.full_hashes.size()); | 293 EXPECT_EQ(0ul, entry->second.full_hashes.size()); |
| 285 | 294 |
| 286 entry = db_manager_->api_cache_.find(expected_prefixes[1]); | 295 entry = cache.find(expected_prefixes[1]); |
| 287 EXPECT_NE(db_manager_->api_cache_.end(), entry); | 296 EXPECT_NE(cache.end(), entry); |
| 288 EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after); | 297 EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after); |
| 289 EXPECT_EQ(0ul, entry->second.full_hashes.size()); | 298 EXPECT_EQ(0ul, entry->second.full_hashes.size()); |
| 290 | 299 |
| 291 entry = db_manager_->api_cache_.find(expected_prefixes[2]); | 300 entry = cache.find(expected_prefixes[2]); |
| 292 EXPECT_NE(db_manager_->api_cache_.end(), entry); | 301 EXPECT_NE(cache.end(), entry); |
| 293 EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after); | 302 EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after); |
| 294 EXPECT_EQ(0ul, entry->second.full_hashes.size()); | 303 EXPECT_EQ(0ul, entry->second.full_hashes.size()); |
| 295 | 304 |
| 296 entry = db_manager_->api_cache_.find(expected_prefixes[3]); | 305 entry = cache.find(expected_prefixes[3]); |
| 297 EXPECT_NE(db_manager_->api_cache_.end(), entry); | 306 EXPECT_NE(cache.end(), entry); |
| 298 EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after); | 307 EXPECT_EQ(now + base::TimeDelta::FromMinutes(5), entry->second.expire_after); |
| 299 EXPECT_EQ(1ul, entry->second.full_hashes.size()); | 308 EXPECT_EQ(1ul, entry->second.full_hashes.size()); |
| 300 EXPECT_TRUE(SBFullHashEqual(full_hash_result.hash, | 309 EXPECT_TRUE(SBFullHashEqual(full_hash_result.hash, |
| 301 entry->second.full_hashes[0].hash)); | 310 entry->second.full_hashes[0].hash)); |
| 302 EXPECT_EQ(1ul, entry->second.full_hashes[0].metadata.api_permissions.size()); | 311 EXPECT_EQ(1ul, entry->second.full_hashes[0].metadata.api_permissions.size()); |
| 303 EXPECT_EQ("GEOLOCATION", | 312 EXPECT_EQ("GEOLOCATION", |
| 304 entry->second.full_hashes[0].metadata.api_permissions[0]); | 313 entry->second.full_hashes[0].metadata.api_permissions[0]); |
| 305 EXPECT_EQ(full_hash_result.cache_expire_after, | 314 EXPECT_EQ(full_hash_result.cache_expire_after, |
| 306 entry->second.full_hashes[0].cache_expire_after); | 315 entry->second.full_hashes[0].cache_expire_after); |
| 307 } | 316 } |
| 308 | 317 |
| 309 // An uninitialized value for negative cache expire does not cache results. | 318 // An uninitialized value for negative cache expire does not cache results. |
| 310 TEST_F(SafeBrowsingDatabaseManagerTest, ResultsAreNotCachedOnNull) { | 319 TEST_F(SafeBrowsingDatabaseManagerTest, ResultsAreNotCachedOnNull) { |
| 311 TestClient client; | 320 TestClient client; |
| 312 const GURL url("https://www.example.com/more"); | 321 const GURL url("https://www.example.com/more"); |
| 313 TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>( | 322 TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>( |
| 314 db_manager_->v4_get_hash_protocol_manager_); | 323 db_manager_->v4_get_hash_protocol_manager_); |
| 315 base::Time now = base::Time::UnixEpoch(); | 324 base::Time now = base::Time::UnixEpoch(); |
| 316 SBFullHashResult full_hash_result; | 325 SBFullHashResult full_hash_result; |
| 317 full_hash_result.hash = SBFullHashForString("example.com/"); | 326 full_hash_result.hash = SBFullHashForString("example.com/"); |
| 318 full_hash_result.metadata.api_permissions.push_back("GEOLOCATION"); | 327 full_hash_result.metadata.api_permissions.push_back("GEOLOCATION"); |
| 319 full_hash_result.cache_expire_after = now + base::TimeDelta::FromMinutes(3); | 328 full_hash_result.cache_expire_after = now + base::TimeDelta::FromMinutes(3); |
| 320 pm->AddGetFullHashResponse(full_hash_result); | 329 pm->AddGetFullHashResponse(full_hash_result); |
| 321 | 330 |
| 322 EXPECT_TRUE(db_manager_->api_cache_.empty()); | 331 EXPECT_TRUE(db_manager_->v4_full_hash_cache_.empty()); |
| 323 EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client)); | 332 EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client)); |
| 324 base::RunLoop().RunUntilIdle(); | 333 base::RunLoop().RunUntilIdle(); |
| 325 | 334 |
| 326 EXPECT_TRUE(client.callback_invoked()); | 335 EXPECT_TRUE(client.callback_invoked()); |
| 327 EXPECT_TRUE(db_manager_->api_cache_.empty()); | 336 EXPECT_TRUE( |
| 337 db_manager_->v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE].empty()); |
| 338 } |
| 339 |
| 340 // Checks that results are looked up correctly in the cache. |
| 341 TEST_F(SafeBrowsingDatabaseManagerTest, GetCachedResults) { |
| 342 base::Time now = base::Time::UnixEpoch(); |
| 343 std::vector<SBFullHash> full_hashes; |
| 344 SBFullHash full_hash = SBFullHashForString("example.com/"); |
| 345 full_hashes.push_back(full_hash); |
| 346 std::vector<SBFullHashResult> cached_results; |
| 347 std::vector<SBPrefix> prefixes; |
| 348 db_manager_->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE, |
| 349 full_hashes, now, &prefixes, &cached_results); |
| 350 |
| 351 // The cache is empty. |
| 352 EXPECT_TRUE(cached_results.empty()); |
| 353 EXPECT_EQ(1ul, prefixes.size()); |
| 354 EXPECT_EQ(full_hash.prefix, prefixes[0]); |
| 355 |
| 356 // Prefix has a cache entry but full hash is not there. |
| 357 SBCachedFullHashResult& entry = db_manager_-> |
| 358 v4_full_hash_cache_[SB_THREAT_TYPE_API_ABUSE][full_hash.prefix] = |
| 359 SBCachedFullHashResult(now + base::TimeDelta::FromMinutes(5)); |
| 360 db_manager_->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE, |
| 361 full_hashes, now, &prefixes, &cached_results); |
| 362 |
| 363 EXPECT_TRUE(prefixes.empty()); |
| 364 EXPECT_TRUE(cached_results.empty()); |
| 365 |
| 366 // Expired negative cache entry. |
| 367 entry.expire_after = now - base::TimeDelta::FromMinutes(5); |
| 368 db_manager_->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE, |
| 369 full_hashes, now, &prefixes, &cached_results); |
| 370 |
| 371 EXPECT_TRUE(cached_results.empty()); |
| 372 EXPECT_EQ(1ul, prefixes.size()); |
| 373 EXPECT_EQ(full_hash.prefix, prefixes[0]); |
| 374 |
| 375 // Now put the full hash in the cache. |
| 376 SBFullHashResult full_hash_result; |
| 377 full_hash_result.hash = full_hash; |
| 378 full_hash_result.cache_expire_after = now + base::TimeDelta::FromMinutes(3); |
| 379 entry.full_hashes.push_back(full_hash_result); |
| 380 db_manager_->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE, |
| 381 full_hashes, now, &prefixes, &cached_results); |
| 382 |
| 383 EXPECT_TRUE(prefixes.empty()); |
| 384 EXPECT_EQ(1ul, cached_results.size()); |
| 385 EXPECT_TRUE(SBFullHashEqual(full_hash, cached_results[0].hash)); |
| 386 |
| 387 // Expired full hash in cache. |
| 388 entry.full_hashes.clear(); |
| 389 full_hash_result.cache_expire_after = now - base::TimeDelta::FromMinutes(3); |
| 390 entry.full_hashes.push_back(full_hash_result); |
| 391 db_manager_->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE, |
| 392 full_hashes, now, &prefixes, &cached_results); |
| 393 |
| 394 EXPECT_TRUE(cached_results.empty()); |
| 395 EXPECT_EQ(1ul, prefixes.size()); |
| 396 EXPECT_EQ(full_hash.prefix, prefixes[0]); |
| 397 } |
| 398 |
| 399 // Checks that the cached results and request results are merged. |
| 400 TEST_F(SafeBrowsingDatabaseManagerTest, CachedResultsMerged) { |
| 401 TestClient client; |
| 402 const GURL url("https://www.example.com/more"); |
| 403 TestV4GetHashProtocolManager* pm = static_cast<TestV4GetHashProtocolManager*>( |
| 404 db_manager_->v4_get_hash_protocol_manager_); |
| 405 // Set now to max time so the cache expire times are in the future. |
| 406 SBFullHashResult full_hash_result; |
| 407 full_hash_result.hash = SBFullHashForString("example.com/"); |
| 408 full_hash_result.metadata.api_permissions.push_back("GEOLOCATION"); |
| 409 full_hash_result.cache_expire_after = base::Time::Max(); |
| 410 pm->AddGetFullHashResponse(full_hash_result); |
| 411 pm->SetNegativeCacheDurationMins(base::Time::Max(), 0); |
| 412 |
| 413 EXPECT_TRUE(db_manager_->v4_full_hash_cache_.empty()); |
| 414 EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client)); |
| 415 base::RunLoop().RunUntilIdle(); |
| 416 |
| 417 EXPECT_TRUE(client.callback_invoked()); |
| 418 const std::vector<std::string>& permissions = client.GetBlockedPermissions(); |
| 419 EXPECT_EQ(1ul, permissions.size()); |
| 420 EXPECT_EQ("GEOLOCATION", permissions[0]); |
| 421 |
| 422 // The results should be cached, so remove them from the protocol manager |
| 423 // response. |
| 424 TestClient client2; |
| 425 pm->ClearFullHashResponse(); |
| 426 pm->SetNegativeCacheDurationMins(base::Time(), 0); |
| 427 EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url, &client2)); |
| 428 base::RunLoop().RunUntilIdle(); |
| 429 |
| 430 EXPECT_TRUE(client2.callback_invoked()); |
| 431 const std::vector<std::string>& permissions2 = |
| 432 client2.GetBlockedPermissions(); |
| 433 EXPECT_EQ(1ul, permissions2.size()); |
| 434 EXPECT_EQ("GEOLOCATION", permissions2[0]); |
| 435 |
| 436 // Add a different result to the protocol manager response and ensure it is |
| 437 // merged with the cached result in the metadata. |
| 438 TestClient client3; |
| 439 const GURL url2("https://m.example.com/more"); |
| 440 full_hash_result.hash = SBFullHashForString("m.example.com/"); |
| 441 full_hash_result.metadata.api_permissions.push_back("NOTIFICATIONS"); |
| 442 pm->AddGetFullHashResponse(full_hash_result); |
| 443 pm->SetNegativeCacheDurationMins(base::Time::Max(), 0); |
| 444 EXPECT_FALSE(db_manager_->CheckApiBlacklistUrl(url2, &client3)); |
| 445 base::RunLoop().RunUntilIdle(); |
| 446 |
| 447 EXPECT_TRUE(client3.callback_invoked()); |
| 448 const std::vector<std::string>& permissions3 = |
| 449 client3.GetBlockedPermissions(); |
| 450 EXPECT_EQ(3ul, permissions3.size()); |
| 451 // TODO(kcarattini): Fix the metadata storage of permissions to avoid |
| 452 // duplicates. |
| 453 EXPECT_EQ("GEOLOCATION", permissions3[0]); |
| 454 EXPECT_EQ("NOTIFICATIONS", permissions3[1]); |
| 455 EXPECT_EQ("GEOLOCATION", permissions3[2]); |
| 328 } | 456 } |
| 329 | 457 |
| 330 } // namespace safe_browsing | 458 } // namespace safe_browsing |
| OLD | NEW |