This source file includes following definitions.
- MATCHER_P
- MATCHER_P
- MATCHER
- ACTION
- ACTION_TEMPLATE
- ACTION_P
- EmptyUrlCheckCallback
- InvokeOnBlockingPageComplete
- SetUp
- TearDown
- CreateBrowserContext
- OnPhishingDetectionDone
- DidStopLoading
- UpdateIPUrlMap
- GetBrowseInfo
- ExpectPreClassificationChecks
- WaitAndCheckPreClassificationChecks
- SetFeatureExtractor
- SetRedirectChain
- SetReferrer
- ExpectShouldClassifyForMalwareResult
- ExpectStartPhishingDetection
- TestUnsafeResourceCopied
- SetUnsafeSubResourceForCurrent
- NavigateWithSBHitAndCommit
- NavigateWithoutSBHitAndCommit
- CheckIPUrlEqual
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
#include "chrome/browser/safe_browsing/browser_feature_extractor.h"
#include "chrome/browser/safe_browsing/client_side_detection_host.h"
#include "chrome/browser/safe_browsing/client_side_detection_service.h"
#include "chrome/browser/safe_browsing/database_manager.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/safe_browsing/ui_manager.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/safe_browsing/csd.pb.h"
#include "chrome/common/safe_browsing/safebrowsing_messages.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_thread.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "ipc/ipc_test_sink.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using ::testing::_;
using ::testing::DeleteArg;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::IsNull;
using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::NotNull;
using ::testing::Pointee;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgumentPointee;
using ::testing::StrictMock;
using content::BrowserThread;
using content::RenderViewHostTester;
using content::WebContents;
namespace {
const bool kFalse = false;
const bool kTrue = true;
}
namespace safe_browsing {
namespace {
MATCHER_P(PartiallyEqualVerdict, other, "") {
return (other.url() == arg.url() &&
other.client_score() == arg.client_score() &&
other.is_phishing() == arg.is_phishing());
}
MATCHER_P(PartiallyEqualMalwareVerdict, other, "") {
if (other.url() != arg.url() ||
other.referrer_url() != arg.referrer_url() ||
other.bad_ip_url_info_size() != arg.bad_ip_url_info_size())
return false;
for (int i = 0; i < other.bad_ip_url_info_size(); ++i) {
if (other.bad_ip_url_info(i).ip() != arg.bad_ip_url_info(i).ip() ||
other.bad_ip_url_info(i).url() != arg.bad_ip_url_info(i).url())
return false;
}
return true;
}
MATCHER(CallbackIsNull, "") {
return arg.is_null();
}
ACTION(QuitUIMessageLoop) {
EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::MessageLoopForUI::current()->Quit();
}
ACTION_TEMPLATE(InvokeCallbackArgument,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_2_VALUE_PARAMS(p0, p1)) {
::std::tr1::get<k>(args).Run(p0, p1);
}
ACTION_P(InvokeMalwareCallback, verdict) {
scoped_ptr<ClientMalwareRequest> request(::std::tr1::get<1>(args));
request->CopyFrom(*verdict);
::std::tr1::get<2>(args).Run(true, request.Pass());
}
void EmptyUrlCheckCallback(bool processed) {
}
class MockClientSideDetectionService : public ClientSideDetectionService {
public:
MockClientSideDetectionService() : ClientSideDetectionService(NULL) {}
virtual ~MockClientSideDetectionService() {};
MOCK_METHOD2(SendClientReportPhishingRequest,
void(ClientPhishingRequest*,
const ClientReportPhishingRequestCallback&));
MOCK_METHOD2(SendClientReportMalwareRequest,
void(ClientMalwareRequest*,
const ClientReportMalwareRequestCallback&));
MOCK_CONST_METHOD1(IsPrivateIPAddress, bool(const std::string&));
MOCK_METHOD2(GetValidCachedResult, bool(const GURL&, bool*));
MOCK_METHOD1(IsInCache, bool(const GURL&));
MOCK_METHOD0(OverPhishingReportLimit, bool());
MOCK_METHOD0(OverMalwareReportLimit, bool());
private:
DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
};
class MockSafeBrowsingUIManager : public SafeBrowsingUIManager {
public:
explicit MockSafeBrowsingUIManager(SafeBrowsingService* service)
: SafeBrowsingUIManager(service) { }
MOCK_METHOD1(DisplayBlockingPage, void(const UnsafeResource& resource));
void InvokeOnBlockingPageComplete(const UrlCheckCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!callback.is_null())
callback.Run(false);
}
protected:
virtual ~MockSafeBrowsingUIManager() { }
private:
DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingUIManager);
};
class MockSafeBrowsingDatabaseManager : public SafeBrowsingDatabaseManager {
public:
explicit MockSafeBrowsingDatabaseManager(SafeBrowsingService* service)
: SafeBrowsingDatabaseManager(service) { }
MOCK_METHOD1(MatchCsdWhitelistUrl, bool(const GURL&));
MOCK_METHOD1(MatchMalwareIP, bool(const std::string& ip_address));
MOCK_METHOD0(IsMalwareKillSwitchOn, bool());
protected:
virtual ~MockSafeBrowsingDatabaseManager() {}
private:
DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager);
};
class MockTestingProfile : public TestingProfile {
public:
MockTestingProfile() {}
virtual ~MockTestingProfile() {}
MOCK_CONST_METHOD0(IsOffTheRecord, bool());
};
class MockBrowserFeatureExtractor : public BrowserFeatureExtractor {
public:
explicit MockBrowserFeatureExtractor(
WebContents* tab,
ClientSideDetectionHost* host)
: BrowserFeatureExtractor(tab, host) {}
virtual ~MockBrowserFeatureExtractor() {}
MOCK_METHOD3(ExtractFeatures,
void(const BrowseInfo*,
ClientPhishingRequest*,
const BrowserFeatureExtractor::DoneCallback&));
MOCK_METHOD3(ExtractMalwareFeatures,
void(BrowseInfo*,
ClientMalwareRequest*,
const BrowserFeatureExtractor::MalwareDoneCallback&));
};
}
class ClientSideDetectionHostTest : public ChromeRenderViewHostTestHarness {
public:
typedef SafeBrowsingUIManager::UnsafeResource UnsafeResource;
virtual void SetUp() {
ChromeRenderViewHostTestHarness::SetUp();
csd_service_.reset(new StrictMock<MockClientSideDetectionService>());
SafeBrowsingService* sb_service =
SafeBrowsingService::CreateSafeBrowsingService();
database_manager_ =
new StrictMock<MockSafeBrowsingDatabaseManager>(sb_service);
ui_manager_ = new StrictMock<MockSafeBrowsingUIManager>(sb_service);
csd_host_.reset(safe_browsing::ClientSideDetectionHost::Create(
web_contents()));
csd_host_->set_client_side_detection_service(csd_service_.get());
csd_host_->set_safe_browsing_managers(ui_manager_.get(),
database_manager_.get());
csd_host_->browse_info_.reset(new BrowseInfo);
}
virtual void TearDown() {
BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE,
csd_host_.release());
database_manager_ = NULL;
ui_manager_ = NULL;
base::RunLoop().RunUntilIdle();
ChromeRenderViewHostTestHarness::TearDown();
}
virtual content::BrowserContext* CreateBrowserContext() OVERRIDE {
mock_profile_ = new NiceMock<MockTestingProfile>();
return mock_profile_;
}
void OnPhishingDetectionDone(const std::string& verdict_str) {
csd_host_->OnPhishingDetectionDone(verdict_str);
}
void DidStopLoading() {
csd_host_->DidStopLoading(pending_rvh());
}
void UpdateIPUrlMap(const std::string& ip, const std::string& host) {
csd_host_->UpdateIPUrlMap(ip, host, "", "", ResourceType::OBJECT);
}
BrowseInfo* GetBrowseInfo() {
return csd_host_->browse_info_.get();
}
void ExpectPreClassificationChecks(const GURL& url,
const bool* is_private,
const bool* is_incognito,
const bool* match_csd_whitelist,
const bool* malware_killswitch,
const bool* get_valid_cached_result,
const bool* is_in_cache,
const bool* over_phishing_report_limit,
const bool* over_malware_report_limit) {
if (is_private) {
EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_))
.WillOnce(Return(*is_private));
}
if (is_incognito) {
EXPECT_CALL(*mock_profile_, IsOffTheRecord())
.WillRepeatedly(Return(*is_incognito));
}
if (match_csd_whitelist) {
EXPECT_CALL(*database_manager_.get(), MatchCsdWhitelistUrl(url))
.WillOnce(Return(*match_csd_whitelist));
}
if (malware_killswitch) {
EXPECT_CALL(*database_manager_.get(), IsMalwareKillSwitchOn())
.WillRepeatedly(Return(*malware_killswitch));
}
if (get_valid_cached_result) {
EXPECT_CALL(*csd_service_, GetValidCachedResult(url, NotNull()))
.WillOnce(DoAll(SetArgumentPointee<1>(true),
Return(*get_valid_cached_result)));
}
if (is_in_cache) {
EXPECT_CALL(*csd_service_, IsInCache(url)).WillOnce(Return(*is_in_cache));
}
if (over_phishing_report_limit) {
EXPECT_CALL(*csd_service_, OverPhishingReportLimit())
.WillOnce(Return(*over_phishing_report_limit));
}
if (over_malware_report_limit) {
EXPECT_CALL(*csd_service_, OverMalwareReportLimit())
.WillOnce(Return(*over_malware_report_limit));
}
}
void WaitAndCheckPreClassificationChecks() {
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
EXPECT_TRUE(Mock::VerifyAndClear(database_manager_.get()));
EXPECT_TRUE(Mock::VerifyAndClear(mock_profile_));
}
void SetFeatureExtractor(BrowserFeatureExtractor* extractor) {
csd_host_->feature_extractor_.reset(extractor);
}
void SetRedirectChain(const std::vector<GURL>& redirect_chain) {
csd_host_->browse_info_->url_redirects = redirect_chain;
}
void SetReferrer(const GURL& referrer) {
csd_host_->browse_info_->referrer = referrer;
}
void ExpectShouldClassifyForMalwareResult(bool should_classify) {
EXPECT_EQ(should_classify, csd_host_->should_classify_for_malware_);
}
void ExpectStartPhishingDetection(const GURL* url) {
const IPC::Message* msg = process()->sink().GetFirstMessageMatching(
SafeBrowsingMsg_StartPhishingDetection::ID);
if (url) {
ASSERT_TRUE(msg);
Tuple1<GURL> actual_url;
SafeBrowsingMsg_StartPhishingDetection::Read(msg, &actual_url);
EXPECT_EQ(*url, actual_url.a);
EXPECT_EQ(rvh()->GetRoutingID(), msg->routing_id());
process()->sink().ClearMessages();
} else {
ASSERT_FALSE(msg);
}
}
void TestUnsafeResourceCopied(const UnsafeResource& resource) {
ASSERT_TRUE(csd_host_->unsafe_resource_.get());
EXPECT_EQ(resource.url, csd_host_->unsafe_resource_->url);
EXPECT_EQ(resource.original_url, csd_host_->unsafe_resource_->original_url);
EXPECT_EQ(resource.is_subresource,
csd_host_->unsafe_resource_->is_subresource);
EXPECT_EQ(resource.threat_type, csd_host_->unsafe_resource_->threat_type);
EXPECT_TRUE(csd_host_->unsafe_resource_->callback.is_null());
EXPECT_EQ(resource.render_process_host_id,
csd_host_->unsafe_resource_->render_process_host_id);
EXPECT_EQ(resource.render_view_id,
csd_host_->unsafe_resource_->render_view_id);
}
void SetUnsafeSubResourceForCurrent() {
UnsafeResource resource;
resource.url = GURL("http://www.malware.com/");
resource.original_url = web_contents()->GetURL();
resource.is_subresource = true;
resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
resource.callback = base::Bind(&EmptyUrlCheckCallback);
resource.render_process_host_id = web_contents()->GetRenderProcessHost()->
GetID();
resource.render_view_id =
web_contents()->GetRenderViewHost()->GetRoutingID();
ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
csd_host_->OnSafeBrowsingMatch(resource);
ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
csd_host_->OnSafeBrowsingHit(resource);
ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
resource.callback.Reset();
ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
TestUnsafeResourceCopied(resource);
}
void NavigateWithSBHitAndCommit(const GURL& url) {
controller().LoadURL(
url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
ASSERT_TRUE(pending_rvh());
if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
pending_rvh()->GetProcess()->GetID()) {
EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
pending_rvh()->GetRoutingID());
}
UnsafeResource resource;
resource.url = url;
resource.original_url = url;
resource.is_subresource = false;
resource.threat_type = SB_THREAT_TYPE_URL_MALWARE;
resource.callback = base::Bind(&EmptyUrlCheckCallback);
resource.render_process_host_id = pending_rvh()->GetProcess()->GetID();
resource.render_view_id = pending_rvh()->GetRoutingID();
csd_host_->OnSafeBrowsingMatch(resource);
csd_host_->OnSafeBrowsingHit(resource);
resource.callback.Reset();
ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
ASSERT_TRUE(csd_host_->DidPageReceiveSafeBrowsingMatch());
ASSERT_TRUE(csd_host_->DidShowSBInterstitial());
TestUnsafeResourceCopied(resource);
}
void NavigateWithoutSBHitAndCommit(const GURL& safe_url) {
controller().LoadURL(
safe_url, content::Referrer(), content::PAGE_TRANSITION_LINK,
std::string());
ASSERT_TRUE(pending_rvh());
if (web_contents()->GetRenderViewHost()->GetProcess()->GetID() ==
pending_rvh()->GetProcess()->GetID()) {
EXPECT_NE(web_contents()->GetRenderViewHost()->GetRoutingID(),
pending_rvh()->GetRoutingID());
}
ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
ASSERT_FALSE(csd_host_->DidPageReceiveSafeBrowsingMatch());
ASSERT_FALSE(csd_host_->DidShowSBInterstitial());
}
void CheckIPUrlEqual(const std::vector<IPUrlInfo>& expect,
const std::vector<IPUrlInfo>& result) {
ASSERT_EQ(expect.size(), result.size());
for (unsigned int i = 0; i < expect.size(); ++i) {
EXPECT_EQ(expect[i].url, result[i].url);
EXPECT_EQ(expect[i].method, result[i].method);
EXPECT_EQ(expect[i].referrer, result[i].referrer);
EXPECT_EQ(expect[i].resource_type, result[i].resource_type);
}
}
protected:
scoped_ptr<ClientSideDetectionHost> csd_host_;
scoped_ptr<StrictMock<MockClientSideDetectionService> > csd_service_;
scoped_refptr<StrictMock<MockSafeBrowsingUIManager> > ui_manager_;
scoped_refptr<StrictMock<MockSafeBrowsingDatabaseManager> > database_manager_;
MockTestingProfile* mock_profile_;
};
TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneInvalidVerdict) {
MockBrowserFeatureExtractor* mock_extractor =
new StrictMock<MockBrowserFeatureExtractor>(
web_contents(),
csd_host_.get());
SetFeatureExtractor(mock_extractor);
EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
OnPhishingDetectionDone("Invalid Protocol Buffer");
EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
}
TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneNotPhishing) {
MockBrowserFeatureExtractor* mock_extractor =
new StrictMock<MockBrowserFeatureExtractor>(
web_contents(),
csd_host_.get());
SetFeatureExtractor(mock_extractor);
ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
ClientPhishingRequest verdict;
verdict.set_url("http://phishingurl.com/");
verdict.set_client_score(1.0f);
verdict.set_is_phishing(true);
EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
.WillOnce(DoAll(DeleteArg<1>(),
InvokeCallbackArgument<2>(true, &verdict)));
EXPECT_CALL(*csd_service_,
SendClientReportPhishingRequest(
Pointee(PartiallyEqualVerdict(verdict)), _))
.WillOnce(SaveArg<1>(&cb));
OnPhishingDetectionDone(verdict.SerializeAsString());
EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
ASSERT_FALSE(cb.is_null());
EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_)).Times(0);
cb.Run(GURL(verdict.url()), false);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
}
TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneDisabled) {
MockBrowserFeatureExtractor* mock_extractor =
new StrictMock<MockBrowserFeatureExtractor>(
web_contents(),
csd_host_.get());
SetFeatureExtractor(mock_extractor);
ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
ClientPhishingRequest verdict;
verdict.set_url("http://phishingurl.com/");
verdict.set_client_score(1.0f);
verdict.set_is_phishing(true);
EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
.WillOnce(DoAll(DeleteArg<1>(),
InvokeCallbackArgument<2>(true, &verdict)));
EXPECT_CALL(*csd_service_,
SendClientReportPhishingRequest(
Pointee(PartiallyEqualVerdict(verdict)), _))
.WillOnce(SaveArg<1>(&cb));
OnPhishingDetectionDone(verdict.SerializeAsString());
EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
ASSERT_FALSE(cb.is_null());
EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_)).Times(0);
cb.Run(GURL(verdict.url()), false);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
}
TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneShowInterstitial) {
MockBrowserFeatureExtractor* mock_extractor =
new StrictMock<MockBrowserFeatureExtractor>(
web_contents(),
csd_host_.get());
SetFeatureExtractor(mock_extractor);
ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
GURL phishing_url("http://phishingurl.com/");
ClientPhishingRequest verdict;
verdict.set_url(phishing_url.spec());
verdict.set_client_score(1.0f);
verdict.set_is_phishing(true);
EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
.WillOnce(DoAll(DeleteArg<1>(),
InvokeCallbackArgument<2>(true, &verdict)));
EXPECT_CALL(*csd_service_,
SendClientReportPhishingRequest(
Pointee(PartiallyEqualVerdict(verdict)), _))
.WillOnce(SaveArg<1>(&cb));
OnPhishingDetectionDone(verdict.SerializeAsString());
EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
ASSERT_FALSE(cb.is_null());
UnsafeResource resource;
EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
.WillOnce(SaveArg<0>(&resource));
cb.Run(phishing_url, true);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
EXPECT_EQ(phishing_url, resource.url);
EXPECT_EQ(phishing_url, resource.original_url);
EXPECT_FALSE(resource.is_subresource);
EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL, resource.threat_type);
EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
resource.render_process_host_id);
EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
resource.render_view_id);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
ui_manager_, resource.callback));
}
TEST_F(ClientSideDetectionHostTest, OnPhishingDetectionDoneMultiplePings) {
MockBrowserFeatureExtractor* mock_extractor =
new StrictMock<MockBrowserFeatureExtractor>(
web_contents(),
csd_host_.get());
SetFeatureExtractor(mock_extractor);
ClientSideDetectionService::ClientReportPhishingRequestCallback cb;
GURL phishing_url("http://phishingurl.com/");
ClientPhishingRequest verdict;
verdict.set_url(phishing_url.spec());
verdict.set_client_score(1.0f);
verdict.set_is_phishing(true);
EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _))
.WillOnce(DoAll(DeleteArg<1>(),
InvokeCallbackArgument<2>(true, &verdict)));
EXPECT_CALL(*csd_service_,
SendClientReportPhishingRequest(
Pointee(PartiallyEqualVerdict(verdict)), _))
.WillOnce(SaveArg<1>(&cb));
OnPhishingDetectionDone(verdict.SerializeAsString());
EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
ASSERT_FALSE(cb.is_null());
SetFeatureExtractor(new BrowserFeatureExtractor(web_contents(),
csd_host_.get()));
GURL other_phishing_url("http://other_phishing_url.com/bla");
ExpectPreClassificationChecks(other_phishing_url, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse, &kFalse);
NavigateAndCommit(other_phishing_url);
WaitAndCheckPreClassificationChecks();
ClientSideDetectionService::ClientReportPhishingRequestCallback cb_other;
verdict.set_url(other_phishing_url.spec());
verdict.set_client_score(0.8f);
EXPECT_CALL(*csd_service_,
SendClientReportPhishingRequest(
Pointee(PartiallyEqualVerdict(verdict)), _))
.WillOnce(DoAll(DeleteArg<0>(),
SaveArg<1>(&cb_other),
QuitUIMessageLoop()));
std::vector<GURL> redirect_chain;
redirect_chain.push_back(other_phishing_url);
SetRedirectChain(redirect_chain);
OnPhishingDetectionDone(verdict.SerializeAsString());
base::MessageLoop::current()->Run();
EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
ASSERT_FALSE(cb_other.is_null());
UnsafeResource resource;
EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
.WillOnce(SaveArg<0>(&resource));
cb.Run(phishing_url, true);
cb_other.Run(other_phishing_url, true);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
EXPECT_EQ(other_phishing_url, resource.url);
EXPECT_EQ(other_phishing_url, resource.original_url);
EXPECT_FALSE(resource.is_subresource);
EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL, resource.threat_type);
EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
resource.render_process_host_id);
EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
resource.render_view_id);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
ui_manager_, resource.callback));
}
TEST_F(ClientSideDetectionHostTest,
OnPhishingDetectionDoneVerdictNotPhishing) {
MockBrowserFeatureExtractor* mock_extractor =
new StrictMock<MockBrowserFeatureExtractor>(
web_contents(),
csd_host_.get());
SetFeatureExtractor(mock_extractor);
ClientPhishingRequest verdict;
verdict.set_url("http://not-phishing.com/");
verdict.set_client_score(0.1f);
verdict.set_is_phishing(false);
EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _, _)).Times(0);
OnPhishingDetectionDone(verdict.SerializeAsString());
EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
}
TEST_F(ClientSideDetectionHostTest,
OnPhishingDetectionDoneVerdictNotPhishingButSBMatchSubResource) {
GURL url("http://not-phishing.com/");
ClientPhishingRequest verdict;
verdict.set_url(url.spec());
verdict.set_client_score(0.1f);
verdict.set_is_phishing(false);
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
SetUnsafeSubResourceForCurrent();
EXPECT_CALL(*csd_service_,
SendClientReportPhishingRequest(
Pointee(PartiallyEqualVerdict(verdict)), CallbackIsNull()))
.WillOnce(DoAll(DeleteArg<0>(), QuitUIMessageLoop()));
std::vector<GURL> redirect_chain;
redirect_chain.push_back(url);
SetRedirectChain(redirect_chain);
OnPhishingDetectionDone(verdict.SerializeAsString());
base::MessageLoop::current()->Run();
EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
}
TEST_F(ClientSideDetectionHostTest,
OnPhishingDetectionDoneVerdictNotPhishingButSBMatchOnNewRVH) {
GURL start_url("http://safe.example.com/");
ExpectPreClassificationChecks(
start_url, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse);
NavigateAndCommit(start_url);
WaitAndCheckPreClassificationChecks();
GURL url("http://malware-but-not-phishing.com/");
ClientPhishingRequest verdict;
verdict.set_url(url.spec());
verdict.set_client_score(0.1f);
verdict.set_is_phishing(false);
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse);
NavigateWithSBHitAndCommit(url);
WaitAndCheckPreClassificationChecks();
EXPECT_CALL(*csd_service_,
SendClientReportPhishingRequest(
Pointee(PartiallyEqualVerdict(verdict)), CallbackIsNull()))
.WillOnce(DoAll(DeleteArg<0>(), QuitUIMessageLoop()));
std::vector<GURL> redirect_chain;
redirect_chain.push_back(url);
SetRedirectChain(redirect_chain);
OnPhishingDetectionDone(verdict.SerializeAsString());
base::MessageLoop::current()->Run();
EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
ExpectPreClassificationChecks(start_url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse);
NavigateWithoutSBHitAndCommit(start_url);
WaitAndCheckPreClassificationChecks();
}
TEST_F(ClientSideDetectionHostTest,
DidStopLoadingShowMalwareInterstitial) {
MockBrowserFeatureExtractor* mock_extractor =
new StrictMock<MockBrowserFeatureExtractor>(
web_contents(),
csd_host_.get());
SetFeatureExtractor(mock_extractor);
GURL malware_landing_url("http://malware.com/");
GURL malware_ip_url("http://badip.com");
ClientMalwareRequest malware_verdict;
malware_verdict.set_url("http://malware.com/");
ClientMalwareRequest::UrlInfo* badipurl =
malware_verdict.add_bad_ip_url_info();
badipurl->set_ip("1.2.3.4");
badipurl->set_url("http://badip.com");
ExpectPreClassificationChecks(GURL(malware_verdict.url()), &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse);
NavigateAndCommit(GURL(malware_verdict.url()));
WaitAndCheckPreClassificationChecks();
ClientSideDetectionService::ClientReportMalwareRequestCallback cb;
EXPECT_CALL(*mock_extractor, ExtractMalwareFeatures(_, _, _))
.WillOnce(InvokeMalwareCallback(&malware_verdict));
EXPECT_CALL(*csd_service_,
SendClientReportMalwareRequest(
Pointee(PartiallyEqualMalwareVerdict(malware_verdict)), _))
.WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
DidStopLoading();
EXPECT_TRUE(Mock::VerifyAndClear(csd_host_.get()));
EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
ASSERT_FALSE(cb.is_null());
UnsafeResource resource;
EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
.WillOnce(SaveArg<0>(&resource));
cb.Run(malware_landing_url, malware_ip_url, true);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(Mock::VerifyAndClear(ui_manager_.get()));
EXPECT_EQ(malware_ip_url, resource.url);
EXPECT_EQ(malware_landing_url, resource.original_url);
EXPECT_TRUE(resource.is_subresource);
EXPECT_EQ(SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL, resource.threat_type);
EXPECT_EQ(web_contents()->GetRenderProcessHost()->GetID(),
resource.render_process_host_id);
EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(),
resource.render_view_id);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
ui_manager_, resource.callback));
}
TEST_F(ClientSideDetectionHostTest, UpdateIPUrlMap) {
BrowseInfo* browse_info = GetBrowseInfo();
UpdateIPUrlMap("250.10.10.10", std::string());
ASSERT_EQ(0U, browse_info->ips.size());
UpdateIPUrlMap(std::string(), "http://google.com/a");
ASSERT_EQ(0U, browse_info->ips.size());
UpdateIPUrlMap(std::string(), std::string());
ASSERT_EQ(0U, browse_info->ips.size());
std::vector<IPUrlInfo> expected_urls;
for (int i = 0; i < 20; i++) {
std::string url = base::StringPrintf("http://%d.com/", i);
expected_urls.push_back(IPUrlInfo(url, "", "", ResourceType::OBJECT));
UpdateIPUrlMap("250.10.10.10", url);
}
ASSERT_EQ(1U, browse_info->ips.size());
ASSERT_EQ(20U, browse_info->ips["250.10.10.10"].size());
CheckIPUrlEqual(expected_urls,
browse_info->ips["250.10.10.10"]);
UpdateIPUrlMap("250.10.10.10", "http://21.com/");
ASSERT_EQ(1U, browse_info->ips.size());
ASSERT_EQ(20U, browse_info->ips["250.10.10.10"].size());
CheckIPUrlEqual(expected_urls,
browse_info->ips["250.10.10.10"]);
for (int i = 0; i < 199; i++) {
std::string ip = base::StringPrintf("%d.%d.%d.256", i, i, i);
expected_urls.clear();
expected_urls.push_back(IPUrlInfo("test.com/", "", "",
ResourceType::OBJECT));
UpdateIPUrlMap(ip, "test.com/");
ASSERT_EQ(1U, browse_info->ips[ip].size());
CheckIPUrlEqual(expected_urls,
browse_info->ips[ip]);
}
ASSERT_EQ(200U, browse_info->ips.size());
UpdateIPUrlMap("250.250.250.250", "goo.com/");
UpdateIPUrlMap("250.250.250.250", "bar.com/");
UpdateIPUrlMap("250.250.0.250", "foo.com/");
ASSERT_EQ(200U, browse_info->ips.size());
UpdateIPUrlMap("100.100.100.256", "more.com/");
ASSERT_EQ(2U, browse_info->ips["100.100.100.256"].size());
expected_urls.clear();
expected_urls.push_back(IPUrlInfo("test.com/", "", "", ResourceType::OBJECT));
expected_urls.push_back(IPUrlInfo("more.com/", "", "", ResourceType::OBJECT));
CheckIPUrlEqual(expected_urls,
browse_info->ips["100.100.100.256"]);
}
TEST_F(ClientSideDetectionHostTest, NavigationCancelsShouldClassifyUrl) {
GURL first_url("http://first.phishy.url.com");
GURL second_url("http://second.url.com/");
EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_))
.WillOnce(Return(false))
.WillOnce(Return(false));
ExpectPreClassificationChecks(first_url, NULL, &kFalse, &kFalse, &kFalse,
NULL, NULL, NULL, NULL);
ExpectPreClassificationChecks(second_url, NULL, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse);
NavigateAndCommit(first_url);
NavigateAndCommit(second_url);
WaitAndCheckPreClassificationChecks();
}
TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckPass) {
GURL url("http://host.com/");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(&url);
ExpectShouldClassifyForMalwareResult(true);
}
TEST_F(ClientSideDetectionHostTest,
TestPreClassificationCheckInPageNavigation) {
GURL url("http://host.com/");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(&url);
ExpectShouldClassifyForMalwareResult(true);
EXPECT_CALL(*csd_service_, IsPrivateIPAddress(_)).Times(0);
GURL inpage("http://host.com/#foo");
ExpectPreClassificationChecks(inpage, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL);
NavigateAndCommit(inpage);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(NULL);
ExpectShouldClassifyForMalwareResult(true);
}
TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckXHTML) {
GURL url("http://host.com/xhtml");
rvh_tester()->SetContentsMimeType("application/xhtml+xml");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(&url);
ExpectShouldClassifyForMalwareResult(true);
}
TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckTwoNavigations) {
GURL url1("http://host1.com/");
ExpectPreClassificationChecks(url1, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse);
NavigateAndCommit(url1);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(&url1);
ExpectShouldClassifyForMalwareResult(true);
GURL url2("http://host2.com/");
ExpectPreClassificationChecks(url2, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse);
NavigateAndCommit(url2);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(&url2);
ExpectShouldClassifyForMalwareResult(true);
}
TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckMimeType) {
GURL url("http://host2.com/image.jpg");
rvh_tester()->SetContentsMimeType("image/jpeg");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse,&kFalse, &kFalse);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(NULL);
ExpectShouldClassifyForMalwareResult(true);
}
TEST_F(ClientSideDetectionHostTest,
TestPreClassificationCheckPrivateIpAddress) {
GURL url("http://host3.com/");
ExpectPreClassificationChecks(url, &kTrue, &kFalse, NULL, NULL, NULL, NULL,
NULL, NULL);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
const IPC::Message* msg = process()->sink().GetFirstMessageMatching(
SafeBrowsingMsg_StartPhishingDetection::ID);
ASSERT_FALSE(msg);
ExpectShouldClassifyForMalwareResult(false);
}
TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckIncognito) {
GURL url("http://host4.com/");
ExpectPreClassificationChecks(url, &kFalse, &kTrue, NULL, NULL, NULL, NULL,
NULL, NULL);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(NULL);
ExpectShouldClassifyForMalwareResult(false);
}
TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckCsdWhitelist) {
GURL url("http://host5.com/");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kTrue, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(NULL);
ExpectShouldClassifyForMalwareResult(true);
}
TEST_F(ClientSideDetectionHostTest,
TestPreClassificationCheckMalwareKillSwitch) {
GURL url("http://host5.com/kill-switch");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kTrue, &kFalse,
&kFalse, &kFalse, &kFalse);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(&url);
ExpectShouldClassifyForMalwareResult(false);
}
TEST_F(ClientSideDetectionHostTest,
TestPreClassificationCheckKillswitchAndCsdWhitelist) {
GURL url("http://host5.com/kill-switch-and-whitelisted");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kTrue, &kTrue, NULL,
NULL, NULL, NULL);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(NULL);
ExpectShouldClassifyForMalwareResult(false);
}
TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckInvalidCache) {
GURL url("http://host6.com/");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kTrue, NULL, &kFalse);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(&url);
ExpectShouldClassifyForMalwareResult(true);
}
TEST_F(ClientSideDetectionHostTest,
TestPreClassificationCheckOverPhishingReportingLimit) {
GURL url("http://host7.com/");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kTrue, &kFalse);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(NULL);
ExpectShouldClassifyForMalwareResult(true);
}
TEST_F(ClientSideDetectionHostTest,
TestPreClassificationCheckOverMalwareReportingLimit) {
GURL url("http://host.com/");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kTrue);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(&url);
ExpectShouldClassifyForMalwareResult(false);
}
TEST_F(ClientSideDetectionHostTest,
TestPreClassificationCheckOverBothReportingLimits) {
GURL url("http://host.com/");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kTrue, &kTrue);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(NULL);
ExpectShouldClassifyForMalwareResult(false);
}
TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckHttpsUrl) {
GURL url("https://host.com/");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse,
&kFalse, &kFalse, &kFalse, &kFalse);
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
ExpectStartPhishingDetection(NULL);
ExpectShouldClassifyForMalwareResult(true);
}
TEST_F(ClientSideDetectionHostTest, TestPreClassificationCheckValidCached) {
GURL url("http://host8.com/");
ExpectPreClassificationChecks(url, &kFalse, &kFalse, &kFalse, &kFalse, &kTrue,
&kFalse, &kFalse, &kFalse);
UnsafeResource resource;
EXPECT_CALL(*ui_manager_.get(), DisplayBlockingPage(_))
.WillOnce(SaveArg<0>(&resource));
NavigateAndCommit(url);
WaitAndCheckPreClassificationChecks();
EXPECT_EQ(url, resource.url);
EXPECT_EQ(url, resource.original_url);
ExpectStartPhishingDetection(NULL);
ExpectShouldClassifyForMalwareResult(false);
}
}