1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <map>
6 #include <queue>
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/time/time.h"
15 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
16 #include "chrome/common/safe_browsing/client_model.pb.h"
17 #include "chrome/common/safe_browsing/csd.pb.h"
18 #include "content/public/test/test_browser_thread.h"
19 #include "crypto/sha2.h"
20 #include "net/http/http_status_code.h"
21 #include "net/url_request/test_url_fetcher_factory.h"
22 #include "net/url_request/url_request_status.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "url/gurl.h"
26
27 using ::testing::Invoke;
28 using ::testing::Mock;
29 using ::testing::StrictMock;
30 using ::testing::_;
31 using content::BrowserThread;
32
33 namespace safe_browsing {
34 namespace {
35 class MockClientSideDetectionService : public ClientSideDetectionService {
36 public:
MockClientSideDetectionService()37 MockClientSideDetectionService() : ClientSideDetectionService(NULL) {}
~MockClientSideDetectionService()38 virtual ~MockClientSideDetectionService() {}
39
40 MOCK_METHOD1(EndFetchModel, void(ClientModelStatus));
41 MOCK_METHOD1(ScheduleFetchModel, void(int64));
42
Schedule(int64)43 void Schedule(int64) {
44 // Ignore the delay when testing.
45 StartFetchModel();
46 }
47
Disable(int)48 void Disable(int) {
49 // Ignore the status.
50 SetEnabledAndRefreshState(false);
51 }
52
53 private:
54 DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
55 };
56
ACTION(QuitCurrentMessageLoop)57 ACTION(QuitCurrentMessageLoop) {
58 base::MessageLoop::current()->Quit();
59 }
60
61 } // namespace
62
63 class ClientSideDetectionServiceTest : public testing::Test {
64 protected:
SetUp()65 virtual void SetUp() {
66 file_thread_.reset(new content::TestBrowserThread(BrowserThread::FILE,
67 &msg_loop_));
68
69 factory_.reset(new net::FakeURLFetcherFactory(NULL));
70
71 browser_thread_.reset(new content::TestBrowserThread(BrowserThread::UI,
72 &msg_loop_));
73 }
74
TearDown()75 virtual void TearDown() {
76 msg_loop_.RunUntilIdle();
77 csd_service_.reset();
78 file_thread_.reset();
79 browser_thread_.reset();
80 }
81
SendClientReportPhishingRequest(const GURL & phishing_url,float score)82 bool SendClientReportPhishingRequest(const GURL& phishing_url,
83 float score) {
84 ClientPhishingRequest* request = new ClientPhishingRequest();
85 request->set_url(phishing_url.spec());
86 request->set_client_score(score);
87 request->set_is_phishing(true); // client thinks the URL is phishing.
88 csd_service_->SendClientReportPhishingRequest(
89 request,
90 base::Bind(&ClientSideDetectionServiceTest::SendRequestDone,
91 base::Unretained(this)));
92 phishing_url_ = phishing_url;
93 msg_loop_.Run(); // Waits until callback is called.
94 return is_phishing_;
95 }
96
SendClientReportMalwareRequest(const GURL & url)97 bool SendClientReportMalwareRequest(const GURL& url) {
98 scoped_ptr<ClientMalwareRequest> request(new ClientMalwareRequest());
99 request->set_url(url.spec());
100 csd_service_->SendClientReportMalwareRequest(
101 request.release(),
102 base::Bind(&ClientSideDetectionServiceTest::SendMalwareRequestDone,
103 base::Unretained(this)));
104 phishing_url_ = url;
105 msg_loop_.Run(); // Waits until callback is called.
106 return is_malware_;
107 }
108
SetModelFetchResponse(std::string response_data,net::HttpStatusCode response_code,net::URLRequestStatus::Status status)109 void SetModelFetchResponse(std::string response_data,
110 net::HttpStatusCode response_code,
111 net::URLRequestStatus::Status status) {
112 factory_->SetFakeResponse(GURL(ClientSideDetectionService::kClientModelUrl),
113 response_data, response_code, status);
114 }
115
SetClientReportPhishingResponse(std::string response_data,net::HttpStatusCode response_code,net::URLRequestStatus::Status status)116 void SetClientReportPhishingResponse(std::string response_data,
117 net::HttpStatusCode response_code,
118 net::URLRequestStatus::Status status) {
119 factory_->SetFakeResponse(
120 ClientSideDetectionService::GetClientReportUrl(
121 ClientSideDetectionService::kClientReportPhishingUrl),
122 response_data, response_code, status);
123 }
124
SetClientReportMalwareResponse(std::string response_data,net::HttpStatusCode response_code,net::URLRequestStatus::Status status)125 void SetClientReportMalwareResponse(std::string response_data,
126 net::HttpStatusCode response_code,
127 net::URLRequestStatus::Status status) {
128 factory_->SetFakeResponse(
129 ClientSideDetectionService::GetClientReportUrl(
130 ClientSideDetectionService::kClientReportMalwareUrl),
131 response_data, response_code, status);
132 }
133
GetNumReports(std::queue<base::Time> * report_times)134 int GetNumReports(std::queue<base::Time>* report_times) {
135 return csd_service_->GetNumReports(report_times);
136 }
137
GetPhishingReportTimes()138 std::queue<base::Time>& GetPhishingReportTimes() {
139 return csd_service_->phishing_report_times_;
140 }
141
GetMalwareReportTimes()142 std::queue<base::Time>& GetMalwareReportTimes() {
143 return csd_service_->malware_report_times_;
144 }
145
SetCache(const GURL & gurl,bool is_phishing,base::Time time)146 void SetCache(const GURL& gurl, bool is_phishing, base::Time time) {
147 csd_service_->cache_[gurl] =
148 make_linked_ptr(new ClientSideDetectionService::CacheState(is_phishing,
149 time));
150 }
151
TestCache()152 void TestCache() {
153 ClientSideDetectionService::PhishingCache& cache = csd_service_->cache_;
154 base::Time now = base::Time::Now();
155 base::Time time =
156 now - base::TimeDelta::FromDays(
157 ClientSideDetectionService::kNegativeCacheIntervalDays) +
158 base::TimeDelta::FromMinutes(5);
159 cache[GURL("http://first.url.com/")] =
160 make_linked_ptr(new ClientSideDetectionService::CacheState(false,
161 time));
162
163 time =
164 now - base::TimeDelta::FromDays(
165 ClientSideDetectionService::kNegativeCacheIntervalDays) -
166 base::TimeDelta::FromHours(1);
167 cache[GURL("http://second.url.com/")] =
168 make_linked_ptr(new ClientSideDetectionService::CacheState(false,
169 time));
170
171 time =
172 now - base::TimeDelta::FromMinutes(
173 ClientSideDetectionService::kPositiveCacheIntervalMinutes) -
174 base::TimeDelta::FromMinutes(5);
175 cache[GURL("http://third.url.com/")] =
176 make_linked_ptr(new ClientSideDetectionService::CacheState(true, time));
177
178 time =
179 now - base::TimeDelta::FromMinutes(
180 ClientSideDetectionService::kPositiveCacheIntervalMinutes) +
181 base::TimeDelta::FromMinutes(5);
182 cache[GURL("http://fourth.url.com/")] =
183 make_linked_ptr(new ClientSideDetectionService::CacheState(true, time));
184
185 csd_service_->UpdateCache();
186
187 // 3 elements should be in the cache, the first, third, and fourth.
188 EXPECT_EQ(3U, cache.size());
189 EXPECT_TRUE(cache.find(GURL("http://first.url.com/")) != cache.end());
190 EXPECT_TRUE(cache.find(GURL("http://third.url.com/")) != cache.end());
191 EXPECT_TRUE(cache.find(GURL("http://fourth.url.com/")) != cache.end());
192
193 // While 3 elements remain, only the first and the fourth are actually
194 // valid.
195 bool is_phishing;
196 EXPECT_TRUE(csd_service_->GetValidCachedResult(
197 GURL("http://first.url.com"), &is_phishing));
198 EXPECT_FALSE(is_phishing);
199 EXPECT_FALSE(csd_service_->GetValidCachedResult(
200 GURL("http://third.url.com"), &is_phishing));
201 EXPECT_TRUE(csd_service_->GetValidCachedResult(
202 GURL("http://fourth.url.com"), &is_phishing));
203 EXPECT_TRUE(is_phishing);
204 }
205
AddFeature(const std::string & name,double value,ClientPhishingRequest * request)206 void AddFeature(const std::string& name, double value,
207 ClientPhishingRequest* request) {
208 ClientPhishingRequest_Feature* feature = request->add_feature_map();
209 feature->set_name(name);
210 feature->set_value(value);
211 }
212
AddNonModelFeature(const std::string & name,double value,ClientPhishingRequest * request)213 void AddNonModelFeature(const std::string& name, double value,
214 ClientPhishingRequest* request) {
215 ClientPhishingRequest_Feature* feature =
216 request->add_non_model_feature_map();
217 feature->set_name(name);
218 feature->set_value(value);
219 }
220
CheckConfirmedMalwareUrl(GURL url)221 void CheckConfirmedMalwareUrl(GURL url) {
222 ASSERT_EQ(confirmed_malware_url_, url);
223 }
224
225 protected:
226 scoped_ptr<ClientSideDetectionService> csd_service_;
227 scoped_ptr<net::FakeURLFetcherFactory> factory_;
228 base::MessageLoop msg_loop_;
229
230 private:
SendRequestDone(GURL phishing_url,bool is_phishing)231 void SendRequestDone(GURL phishing_url, bool is_phishing) {
232 ASSERT_EQ(phishing_url, phishing_url_);
233 is_phishing_ = is_phishing;
234 msg_loop_.Quit();
235 }
236
SendMalwareRequestDone(GURL original_url,GURL malware_url,bool is_malware)237 void SendMalwareRequestDone(GURL original_url, GURL malware_url,
238 bool is_malware) {
239 ASSERT_EQ(phishing_url_, original_url);
240 confirmed_malware_url_ = malware_url;
241 is_malware_ = is_malware;
242 msg_loop_.Quit();
243 }
244
245 scoped_ptr<content::TestBrowserThread> browser_thread_;
246 scoped_ptr<content::TestBrowserThread> file_thread_;
247
248 GURL phishing_url_;
249 GURL confirmed_malware_url_;
250 bool is_phishing_;
251 bool is_malware_;
252 };
253
TEST_F(ClientSideDetectionServiceTest,FetchModelTest)254 TEST_F(ClientSideDetectionServiceTest, FetchModelTest) {
255 // We don't want to use a real service class here because we can't call
256 // the real EndFetchModel. It would reschedule a reload which might
257 // make the test flaky.
258 MockClientSideDetectionService service;
259 EXPECT_CALL(service, ScheduleFetchModel(_)).Times(1);
260 service.SetEnabledAndRefreshState(true);
261
262 // The model fetch failed.
263 SetModelFetchResponse("blamodel", net::HTTP_INTERNAL_SERVER_ERROR,
264 net::URLRequestStatus::FAILED);
265 EXPECT_CALL(service, EndFetchModel(
266 ClientSideDetectionService::MODEL_FETCH_FAILED))
267 .WillOnce(QuitCurrentMessageLoop());
268 service.StartFetchModel();
269 msg_loop_.Run(); // EndFetchModel will quit the message loop.
270 Mock::VerifyAndClearExpectations(&service);
271
272 // Empty model file.
273 SetModelFetchResponse(std::string(), net::HTTP_OK,
274 net::URLRequestStatus::SUCCESS);
275 EXPECT_CALL(service, EndFetchModel(ClientSideDetectionService::MODEL_EMPTY))
276 .WillOnce(QuitCurrentMessageLoop());
277 service.StartFetchModel();
278 msg_loop_.Run(); // EndFetchModel will quit the message loop.
279 Mock::VerifyAndClearExpectations(&service);
280
281 // Model is too large.
282 SetModelFetchResponse(
283 std::string(ClientSideDetectionService::kMaxModelSizeBytes + 1, 'x'),
284 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
285 EXPECT_CALL(service, EndFetchModel(
286 ClientSideDetectionService::MODEL_TOO_LARGE))
287 .WillOnce(QuitCurrentMessageLoop());
288 service.StartFetchModel();
289 msg_loop_.Run(); // EndFetchModel will quit the message loop.
290 Mock::VerifyAndClearExpectations(&service);
291
292 // Unable to parse the model file.
293 SetModelFetchResponse("Invalid model file", net::HTTP_OK,
294 net::URLRequestStatus::SUCCESS);
295 EXPECT_CALL(service, EndFetchModel(
296 ClientSideDetectionService::MODEL_PARSE_ERROR))
297 .WillOnce(QuitCurrentMessageLoop());
298 service.StartFetchModel();
299 msg_loop_.Run(); // EndFetchModel will quit the message loop.
300 Mock::VerifyAndClearExpectations(&service);
301
302 // Model that is missing some required fields (missing the version field).
303 ClientSideModel model;
304 model.set_max_words_per_term(4);
305 SetModelFetchResponse(model.SerializePartialAsString(), net::HTTP_OK,
306 net::URLRequestStatus::SUCCESS);
307 EXPECT_CALL(service, EndFetchModel(
308 ClientSideDetectionService::MODEL_MISSING_FIELDS))
309 .WillOnce(QuitCurrentMessageLoop());
310 service.StartFetchModel();
311 msg_loop_.Run(); // EndFetchModel will quit the message loop.
312 Mock::VerifyAndClearExpectations(&service);
313
314 // Model that points to hashes that don't exist.
315 model.set_version(10);
316 model.add_hashes("bla");
317 model.add_page_term(1); // Should be 0 instead of 1.
318 SetModelFetchResponse(model.SerializePartialAsString(), net::HTTP_OK,
319 net::URLRequestStatus::SUCCESS);
320 EXPECT_CALL(service, EndFetchModel(
321 ClientSideDetectionService::MODEL_BAD_HASH_IDS))
322 .WillOnce(QuitCurrentMessageLoop());
323 service.StartFetchModel();
324 msg_loop_.Run(); // EndFetchModel will quit the message loop.
325 Mock::VerifyAndClearExpectations(&service);
326 model.set_page_term(0, 0);
327
328 // Model version number is wrong.
329 model.set_version(-1);
330 SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
331 net::URLRequestStatus::SUCCESS);
332 EXPECT_CALL(service, EndFetchModel(
333 ClientSideDetectionService::MODEL_INVALID_VERSION_NUMBER))
334 .WillOnce(QuitCurrentMessageLoop());
335 service.StartFetchModel();
336 msg_loop_.Run(); // EndFetchModel will quit the message loop.
337 Mock::VerifyAndClearExpectations(&service);
338
339 // Normal model.
340 model.set_version(10);
341 SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
342 net::URLRequestStatus::SUCCESS);
343 EXPECT_CALL(service, EndFetchModel(
344 ClientSideDetectionService::MODEL_SUCCESS))
345 .WillOnce(QuitCurrentMessageLoop());
346 service.StartFetchModel();
347 msg_loop_.Run(); // EndFetchModel will quit the message loop.
348 Mock::VerifyAndClearExpectations(&service);
349
350 // Model version number is decreasing. Set the model version number of the
351 // model that is currently loaded in the service object to 11.
352 service.model_.reset(new ClientSideModel(model));
353 service.model_->set_version(11);
354 SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
355 net::URLRequestStatus::SUCCESS);
356 EXPECT_CALL(service, EndFetchModel(
357 ClientSideDetectionService::MODEL_INVALID_VERSION_NUMBER))
358 .WillOnce(QuitCurrentMessageLoop());
359 service.StartFetchModel();
360 msg_loop_.Run(); // EndFetchModel will quit the message loop.
361 Mock::VerifyAndClearExpectations(&service);
362
363 // Model version hasn't changed since the last reload.
364 service.model_->set_version(10);
365 SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
366 net::URLRequestStatus::SUCCESS);
367 EXPECT_CALL(service, EndFetchModel(
368 ClientSideDetectionService::MODEL_NOT_CHANGED))
369 .WillOnce(QuitCurrentMessageLoop());
370 service.StartFetchModel();
371 msg_loop_.Run(); // EndFetchModel will quit the message loop.
372 Mock::VerifyAndClearExpectations(&service);
373 }
374
TEST_F(ClientSideDetectionServiceTest,ServiceObjectDeletedBeforeCallbackDone)375 TEST_F(ClientSideDetectionServiceTest, ServiceObjectDeletedBeforeCallbackDone) {
376 SetModelFetchResponse("bogus model", net::HTTP_OK,
377 net::URLRequestStatus::SUCCESS);
378 csd_service_.reset(ClientSideDetectionService::Create(NULL));
379 csd_service_->SetEnabledAndRefreshState(true);
380 EXPECT_TRUE(csd_service_.get() != NULL);
381 // We delete the client-side detection service class even though the callbacks
382 // haven't run yet.
383 csd_service_.reset();
384 // Waiting for the callbacks to run should not crash even if the service
385 // object is gone.
386 msg_loop_.RunUntilIdle();
387 }
388
TEST_F(ClientSideDetectionServiceTest,SendClientReportPhishingRequest)389 TEST_F(ClientSideDetectionServiceTest, SendClientReportPhishingRequest) {
390 SetModelFetchResponse("bogus model", net::HTTP_OK,
391 net::URLRequestStatus::SUCCESS);
392 csd_service_.reset(ClientSideDetectionService::Create(NULL));
393 csd_service_->SetEnabledAndRefreshState(true);
394
395 GURL url("http://a.com/");
396 float score = 0.4f; // Some random client score.
397
398 base::Time before = base::Time::Now();
399
400 // Invalid response body from the server.
401 SetClientReportPhishingResponse("invalid proto response", net::HTTP_OK,
402 net::URLRequestStatus::SUCCESS);
403 EXPECT_FALSE(SendClientReportPhishingRequest(url, score));
404
405 // Normal behavior.
406 ClientPhishingResponse response;
407 response.set_phishy(true);
408 SetClientReportPhishingResponse(response.SerializeAsString(), net::HTTP_OK,
409 net::URLRequestStatus::SUCCESS);
410 EXPECT_TRUE(SendClientReportPhishingRequest(url, score));
411
412 // This request will fail
413 GURL second_url("http://b.com/");
414 response.set_phishy(false);
415 SetClientReportPhishingResponse(response.SerializeAsString(),
416 net::HTTP_INTERNAL_SERVER_ERROR,
417 net::URLRequestStatus::FAILED);
418 EXPECT_FALSE(SendClientReportPhishingRequest(second_url, score));
419
420 base::Time after = base::Time::Now();
421
422 // Check that we have recorded all 3 requests within the correct time range.
423 std::queue<base::Time>& report_times = GetPhishingReportTimes();
424 EXPECT_EQ(3U, report_times.size());
425 while (!report_times.empty()) {
426 base::Time time = report_times.back();
427 report_times.pop();
428 EXPECT_LE(before, time);
429 EXPECT_GE(after, time);
430 }
431
432 // Only the first url should be in the cache.
433 bool is_phishing;
434 EXPECT_TRUE(csd_service_->IsInCache(url));
435 EXPECT_TRUE(csd_service_->GetValidCachedResult(url, &is_phishing));
436 EXPECT_TRUE(is_phishing);
437 EXPECT_FALSE(csd_service_->IsInCache(second_url));
438 }
439
TEST_F(ClientSideDetectionServiceTest,SendClientReportMalwareRequest)440 TEST_F(ClientSideDetectionServiceTest, SendClientReportMalwareRequest) {
441 SetModelFetchResponse("bogus model", net::HTTP_OK,
442 net::URLRequestStatus::SUCCESS);
443 csd_service_.reset(ClientSideDetectionService::Create(NULL));
444 csd_service_->SetEnabledAndRefreshState(true);
445 GURL url("http://a.com/");
446
447 base::Time before = base::Time::Now();
448 // Invalid response body from the server.
449 SetClientReportMalwareResponse("invalid proto response", net::HTTP_OK,
450 net::URLRequestStatus::SUCCESS);
451 EXPECT_FALSE(SendClientReportMalwareRequest(url));
452
453 // Missing bad_url.
454 ClientMalwareResponse response;
455 response.set_blacklist(true);
456 SetClientReportMalwareResponse(response.SerializeAsString(), net::HTTP_OK,
457 net::URLRequestStatus::SUCCESS);
458 EXPECT_FALSE(SendClientReportMalwareRequest(url));
459
460 // Normal behavior.
461 response.set_blacklist(true);
462 response.set_bad_url("http://response-bad.com/");
463 SetClientReportMalwareResponse(response.SerializeAsString(), net::HTTP_OK,
464 net::URLRequestStatus::SUCCESS);
465 EXPECT_TRUE(SendClientReportMalwareRequest(url));
466 CheckConfirmedMalwareUrl(GURL("http://response-bad.com/"));
467
468 // This request will fail
469 response.set_blacklist(false);
470 SetClientReportMalwareResponse(response.SerializeAsString(),
471 net::HTTP_INTERNAL_SERVER_ERROR,
472 net::URLRequestStatus::FAILED);
473 EXPECT_FALSE(SendClientReportMalwareRequest(url));
474
475 // Server blacklist decision is false, and response is successful
476 response.set_blacklist(false);
477 SetClientReportMalwareResponse(response.SerializeAsString(), net::HTTP_OK,
478 net::URLRequestStatus::SUCCESS);
479 EXPECT_FALSE(SendClientReportMalwareRequest(url));
480
481 // Check that we have recorded all 5 requests within the correct time range.
482 base::Time after = base::Time::Now();
483 std::queue<base::Time>& report_times = GetMalwareReportTimes();
484 EXPECT_EQ(5U, report_times.size());
485
486 // Check that the malware report limit was reached.
487 EXPECT_TRUE(csd_service_->OverMalwareReportLimit());
488
489 report_times = GetMalwareReportTimes();
490 EXPECT_EQ(5U, report_times.size());
491 while (!report_times.empty()) {
492 base::Time time = report_times.back();
493 report_times.pop();
494 EXPECT_LE(before, time);
495 EXPECT_GE(after, time);
496 }
497 }
498
TEST_F(ClientSideDetectionServiceTest,GetNumReportTest)499 TEST_F(ClientSideDetectionServiceTest, GetNumReportTest) {
500 SetModelFetchResponse("bogus model", net::HTTP_OK,
501 net::URLRequestStatus::SUCCESS);
502 csd_service_.reset(ClientSideDetectionService::Create(NULL));
503
504 std::queue<base::Time>& report_times = GetPhishingReportTimes();
505 base::Time now = base::Time::Now();
506 base::TimeDelta twenty_five_hours = base::TimeDelta::FromHours(25);
507 report_times.push(now - twenty_five_hours);
508 report_times.push(now - twenty_five_hours);
509 report_times.push(now);
510 report_times.push(now);
511
512 EXPECT_EQ(2, GetNumReports(&report_times));
513 }
514
TEST_F(ClientSideDetectionServiceTest,CacheTest)515 TEST_F(ClientSideDetectionServiceTest, CacheTest) {
516 SetModelFetchResponse("bogus model", net::HTTP_OK,
517 net::URLRequestStatus::SUCCESS);
518 csd_service_.reset(ClientSideDetectionService::Create(NULL));
519
520 TestCache();
521 }
522
TEST_F(ClientSideDetectionServiceTest,IsPrivateIPAddress)523 TEST_F(ClientSideDetectionServiceTest, IsPrivateIPAddress) {
524 SetModelFetchResponse("bogus model", net::HTTP_OK,
525 net::URLRequestStatus::SUCCESS);
526 csd_service_.reset(ClientSideDetectionService::Create(NULL));
527
528 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("10.1.2.3"));
529 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("127.0.0.1"));
530 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("172.24.3.4"));
531 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("192.168.1.1"));
532 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fc00::"));
533 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0::"));
534 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0:1:2::3"));
535 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("::1"));
536
537 EXPECT_FALSE(csd_service_->IsPrivateIPAddress("1.2.3.4"));
538 EXPECT_FALSE(csd_service_->IsPrivateIPAddress("200.1.1.1"));
539 EXPECT_FALSE(csd_service_->IsPrivateIPAddress("2001:0db8:ac10:fe01::"));
540
541 // If the address can't be parsed, the default is true.
542 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("blah"));
543 }
544
TEST_F(ClientSideDetectionServiceTest,SetBadSubnets)545 TEST_F(ClientSideDetectionServiceTest, SetBadSubnets) {
546 ClientSideModel model;
547 ClientSideDetectionService::BadSubnetMap bad_subnets;
548 ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
549 EXPECT_EQ(0U, bad_subnets.size());
550
551 // Bad subnets are skipped.
552 ClientSideModel::IPSubnet* subnet = model.add_bad_subnet();
553 subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
554 subnet->set_size(130); // Invalid size.
555
556 subnet = model.add_bad_subnet();
557 subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
558 subnet->set_size(-1); // Invalid size.
559
560 subnet = model.add_bad_subnet();
561 subnet->set_prefix(std::string(16, '.')); // Invalid len.
562 subnet->set_size(64);
563
564 ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
565 EXPECT_EQ(0U, bad_subnets.size());
566
567 subnet = model.add_bad_subnet();
568 subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
569 subnet->set_size(64);
570
571 subnet = model.add_bad_subnet();
572 subnet->set_prefix(std::string(crypto::kSHA256Length, ','));
573 subnet->set_size(64);
574
575 subnet = model.add_bad_subnet();
576 subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
577 subnet->set_size(128);
578
579 subnet = model.add_bad_subnet();
580 subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
581 subnet->set_size(100);
582
583 ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
584 EXPECT_EQ(3U, bad_subnets.size());
585 ClientSideDetectionService::BadSubnetMap::const_iterator it;
586 std::string mask = std::string(8, '\xFF') + std::string(8, '\x00');
587 EXPECT_TRUE(bad_subnets.count(mask));
588 EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
589 EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, ',')));
590
591 mask = std::string(16, '\xFF');
592 EXPECT_TRUE(bad_subnets.count(mask));
593 EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
594
595 mask = std::string(12, '\xFF') + "\xF0" + std::string(3, '\x00');
596 EXPECT_TRUE(bad_subnets.count(mask));
597 EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
598 }
599
TEST_F(ClientSideDetectionServiceTest,ModelHasValidHashIds)600 TEST_F(ClientSideDetectionServiceTest, ModelHasValidHashIds) {
601 ClientSideModel model;
602 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
603 model.add_hashes("bla");
604 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
605 model.add_page_term(0);
606 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
607
608 model.add_page_term(-1);
609 EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
610 model.set_page_term(1, 1);
611 EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
612 model.set_page_term(1, 0);
613 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
614
615 // Test bad rules.
616 model.add_hashes("blu");
617 ClientSideModel::Rule* rule = model.add_rule();
618 rule->add_feature(0);
619 rule->add_feature(1);
620 rule->set_weight(0.1f);
621 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
622
623 rule = model.add_rule();
624 rule->add_feature(0);
625 rule->add_feature(1);
626 rule->add_feature(-1);
627 rule->set_weight(0.2f);
628 EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
629
630 rule->set_feature(2, 2);
631 EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
632
633 rule->set_feature(2, 1);
634 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
635 }
636
TEST_F(ClientSideDetectionServiceTest,SetEnabledAndRefreshState)637 TEST_F(ClientSideDetectionServiceTest, SetEnabledAndRefreshState) {
638 // Check that the model isn't downloaded until the service is enabled.
639 csd_service_.reset(ClientSideDetectionService::Create(NULL));
640 EXPECT_FALSE(csd_service_->enabled());
641 EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
642
643 // Use a MockClientSideDetectionService for the rest of the test, to avoid
644 // the scheduling delay.
645 MockClientSideDetectionService* service =
646 new StrictMock<MockClientSideDetectionService>();
647 csd_service_.reset(service);
648 EXPECT_FALSE(csd_service_->enabled());
649 EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
650 // No calls expected yet.
651 Mock::VerifyAndClearExpectations(service);
652
653 ClientSideModel model;
654 model.set_version(10);
655 model.set_max_words_per_term(4);
656 SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
657 net::URLRequestStatus::SUCCESS);
658 EXPECT_CALL(*service, ScheduleFetchModel(_))
659 .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
660 EXPECT_CALL(*service, EndFetchModel(
661 ClientSideDetectionService::MODEL_SUCCESS))
662 .WillOnce(QuitCurrentMessageLoop());
663 csd_service_->SetEnabledAndRefreshState(true);
664 EXPECT_TRUE(csd_service_->model_fetcher_.get() != NULL);
665 msg_loop_.Run(); // EndFetchModel will quit the message loop.
666 Mock::VerifyAndClearExpectations(service);
667
668 // Check that enabling again doesn't request the model.
669 csd_service_->SetEnabledAndRefreshState(true);
670 // No calls expected.
671 Mock::VerifyAndClearExpectations(service);
672
673 // Check that disabling the service cancels pending requests.
674 EXPECT_CALL(*service, ScheduleFetchModel(_))
675 .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
676 csd_service_->SetEnabledAndRefreshState(false);
677 csd_service_->SetEnabledAndRefreshState(true);
678 Mock::VerifyAndClearExpectations(service);
679 EXPECT_TRUE(csd_service_->model_fetcher_.get() != NULL);
680 csd_service_->SetEnabledAndRefreshState(false);
681 EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
682 msg_loop_.RunUntilIdle();
683 // No calls expected.
684 Mock::VerifyAndClearExpectations(service);
685
686 // Requests always return false when the service is disabled.
687 ClientPhishingResponse response;
688 response.set_phishy(true);
689 SetClientReportPhishingResponse(response.SerializeAsString(), net::HTTP_OK,
690 net::URLRequestStatus::SUCCESS);
691 EXPECT_FALSE(SendClientReportPhishingRequest(GURL("http://a.com/"), 0.4f));
692
693 // Pending requests also return false if the service is disabled before they
694 // report back.
695 EXPECT_CALL(*service, ScheduleFetchModel(_))
696 .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
697 EXPECT_CALL(*service, EndFetchModel(
698 ClientSideDetectionService::MODEL_NOT_CHANGED))
699 .WillOnce(Invoke(service, &MockClientSideDetectionService::Disable));
700 csd_service_->SetEnabledAndRefreshState(true);
701 EXPECT_FALSE(SendClientReportPhishingRequest(GURL("http://a.com/"), 0.4f));
702 Mock::VerifyAndClearExpectations(service);
703 }
704 } // namespace safe_browsing
705