// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "chrome/browser/safe_browsing/malware_details.h" #include "chrome/browser/safe_browsing/report.pb.h" #include "chrome/common/safebrowsing_messages.h" #include "content/browser/browser_thread.h" #include "content/browser/renderer_host/test_render_view_host.h" #include "content/browser/tab_contents/navigation_entry.h" #include "content/browser/tab_contents/test_tab_contents.h" static const char* kOriginalLandingURL = "http://www.originallandingpage.com/"; static const char* kLandingURL = "http://www.landingpage.com/"; static const char* kMalwareURL = "http://www.malware.com/"; static const char* kHttpsURL = "https://www.url.com/"; static const char* kDOMChildURL = "http://www.domparent.com/"; static const char* kDOMParentURL = "http://www.domchild.com/"; static const char* kFirstRedirectURL = "http://redirectone.com/"; static const char* kSecondRedirectURL = "http://redirecttwo.com/"; using safe_browsing::ClientMalwareReportRequest; class MalwareDetailsTest : public RenderViewHostTestHarness { public: MalwareDetailsTest() : ui_thread_(BrowserThread::UI, MessageLoop::current()), io_thread_(BrowserThread::IO, MessageLoop::current()) { } virtual void SetUp() { RenderViewHostTestHarness::SetUp(); } static bool ResourceLessThan( const ClientMalwareReportRequest::Resource* lhs, const ClientMalwareReportRequest::Resource* rhs) { return lhs->id() < rhs->id(); } protected: void InitResource(SafeBrowsingService::UnsafeResource* resource, ResourceType::Type resource_type, const GURL& url) { resource->client = NULL; resource->url = url; resource->resource_type = resource_type; resource->threat_type = SafeBrowsingService::URL_MALWARE; resource->render_process_host_id = contents()->GetRenderProcessHost()->id(); resource->render_view_id = contents()->render_view_host()->routing_id(); } void VerifyResults(const ClientMalwareReportRequest& report_pb, const ClientMalwareReportRequest& expected_pb) { EXPECT_EQ(expected_pb.malware_url(), report_pb.malware_url()); EXPECT_EQ(expected_pb.page_url(), report_pb.page_url()); EXPECT_EQ(expected_pb.referrer_url(), report_pb.referrer_url()); ASSERT_EQ(expected_pb.resources_size(), report_pb.resources_size()); // Sort the resources, to make the test deterministic std::vector resources; for (int i = 0; i < report_pb.resources_size(); ++i) { const ClientMalwareReportRequest::Resource& resource = report_pb.resources(i); resources.push_back(&resource); } std::sort(resources.begin(), resources.end(), &MalwareDetailsTest::ResourceLessThan); std::vector expected; for (int i = 0; i < report_pb.resources_size(); ++i) { const ClientMalwareReportRequest::Resource& resource = expected_pb.resources(i); expected.push_back(&resource); } std::sort(expected.begin(), expected.end(), &MalwareDetailsTest::ResourceLessThan); for (uint32 i = 0; i < expected.size(); ++i) { EXPECT_EQ(expected[i]->id(), resources[i]->id()); EXPECT_EQ(expected[i]->url(), resources[i]->url()); EXPECT_EQ(expected[i]->parent_id(), resources[i]->parent_id()); ASSERT_EQ(expected[i]->child_ids_size(), resources[i]->child_ids_size()); for (int j = 0; j < expected[i]->child_ids_size(); j++) { EXPECT_EQ(expected[i]->child_ids(j), resources[i]->child_ids(j)); } } } BrowserThread ui_thread_; BrowserThread io_thread_; }; // Tests creating a simple malware report. TEST_F(MalwareDetailsTest, MalwareSubResource) { // Start a load. controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED); SafeBrowsingService::UnsafeResource resource; InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL)); scoped_refptr report = MalwareDetails::NewMalwareDetails( contents(), resource); scoped_ptr serialized(report->GetSerializedReport()); ClientMalwareReportRequest actual; actual.ParseFromString(*serialized); ClientMalwareReportRequest expected; expected.set_malware_url(kMalwareURL); expected.set_page_url(kLandingURL); expected.set_referrer_url(""); ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources(); pb_resource->set_id(0); pb_resource->set_url(kLandingURL); pb_resource = expected.add_resources(); pb_resource->set_id(1); pb_resource->set_url(kMalwareURL); VerifyResults(actual, expected); } // Tests creating a simple malware report where the subresource has a // different original_url. TEST_F(MalwareDetailsTest, MalwareSubResourceWithOriginalUrl) { controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED); SafeBrowsingService::UnsafeResource resource; InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL)); resource.original_url = GURL(kOriginalLandingURL); scoped_refptr report = MalwareDetails::NewMalwareDetails( contents(), resource); scoped_ptr serialized(report->GetSerializedReport()); ClientMalwareReportRequest actual; actual.ParseFromString(*serialized); ClientMalwareReportRequest expected; expected.set_malware_url(kMalwareURL); expected.set_page_url(kLandingURL); expected.set_referrer_url(""); ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources(); pb_resource->set_id(0); pb_resource->set_url(kLandingURL); pb_resource = expected.add_resources(); pb_resource->set_id(1); pb_resource->set_url(kOriginalLandingURL); pb_resource = expected.add_resources(); pb_resource->set_id(2); pb_resource->set_url(kMalwareURL); // The Resource for kMmalwareUrl should have the Resource for // kOriginalLandingURL (with id 1) as parent. pb_resource->set_parent_id(1); VerifyResults(actual, expected); } // Tests creating a malware report with data from the renderer. TEST_F(MalwareDetailsTest, MalwareDOMDetails) { controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED); SafeBrowsingService::UnsafeResource resource; InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL)); scoped_refptr report = MalwareDetails::NewMalwareDetails( contents(), resource); // Send a message from the DOM, with 2 nodes, a parent and a child. std::vector params; SafeBrowsingHostMsg_MalwareDOMDetails_Node child_node; child_node.url = GURL(kDOMChildURL); child_node.tag_name = "iframe"; child_node.parent = GURL(kDOMParentURL); params.push_back(child_node); SafeBrowsingHostMsg_MalwareDOMDetails_Node parent_node; parent_node.url = GURL(kDOMParentURL); parent_node.children.push_back(GURL(kDOMChildURL)); params.push_back(parent_node); report->OnReceivedMalwareDOMDetails(params); MessageLoop::current()->RunAllPending(); scoped_ptr serialized(report->GetSerializedReport()); ClientMalwareReportRequest actual; actual.ParseFromString(*serialized); ClientMalwareReportRequest expected; expected.set_malware_url(kMalwareURL); expected.set_page_url(kLandingURL); expected.set_referrer_url(""); ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources(); pb_resource->set_id(0); pb_resource->set_url(kLandingURL); pb_resource = expected.add_resources(); pb_resource->set_id(1); pb_resource->set_url(kMalwareURL); pb_resource = expected.add_resources(); pb_resource->set_id(2); pb_resource->set_url(kDOMChildURL); pb_resource->set_parent_id(3); pb_resource = expected.add_resources(); pb_resource->set_id(3); pb_resource->set_url(kDOMParentURL); pb_resource->add_child_ids(2); VerifyResults(actual, expected); } // Verify that https:// urls are dropped. TEST_F(MalwareDetailsTest, NotPublicUrl) { controller().LoadURL(GURL(kHttpsURL), GURL(), PageTransition::TYPED); SafeBrowsingService::UnsafeResource resource; InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL)); scoped_refptr report = MalwareDetails::NewMalwareDetails( contents(), resource); scoped_ptr serialized(report->GetSerializedReport()); ClientMalwareReportRequest actual; actual.ParseFromString(*serialized); ClientMalwareReportRequest expected; expected.set_malware_url(kMalwareURL); // No page_url expected.set_referrer_url(""); ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources(); pb_resource->set_url(kMalwareURL); // Only one resource VerifyResults(actual, expected); } // Tests creating a malware report where there are redirect urls to an unsafe // resource url TEST_F(MalwareDetailsTest, MalwareWithRedirectUrl) { controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED); SafeBrowsingService::UnsafeResource resource; InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL)); resource.original_url = GURL(kOriginalLandingURL); // add some redirect urls resource.redirect_urls.push_back(GURL(kFirstRedirectURL)); resource.redirect_urls.push_back(GURL(kSecondRedirectURL)); resource.redirect_urls.push_back(GURL(kMalwareURL)); scoped_refptr report = MalwareDetails::NewMalwareDetails( contents(), resource); scoped_ptr serialized(report->GetSerializedReport()); ClientMalwareReportRequest actual; actual.ParseFromString(*serialized); ClientMalwareReportRequest expected; expected.set_malware_url(kMalwareURL); expected.set_page_url(kLandingURL); expected.set_referrer_url(""); ClientMalwareReportRequest::Resource* pb_resource = expected.add_resources(); pb_resource->set_id(0); pb_resource->set_url(kLandingURL); pb_resource = expected.add_resources(); pb_resource->set_id(1); pb_resource->set_url(kOriginalLandingURL); pb_resource = expected.add_resources(); pb_resource->set_id(2); pb_resource->set_url(kMalwareURL); pb_resource->set_parent_id(4); pb_resource = expected.add_resources(); pb_resource->set_id(3); pb_resource->set_url(kFirstRedirectURL); pb_resource->set_parent_id(1); pb_resource = expected.add_resources(); pb_resource->set_id(4); pb_resource->set_url(kSecondRedirectURL); pb_resource->set_parent_id(3); VerifyResults(actual, expected); }