1 // Copyright 2019 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 "chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.h"
6 
7 #include <algorithm>
8 #include <memory>
9 
10 #include "base/bind.h"
11 #include "base/metrics/histogram_functions.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/safe_browsing/download_protection/download_feedback_service.h"
15 #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
16 #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
17 #include "chrome/common/safe_browsing/download_type_util.h"
18 #include "components/safe_browsing/core/common/utils.h"
19 #include "components/safe_browsing/core/features.h"
20 #include "components/safe_browsing/core/file_type_policies.h"
21 #include "components/safe_browsing/core/proto/csd.pb.h"
22 #include "content/public/browser/browser_context.h"
23 #include "content/public/browser/download_item_utils.h"
24 #include "content/public/browser/navigation_entry.h"
25 
26 namespace safe_browsing {
27 
28 using content::BrowserThread;
29 
30 namespace {
31 
GetDownloadUrl(const GURL & frame_url)32 GURL GetDownloadUrl(const GURL& frame_url) {
33   // Regular blob: URLs are of the form
34   // "blob:https://my-origin.com/def07373-cbd8-49d2-9ef7-20b071d34a1a". To make
35   // these URLs distinguishable from those we use a fixed string rather than a
36   // random UUID.
37   return GURL("blob:" + frame_url.GetOrigin().spec() +
38               "native-file-system-write");
39 }
40 
TabUrlsFromWebContents(content::WebContents * web_contents)41 CheckClientDownloadRequestBase::TabUrls TabUrlsFromWebContents(
42     content::WebContents* web_contents) {
43   CheckClientDownloadRequestBase::TabUrls result;
44   if (web_contents) {
45     content::NavigationEntry* entry =
46         web_contents->GetController().GetVisibleEntry();
47     if (entry) {
48       result.url = entry->GetURL();
49       result.referrer = entry->GetReferrer().url;
50     }
51   }
52   return result;
53 }
54 
55 }  // namespace
56 
CheckNativeFileSystemWriteRequest(std::unique_ptr<content::NativeFileSystemWriteItem> item,CheckDownloadCallback callback,DownloadProtectionService * service,scoped_refptr<SafeBrowsingDatabaseManager> database_manager,scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor)57 CheckNativeFileSystemWriteRequest::CheckNativeFileSystemWriteRequest(
58     std::unique_ptr<content::NativeFileSystemWriteItem> item,
59     CheckDownloadCallback callback,
60     DownloadProtectionService* service,
61     scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
62     scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor)
63     : CheckClientDownloadRequestBase(GetDownloadUrl(item->frame_url),
64                                      item->target_file_path,
65                                      item->full_path,
66                                      TabUrlsFromWebContents(item->web_contents),
67                                      "application/octet-stream",
68                                      item->sha256_hash,
69                                      item->browser_context,
70                                      std::move(callback),
71                                      service,
72                                      std::move(database_manager),
73                                      std::move(binary_feature_extractor)),
74       item_(std::move(item)),
75       referrer_chain_data_(service->IdentifyReferrerChain(*item_)) {
76   DCHECK_CURRENTLY_ON(BrowserThread::UI);
77 }
78 
79 CheckNativeFileSystemWriteRequest ::~CheckNativeFileSystemWriteRequest() =
80     default;
81 
IsSupportedDownload(DownloadCheckResultReason * reason,ClientDownloadRequest::DownloadType * type)82 bool CheckNativeFileSystemWriteRequest::IsSupportedDownload(
83     DownloadCheckResultReason* reason,
84     ClientDownloadRequest::DownloadType* type) {
85   if (!FileTypePolicies::GetInstance()->IsCheckedBinaryFile(
86           item_->target_file_path)) {
87     *reason = REASON_NOT_BINARY_FILE;
88     return false;
89   }
90   *type = download_type_util::GetDownloadType(item_->target_file_path);
91   return true;
92 }
93 
GetBrowserContext() const94 content::BrowserContext* CheckNativeFileSystemWriteRequest::GetBrowserContext()
95     const {
96   return item_->browser_context;
97 }
98 
IsCancelled()99 bool CheckNativeFileSystemWriteRequest::IsCancelled() {
100   return false;
101 }
102 
PopulateRequest(ClientDownloadRequest * request)103 void CheckNativeFileSystemWriteRequest::PopulateRequest(
104     ClientDownloadRequest* request) {
105   request->mutable_digests()->set_sha256(item_->sha256_hash);
106   request->set_length(item_->size);
107   {
108     ClientDownloadRequest::Resource* resource = request->add_resources();
109     resource->set_url(SanitizeUrl(GetDownloadUrl(item_->frame_url)));
110     resource->set_type(ClientDownloadRequest::DOWNLOAD_URL);
111     if (item_->frame_url.is_valid())
112       resource->set_referrer(SanitizeUrl(item_->frame_url));
113   }
114 
115   request->set_user_initiated(item_->has_user_gesture);
116 
117   if (referrer_chain_data_ &&
118       !referrer_chain_data_->GetReferrerChain()->empty()) {
119     request->mutable_referrer_chain()->Swap(
120         referrer_chain_data_->GetReferrerChain());
121     request->mutable_referrer_chain_options()
122         ->set_recent_navigations_to_collect(
123             referrer_chain_data_->recent_navigations_to_collect());
124     UMA_HISTOGRAM_COUNTS_100(
125         "SafeBrowsing.ReferrerURLChainSize.NativeFileSystemWriteAttribution",
126         referrer_chain_data_->referrer_chain_length());
127   }
128 }
129 
130 base::WeakPtr<CheckClientDownloadRequestBase>
GetWeakPtr()131 CheckNativeFileSystemWriteRequest::GetWeakPtr() {
132   return weakptr_factory_.GetWeakPtr();
133 }
134 
NotifySendRequest(const ClientDownloadRequest * request)135 void CheckNativeFileSystemWriteRequest::NotifySendRequest(
136     const ClientDownloadRequest* request) {
137   service()->native_file_system_write_request_callbacks_.Notify(request);
138 }
139 
SetDownloadPingToken(const std::string & token)140 void CheckNativeFileSystemWriteRequest::SetDownloadPingToken(
141     const std::string& token) {
142   // TODO(https://crbug.com/996797): Actually store token for
143   // IncidentReportingService usage.
144 }
145 
MaybeStorePingsForDownload(DownloadCheckResult result,bool upload_requested,const std::string & request_data,const std::string & response_body)146 void CheckNativeFileSystemWriteRequest::MaybeStorePingsForDownload(
147     DownloadCheckResult result,
148     bool upload_requested,
149     const std::string& request_data,
150     const std::string& response_body) {
151   // TODO(https://crbug.com/996797): Integrate with DownloadFeedbackService.
152 }
153 
154 base::Optional<enterprise_connectors::AnalysisSettings>
ShouldUploadBinary(DownloadCheckResultReason reason)155 CheckNativeFileSystemWriteRequest::ShouldUploadBinary(
156     DownloadCheckResultReason reason) {
157   return base::nullopt;
158 }
159 
UploadBinary(DownloadCheckResultReason reason,enterprise_connectors::AnalysisSettings settings)160 void CheckNativeFileSystemWriteRequest::UploadBinary(
161     DownloadCheckResultReason reason,
162     enterprise_connectors::AnalysisSettings settings) {}
163 
ShouldPromptForDeepScanning(DownloadCheckResultReason reason) const164 bool CheckNativeFileSystemWriteRequest::ShouldPromptForDeepScanning(
165     DownloadCheckResultReason reason) const {
166   return false;
167 }
168 
NotifyRequestFinished(DownloadCheckResult result,DownloadCheckResultReason reason)169 void CheckNativeFileSystemWriteRequest::NotifyRequestFinished(
170     DownloadCheckResult result,
171     DownloadCheckResultReason reason) {
172   DCHECK_CURRENTLY_ON(BrowserThread::UI);
173   weakptr_factory_.InvalidateWeakPtrs();
174 }
175 
IsWhitelistedByPolicy() const176 bool CheckNativeFileSystemWriteRequest::IsWhitelistedByPolicy() const {
177   Profile* profile = Profile::FromBrowserContext(item_->browser_context);
178   if (!profile)
179     return false;
180   return IsURLWhitelistedByPolicy(item_->frame_url, *profile->GetPrefs());
181 }
182 
183 }  // namespace safe_browsing
184