1 // Copyright 2017 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 "components/safe_browsing/content/web_ui/safe_browsing_ui.h"
6 
7 #include <stddef.h>
8 #include <algorithm>
9 #include <memory>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/base64.h"
14 #include "base/base64url.h"
15 #include "base/bind.h"
16 #include "base/callback.h"
17 #include "base/i18n/time_formatting.h"
18 #include "base/json/json_string_value_serializer.h"
19 #include "base/memory/ref_counted.h"
20 #include "base/memory/singleton.h"
21 #include "base/stl_util.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "base/task/post_task.h"
25 #include "base/time/time.h"
26 #include "base/values.h"
27 #include "components/grit/components_resources.h"
28 #include "components/grit/components_scaled_resources.h"
29 #include "components/password_manager/core/browser/hash_password_manager.h"
30 #include "components/safe_browsing/buildflags.h"
31 #include "components/safe_browsing/core/browser/referrer_chain_provider.h"
32 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
33 #include "components/safe_browsing/core/features.h"
34 #include "components/safe_browsing/core/proto/csd.pb.h"
35 #if BUILDFLAG(FULL_SAFE_BROWSING)
36 #include "components/safe_browsing/core/proto/webprotect.pb.h"
37 #endif
38 #include "components/safe_browsing/core/realtime/policy_engine.h"
39 #include "components/safe_browsing/core/web_ui/constants.h"
40 #include "components/strings/grit/components_strings.h"
41 #include "components/user_prefs/user_prefs.h"
42 #include "content/public/browser/browser_context.h"
43 #include "content/public/browser/browser_task_traits.h"
44 #include "content/public/browser/browser_thread.h"
45 #include "content/public/browser/web_contents.h"
46 
47 #if BUILDFLAG(SAFE_BROWSING_DB_LOCAL)
48 #include "components/safe_browsing/core/db/v4_local_database_manager.h"
49 #endif
50 
51 using base::Time;
52 using sync_pb::GaiaPasswordReuse;
53 using PasswordCaptured = sync_pb::UserEventSpecifics::GaiaPasswordCaptured;
54 using PasswordReuseLookup = sync_pb::GaiaPasswordReuse::PasswordReuseLookup;
55 using PasswordReuseDetected = sync_pb::GaiaPasswordReuse::PasswordReuseDetected;
56 using PasswordReuseDialogInteraction =
57     sync_pb::GaiaPasswordReuse::PasswordReuseDialogInteraction;
58 
59 namespace safe_browsing {
60 WebUIInfoSingleton::WebUIInfoSingleton() = default;
61 
62 WebUIInfoSingleton::~WebUIInfoSingleton() = default;
63 
64 // static
GetInstance()65 WebUIInfoSingleton* WebUIInfoSingleton::GetInstance() {
66   return base::Singleton<WebUIInfoSingleton>::get();
67 }
68 
69 // static
HasListener()70 bool WebUIInfoSingleton::HasListener() {
71   return GetInstance()->has_test_listener_ ||
72          !GetInstance()->webui_instances_.empty();
73 }
74 
AddToClientDownloadRequestsSent(std::unique_ptr<ClientDownloadRequest> client_download_request)75 void WebUIInfoSingleton::AddToClientDownloadRequestsSent(
76     std::unique_ptr<ClientDownloadRequest> client_download_request) {
77   if (!HasListener())
78     return;
79 
80   for (auto* webui_listener : webui_instances_)
81     webui_listener->NotifyClientDownloadRequestJsListener(
82         client_download_request.get());
83   client_download_requests_sent_.push_back(std::move(client_download_request));
84 }
85 
ClearClientDownloadRequestsSent()86 void WebUIInfoSingleton::ClearClientDownloadRequestsSent() {
87   std::vector<std::unique_ptr<ClientDownloadRequest>>().swap(
88       client_download_requests_sent_);
89 }
90 
AddToClientDownloadResponsesReceived(std::unique_ptr<ClientDownloadResponse> client_download_response)91 void WebUIInfoSingleton::AddToClientDownloadResponsesReceived(
92     std::unique_ptr<ClientDownloadResponse> client_download_response) {
93   if (!HasListener())
94     return;
95 
96   for (auto* webui_listener : webui_instances_)
97     webui_listener->NotifyClientDownloadResponseJsListener(
98         client_download_response.get());
99   client_download_responses_received_.push_back(
100       std::move(client_download_response));
101 }
102 
ClearClientDownloadResponsesReceived()103 void WebUIInfoSingleton::ClearClientDownloadResponsesReceived() {
104   std::vector<std::unique_ptr<ClientDownloadResponse>>().swap(
105       client_download_responses_received_);
106 }
107 
AddToCSBRRsSent(std::unique_ptr<ClientSafeBrowsingReportRequest> csbrr)108 void WebUIInfoSingleton::AddToCSBRRsSent(
109     std::unique_ptr<ClientSafeBrowsingReportRequest> csbrr) {
110   if (!HasListener())
111     return;
112 
113   for (auto* webui_listener : webui_instances_)
114     webui_listener->NotifyCSBRRJsListener(csbrr.get());
115   csbrrs_sent_.push_back(std::move(csbrr));
116 }
117 
ClearCSBRRsSent()118 void WebUIInfoSingleton::ClearCSBRRsSent() {
119   std::vector<std::unique_ptr<ClientSafeBrowsingReportRequest>>().swap(
120       csbrrs_sent_);
121 }
122 
AddToPGEvents(const sync_pb::UserEventSpecifics & event)123 void WebUIInfoSingleton::AddToPGEvents(
124     const sync_pb::UserEventSpecifics& event) {
125   if (!HasListener())
126     return;
127 
128   for (auto* webui_listener : webui_instances_)
129     webui_listener->NotifyPGEventJsListener(event);
130 
131   pg_event_log_.push_back(event);
132 }
133 
ClearPGEvents()134 void WebUIInfoSingleton::ClearPGEvents() {
135   std::vector<sync_pb::UserEventSpecifics>().swap(pg_event_log_);
136 }
137 
AddToSecurityEvents(const sync_pb::GaiaPasswordReuse & event)138 void WebUIInfoSingleton::AddToSecurityEvents(
139     const sync_pb::GaiaPasswordReuse& event) {
140   if (!HasListener())
141     return;
142 
143   for (auto* webui_listener : webui_instances_)
144     webui_listener->NotifySecurityEventJsListener(event);
145 
146   security_event_log_.push_back(event);
147 }
148 
ClearSecurityEvents()149 void WebUIInfoSingleton::ClearSecurityEvents() {
150   std::vector<sync_pb::GaiaPasswordReuse>().swap(security_event_log_);
151 }
152 
AddToPGPings(const LoginReputationClientRequest & request)153 int WebUIInfoSingleton::AddToPGPings(
154     const LoginReputationClientRequest& request) {
155   if (!HasListener())
156     return -1;
157 
158   for (auto* webui_listener : webui_instances_)
159     webui_listener->NotifyPGPingJsListener(pg_pings_.size(), request);
160 
161   pg_pings_.push_back(request);
162 
163   return pg_pings_.size() - 1;
164 }
165 
AddToPGResponses(int token,const LoginReputationClientResponse & response)166 void WebUIInfoSingleton::AddToPGResponses(
167     int token,
168     const LoginReputationClientResponse& response) {
169   if (!HasListener())
170     return;
171 
172   for (auto* webui_listener : webui_instances_)
173     webui_listener->NotifyPGResponseJsListener(token, response);
174 
175   pg_responses_[token] = response;
176 }
177 
ClearPGPings()178 void WebUIInfoSingleton::ClearPGPings() {
179   std::vector<LoginReputationClientRequest>().swap(pg_pings_);
180   std::map<int, LoginReputationClientResponse>().swap(pg_responses_);
181 }
182 
AddToRTLookupPings(const RTLookupRequest request)183 int WebUIInfoSingleton::AddToRTLookupPings(const RTLookupRequest request) {
184   if (!HasListener())
185     return -1;
186 
187   for (auto* webui_listener : webui_instances_)
188     webui_listener->NotifyRTLookupPingJsListener(rt_lookup_pings_.size(),
189                                                  request);
190 
191   rt_lookup_pings_.push_back(request);
192 
193   return rt_lookup_pings_.size() - 1;
194 }
195 
AddToRTLookupResponses(int token,const RTLookupResponse response)196 void WebUIInfoSingleton::AddToRTLookupResponses(
197     int token,
198     const RTLookupResponse response) {
199   if (!HasListener())
200     return;
201 
202   for (auto* webui_listener : webui_instances_)
203     webui_listener->NotifyRTLookupResponseJsListener(token, response);
204 
205   rt_lookup_responses_[token] = response;
206 }
207 
ClearRTLookupPings()208 void WebUIInfoSingleton::ClearRTLookupPings() {
209   std::vector<RTLookupRequest>().swap(rt_lookup_pings_);
210   std::map<int, RTLookupResponse>().swap(rt_lookup_responses_);
211 }
212 
LogMessage(const std::string & message)213 void WebUIInfoSingleton::LogMessage(const std::string& message) {
214   if (!HasListener())
215     return;
216 
217   base::Time timestamp = base::Time::Now();
218   log_messages_.push_back(std::make_pair(timestamp, message));
219 
220   base::PostTask(FROM_HERE, {content::BrowserThread::UI},
221                  base::BindOnce(&WebUIInfoSingleton::NotifyLogMessageListeners,
222                                 timestamp, message));
223 }
224 
ClearLogMessages()225 void WebUIInfoSingleton::ClearLogMessages() {
226   std::vector<std::pair<base::Time, std::string>>().swap(log_messages_);
227 }
228 
NotifyLogMessageListeners(const base::Time & timestamp,const std::string & message)229 /* static */ void WebUIInfoSingleton::NotifyLogMessageListeners(
230     const base::Time& timestamp,
231     const std::string& message) {
232   WebUIInfoSingleton* web_ui_info = GetInstance();
233 
234   for (auto* webui_listener : web_ui_info->webui_instances())
235     webui_listener->NotifyLogMessageJsListener(timestamp, message);
236 }
237 
AddToReportingEvents(const base::Value & event)238 void WebUIInfoSingleton::AddToReportingEvents(const base::Value& event) {
239   if (!HasListener())
240     return;
241 
242   for (auto* webui_listener : webui_instances_)
243     webui_listener->NotifyReportingEventJsListener(event);
244 
245   reporting_events_.push_back(event.Clone());
246 }
247 
ClearReportingEvents()248 void WebUIInfoSingleton::ClearReportingEvents() {
249   std::vector<base::Value>().swap(reporting_events_);
250 }
251 
252 #if BUILDFLAG(FULL_SAFE_BROWSING)
AddToDeepScanRequests(const DeepScanningClientRequest & request)253 void WebUIInfoSingleton::AddToDeepScanRequests(
254     const DeepScanningClientRequest& request) {
255   if (!HasListener())
256     return;
257 
258   if (deep_scan_requests_.find(request.request_token()) ==
259       deep_scan_requests_.end()) {
260     for (auto* webui_listener : webui_instances_)
261       webui_listener->NotifyDeepScanRequestJsListener(request);
262   }
263 
264   deep_scan_requests_[request.request_token()] = request;
265 }
266 
AddToDeepScanResponses(const std::string & token,const std::string & status,const DeepScanningClientResponse & response)267 void WebUIInfoSingleton::AddToDeepScanResponses(
268     const std::string& token,
269     const std::string& status,
270     const DeepScanningClientResponse& response) {
271   if (!HasListener())
272     return;
273 
274   for (auto* webui_listener : webui_instances_)
275     webui_listener->NotifyDeepScanResponseJsListener(token, status, response);
276 
277   deep_scan_responses_[token] = std::make_pair(status, response);
278 }
279 
ClearDeepScans()280 void WebUIInfoSingleton::ClearDeepScans() {
281   DeepScanningRequestMap().swap(deep_scan_requests_);
282   StatusAndDeepScanningResponseMap().swap(deep_scan_responses_);
283 }
284 #endif
RegisterWebUIInstance(SafeBrowsingUIHandler * webui)285 void WebUIInfoSingleton::RegisterWebUIInstance(SafeBrowsingUIHandler* webui) {
286   webui_instances_.push_back(webui);
287 }
288 
UnregisterWebUIInstance(SafeBrowsingUIHandler * webui)289 void WebUIInfoSingleton::UnregisterWebUIInstance(SafeBrowsingUIHandler* webui) {
290   base::Erase(webui_instances_, webui);
291   MaybeClearData();
292 }
293 
GetCookieManager()294 network::mojom::CookieManager* WebUIInfoSingleton::GetCookieManager() {
295   if (!cookie_manager_remote_)
296     InitializeCookieManager();
297 
298   return cookie_manager_remote_.get();
299 }
300 
ClearListenerForTesting()301 void WebUIInfoSingleton::ClearListenerForTesting() {
302   has_test_listener_ = false;
303   MaybeClearData();
304 }
305 
InitializeCookieManager()306 void WebUIInfoSingleton::InitializeCookieManager() {
307   DCHECK(network_context_);
308 
309   // Reset |cookie_manager_remote_|, and only re-initialize it if we have a
310   // listening SafeBrowsingUIHandler.
311   cookie_manager_remote_.reset();
312 
313   if (HasListener()) {
314     network_context_->GetNetworkContext()->GetCookieManager(
315         cookie_manager_remote_.BindNewPipeAndPassReceiver());
316 
317     // base::Unretained is safe because |this| owns |cookie_manager_remote_|.
318     cookie_manager_remote_.set_disconnect_handler(base::BindOnce(
319         &WebUIInfoSingleton::InitializeCookieManager, base::Unretained(this)));
320   }
321 }
322 
MaybeClearData()323 void WebUIInfoSingleton::MaybeClearData() {
324   if (!HasListener()) {
325     ClearCSBRRsSent();
326     ClearClientDownloadRequestsSent();
327     ClearClientDownloadResponsesReceived();
328     ClearPGEvents();
329     ClearPGPings();
330     ClearRTLookupPings();
331     ClearLogMessages();
332     ClearReportingEvents();
333 
334 #if BUILDFLAG(FULL_SAFE_BROWSING)
335     ClearDeepScans();
336 #endif
337   }
338 }
339 
340 namespace {
341 #if BUILDFLAG(SAFE_BROWSING_DB_LOCAL)
342 
UserReadableTimeFromMillisSinceEpoch(int64_t time_in_milliseconds)343 base::Value UserReadableTimeFromMillisSinceEpoch(int64_t time_in_milliseconds) {
344   base::Time time = base::Time::UnixEpoch() +
345                     base::TimeDelta::FromMilliseconds(time_in_milliseconds);
346   return base::Value(
347       base::UTF16ToASCII(base::TimeFormatShortDateAndTime(time)));
348 }
349 
AddStoreInfo(const DatabaseManagerInfo::DatabaseInfo::StoreInfo store_info,base::ListValue * database_info_list)350 void AddStoreInfo(const DatabaseManagerInfo::DatabaseInfo::StoreInfo store_info,
351                   base::ListValue* database_info_list) {
352   if (store_info.has_file_name()) {
353     database_info_list->Append(base::Value(store_info.file_name()));
354   } else {
355     database_info_list->Append(base::Value("Unknown store"));
356   }
357 
358   std::string store_info_string = "<blockquote>";
359   if (store_info.has_file_size_bytes()) {
360     store_info_string +=
361         "Size (in bytes): " + std::to_string(store_info.file_size_bytes()) +
362         "<br>";
363   }
364 
365   if (store_info.has_update_status()) {
366     store_info_string +=
367         "Update status: " + std::to_string(store_info.update_status()) + "<br>";
368   }
369 
370   if (store_info.has_last_apply_update_time_millis()) {
371     store_info_string += "Last update time: " +
372                          UserReadableTimeFromMillisSinceEpoch(
373                              store_info.last_apply_update_time_millis())
374                              .GetString() +
375                          "<br>";
376   }
377 
378   if (store_info.has_checks_attempted()) {
379     store_info_string += "Number of database checks: " +
380                          std::to_string(store_info.checks_attempted()) + "<br>";
381   }
382 
383   store_info_string += "</blockquote>";
384 
385   database_info_list->Append(base::Value(store_info_string));
386 }
387 
AddDatabaseInfo(const DatabaseManagerInfo::DatabaseInfo database_info,base::ListValue * database_info_list)388 void AddDatabaseInfo(const DatabaseManagerInfo::DatabaseInfo database_info,
389                      base::ListValue* database_info_list) {
390   if (database_info.has_database_size_bytes()) {
391     database_info_list->Append(base::Value("Database size (in bytes)"));
392     database_info_list->Append(
393         base::Value(static_cast<double>(database_info.database_size_bytes())));
394   }
395 
396   // Add the information specific to each store.
397   for (int i = 0; i < database_info.store_info_size(); i++) {
398     AddStoreInfo(database_info.store_info(i), database_info_list);
399   }
400 }
401 
AddUpdateInfo(const DatabaseManagerInfo::UpdateInfo update_info,base::ListValue * database_info_list)402 void AddUpdateInfo(const DatabaseManagerInfo::UpdateInfo update_info,
403                    base::ListValue* database_info_list) {
404   if (update_info.has_network_status_code()) {
405     // Network status of the last GetUpdate().
406     database_info_list->Append(base::Value("Last update network status code"));
407     database_info_list->Append(base::Value(update_info.network_status_code()));
408   }
409   if (update_info.has_last_update_time_millis()) {
410     database_info_list->Append(base::Value("Last update time"));
411     database_info_list->Append(UserReadableTimeFromMillisSinceEpoch(
412         update_info.last_update_time_millis()));
413   }
414   if (update_info.has_next_update_time_millis()) {
415     database_info_list->Append(base::Value("Next update time"));
416     database_info_list->Append(UserReadableTimeFromMillisSinceEpoch(
417         update_info.next_update_time_millis()));
418   }
419 }
420 
ParseFullHashInfo(const FullHashCacheInfo::FullHashCache::CachedHashPrefixInfo::FullHashInfo full_hash_info,base::DictionaryValue * full_hash_info_dict)421 void ParseFullHashInfo(
422     const FullHashCacheInfo::FullHashCache::CachedHashPrefixInfo::FullHashInfo
423         full_hash_info,
424     base::DictionaryValue* full_hash_info_dict) {
425   if (full_hash_info.has_positive_expiry()) {
426     full_hash_info_dict->SetString(
427         "Positive expiry",
428         UserReadableTimeFromMillisSinceEpoch(full_hash_info.positive_expiry())
429             .GetString());
430   }
431   if (full_hash_info.has_full_hash()) {
432     std::string full_hash;
433     base::Base64UrlEncode(full_hash_info.full_hash(),
434                           base::Base64UrlEncodePolicy::INCLUDE_PADDING,
435                           &full_hash);
436     full_hash_info_dict->SetString("Full hash (base64)", full_hash);
437   }
438   if (full_hash_info.list_identifier().has_platform_type()) {
439     full_hash_info_dict->SetInteger(
440         "platform_type", full_hash_info.list_identifier().platform_type());
441   }
442   if (full_hash_info.list_identifier().has_threat_entry_type()) {
443     full_hash_info_dict->SetInteger(
444         "threat_entry_type",
445         full_hash_info.list_identifier().threat_entry_type());
446   }
447   if (full_hash_info.list_identifier().has_threat_type()) {
448     full_hash_info_dict->SetInteger(
449         "threat_type", full_hash_info.list_identifier().threat_type());
450   }
451 }
452 
ParseFullHashCache(const FullHashCacheInfo::FullHashCache full_hash_cache,base::ListValue * full_hash_cache_list)453 void ParseFullHashCache(const FullHashCacheInfo::FullHashCache full_hash_cache,
454                         base::ListValue* full_hash_cache_list) {
455   base::DictionaryValue full_hash_cache_parsed;
456 
457   if (full_hash_cache.has_hash_prefix()) {
458     std::string hash_prefix;
459     base::Base64UrlEncode(full_hash_cache.hash_prefix(),
460                           base::Base64UrlEncodePolicy::INCLUDE_PADDING,
461                           &hash_prefix);
462     full_hash_cache_parsed.SetString("Hash prefix (base64)", hash_prefix);
463   }
464   if (full_hash_cache.cached_hash_prefix_info().has_negative_expiry()) {
465     full_hash_cache_parsed.SetString(
466         "Negative expiry",
467         UserReadableTimeFromMillisSinceEpoch(
468             full_hash_cache.cached_hash_prefix_info().negative_expiry())
469             .GetString());
470   }
471 
472   full_hash_cache_list->Append(std::move(full_hash_cache_parsed));
473 
474   for (auto full_hash_info_it :
475        full_hash_cache.cached_hash_prefix_info().full_hash_info()) {
476     base::DictionaryValue full_hash_info_dict;
477     ParseFullHashInfo(full_hash_info_it, &full_hash_info_dict);
478     full_hash_cache_list->Append(std::move(full_hash_info_dict));
479   }
480 }
481 
ParseFullHashCacheInfo(const FullHashCacheInfo full_hash_cache_info_proto,base::ListValue * full_hash_cache_info)482 void ParseFullHashCacheInfo(const FullHashCacheInfo full_hash_cache_info_proto,
483                             base::ListValue* full_hash_cache_info) {
484   if (full_hash_cache_info_proto.has_number_of_hits()) {
485     base::DictionaryValue number_of_hits;
486     number_of_hits.SetInteger("Number of cache hits",
487                               full_hash_cache_info_proto.number_of_hits());
488     full_hash_cache_info->Append(std::move(number_of_hits));
489   }
490 
491   // Record FullHashCache list.
492   for (auto full_hash_cache_it : full_hash_cache_info_proto.full_hash_cache()) {
493     base::ListValue full_hash_cache_list;
494     ParseFullHashCache(full_hash_cache_it, &full_hash_cache_list);
495     full_hash_cache_info->Append(std::move(full_hash_cache_list));
496   }
497 }
498 
AddFullHashCacheInfo(const FullHashCacheInfo full_hash_cache_info_proto)499 std::string AddFullHashCacheInfo(
500     const FullHashCacheInfo full_hash_cache_info_proto) {
501   std::string full_hash_cache_parsed;
502 
503   base::ListValue full_hash_cache;
504   ParseFullHashCacheInfo(full_hash_cache_info_proto, &full_hash_cache);
505 
506   base::Value* full_hash_cache_tree = &full_hash_cache;
507 
508   JSONStringValueSerializer serializer(&full_hash_cache_parsed);
509   serializer.set_pretty_print(true);
510   serializer.Serialize(*full_hash_cache_tree);
511 
512   return full_hash_cache_parsed;
513 }
514 
515 #endif
516 
SerializeReferrer(const ReferrerChainEntry & referrer)517 base::Value SerializeReferrer(const ReferrerChainEntry& referrer) {
518   base::DictionaryValue referrer_dict;
519   referrer_dict.SetKey("url", base::Value(referrer.url()));
520   referrer_dict.SetKey("main_frame_url",
521                        base::Value(referrer.main_frame_url()));
522 
523   std::string url_type;
524   switch (referrer.type()) {
525     case ReferrerChainEntry::EVENT_URL:
526       url_type = "EVENT_URL";
527       break;
528     case ReferrerChainEntry::LANDING_PAGE:
529       url_type = "LANDING_PAGE";
530       break;
531     case ReferrerChainEntry::LANDING_REFERRER:
532       url_type = "LANDING_REFERRER";
533       break;
534     case ReferrerChainEntry::CLIENT_REDIRECT:
535       url_type = "CLIENT_REDIRECT";
536       break;
537     case ReferrerChainEntry::DEPRECATED_SERVER_REDIRECT:
538       url_type = "DEPRECATED_SERVER_REDIRECT";
539       break;
540     case ReferrerChainEntry::RECENT_NAVIGATION:
541       url_type = "RECENT_NAVIGATION";
542       break;
543     case ReferrerChainEntry::REFERRER:
544       url_type = "REFERRER";
545       break;
546   }
547   referrer_dict.SetKey("type", base::Value(url_type));
548 
549   base::ListValue ip_addresses;
550   for (const std::string& ip_address : referrer.ip_addresses()) {
551     ip_addresses.Append(base::Value(ip_address));
552   }
553   referrer_dict.SetKey("ip_addresses", std::move(ip_addresses));
554 
555   referrer_dict.SetKey("referrer_url", base::Value(referrer.referrer_url()));
556 
557   referrer_dict.SetKey("referrer_main_frame_url",
558                        base::Value(referrer.referrer_main_frame_url()));
559 
560   referrer_dict.SetKey("is_retargeting",
561                        base::Value(referrer.is_retargeting()));
562 
563   referrer_dict.SetKey("navigation_time_msec",
564                        base::Value(referrer.navigation_time_msec()));
565 
566   base::ListValue server_redirects;
567   for (const ReferrerChainEntry::ServerRedirect& server_redirect :
568        referrer.server_redirect_chain()) {
569     server_redirects.Append(base::Value(server_redirect.url()));
570   }
571   referrer_dict.SetKey("server_redirect_chain", std::move(server_redirects));
572 
573   std::string navigation_initiation;
574   switch (referrer.navigation_initiation()) {
575     case ReferrerChainEntry::UNDEFINED:
576       navigation_initiation = "UNDEFINED";
577       break;
578     case ReferrerChainEntry::BROWSER_INITIATED:
579       navigation_initiation = "BROWSER_INITIATED";
580       break;
581     case ReferrerChainEntry::RENDERER_INITIATED_WITHOUT_USER_GESTURE:
582       navigation_initiation = "RENDERER_INITIATED_WITHOUT_USER_GESTURE";
583       break;
584     case ReferrerChainEntry::RENDERER_INITIATED_WITH_USER_GESTURE:
585       navigation_initiation = "RENDERER_INITIATED_WITH_USER_GESTURE";
586       break;
587   }
588   referrer_dict.SetKey("navigation_initiation",
589                        base::Value(navigation_initiation));
590 
591   referrer_dict.SetKey(
592       "maybe_launched_by_external_application",
593       base::Value(referrer.maybe_launched_by_external_application()));
594 
595   return std::move(referrer_dict);
596 }
597 
SerializeClientDownloadRequest(const ClientDownloadRequest & cdr)598 std::string SerializeClientDownloadRequest(const ClientDownloadRequest& cdr) {
599   base::DictionaryValue dict;
600   if (cdr.has_url())
601     dict.SetString("url", cdr.url());
602   if (cdr.has_download_type())
603     dict.SetInteger("download_type", cdr.download_type());
604   if (cdr.has_length())
605     dict.SetInteger("length", cdr.length());
606   if (cdr.has_file_basename())
607     dict.SetString("file_basename", cdr.file_basename());
608   if (cdr.has_archive_valid())
609     dict.SetBoolean("archive_valid", cdr.archive_valid());
610 
611   auto archived_binaries = std::make_unique<base::ListValue>();
612   for (const auto& archived_binary : cdr.archived_binary()) {
613     auto dict_archived_binary = std::make_unique<base::DictionaryValue>();
614     if (archived_binary.has_file_basename())
615       dict_archived_binary->SetString("file_basename",
616                                       archived_binary.file_basename());
617     if (archived_binary.has_download_type())
618       dict_archived_binary->SetInteger("download_type",
619                                        archived_binary.download_type());
620     if (archived_binary.has_length())
621       dict_archived_binary->SetInteger("length", archived_binary.length());
622     if (archived_binary.is_encrypted())
623       dict_archived_binary->SetBoolean("is_encrypted", true);
624     if (archived_binary.digests().has_sha256()) {
625       const std::string& sha256 = archived_binary.digests().sha256();
626       dict_archived_binary->SetString(
627           "digests.sha256", base::HexEncode(sha256.c_str(), sha256.size()));
628     }
629     archived_binaries->Append(std::move(dict_archived_binary));
630   }
631   dict.SetList("archived_binary", std::move(archived_binaries));
632 
633   auto referrer_chain = std::make_unique<base::ListValue>();
634   for (const auto& referrer_chain_entry : cdr.referrer_chain()) {
635     referrer_chain->Append(SerializeReferrer(referrer_chain_entry));
636   }
637   dict.SetList("referrer_chain", std::move(referrer_chain));
638 
639   dict.SetBoolean("request_ap_verdicts", cdr.request_ap_verdicts());
640 
641   dict.SetInteger("archive_file_count", cdr.archive_file_count());
642   dict.SetInteger("archive_directory_count", cdr.archive_directory_count());
643 
644   dict.SetBoolean("request_ap_verdicts", cdr.request_ap_verdicts());
645 
646   if (!cdr.access_token().empty())
647     dict.SetString("access_token", cdr.access_token());
648 
649   base::Value* request_tree = &dict;
650   std::string request_serialized;
651   JSONStringValueSerializer serializer(&request_serialized);
652   serializer.set_pretty_print(true);
653   serializer.Serialize(*request_tree);
654   return request_serialized;
655 }
656 
SerializeClientDownloadResponse(const ClientDownloadResponse & cdr)657 std::string SerializeClientDownloadResponse(const ClientDownloadResponse& cdr) {
658   base::DictionaryValue dict;
659 
660   switch (cdr.verdict()) {
661     case ClientDownloadResponse::SAFE:
662       dict.SetKey("verdict", base::Value("SAFE"));
663       break;
664     case ClientDownloadResponse::DANGEROUS:
665       dict.SetKey("verdict", base::Value("DANGEROUS"));
666       break;
667     case ClientDownloadResponse::UNCOMMON:
668       dict.SetKey("verdict", base::Value("UNCOMMON"));
669       break;
670     case ClientDownloadResponse::POTENTIALLY_UNWANTED:
671       dict.SetKey("verdict", base::Value("POTENTIALLY_UNWANTED"));
672       break;
673     case ClientDownloadResponse::DANGEROUS_HOST:
674       dict.SetKey("verdict", base::Value("DANGEROUS_HOST"));
675       break;
676     case ClientDownloadResponse::UNKNOWN:
677       dict.SetKey("verdict", base::Value("UNKNOWN"));
678       break;
679   }
680 
681   if (cdr.has_more_info()) {
682     dict.SetPath({"more_info", "description"},
683                  base::Value(cdr.more_info().description()));
684     dict.SetPath({"more_info", "url"}, base::Value(cdr.more_info().url()));
685   }
686 
687   if (cdr.has_token()) {
688     dict.SetKey("token", base::Value(cdr.token()));
689   }
690 
691   if (cdr.has_upload()) {
692     dict.SetKey("upload", base::Value(cdr.upload()));
693   }
694 
695   base::Value* request_tree = &dict;
696   std::string request_serialized;
697   JSONStringValueSerializer serializer(&request_serialized);
698   serializer.set_pretty_print(true);
699   serializer.Serialize(*request_tree);
700   return request_serialized;
701 }
702 
SerializeCSBRR(const ClientSafeBrowsingReportRequest & report)703 std::string SerializeCSBRR(const ClientSafeBrowsingReportRequest& report) {
704   base::DictionaryValue report_request;
705   if (report.has_type()) {
706     report_request.SetInteger("type", static_cast<int>(report.type()));
707   }
708   if (report.has_page_url())
709     report_request.SetString("page_url", report.page_url());
710   if (report.has_client_country()) {
711     report_request.SetString("client_country", report.client_country());
712   }
713   if (report.has_repeat_visit()) {
714     report_request.SetInteger("repeat_visit", report.repeat_visit());
715   }
716   if (report.has_did_proceed()) {
717     report_request.SetInteger("did_proceed", report.did_proceed());
718   }
719   std::string serialized;
720   if (report.SerializeToString(&serialized)) {
721     std::string base64_encoded;
722     base::Base64Encode(serialized, &base64_encoded);
723     report_request.SetString("csbrr(base64)", base64_encoded);
724   }
725 
726   base::Value* report_request_tree = &report_request;
727   std::string report_request_serialized;
728   JSONStringValueSerializer serializer(&report_request_serialized);
729   serializer.set_pretty_print(true);
730   serializer.Serialize(*report_request_tree);
731   return report_request_serialized;
732 }
733 
SerializeReuseLookup(const PasswordReuseLookup password_reuse_lookup)734 base::Value SerializeReuseLookup(
735     const PasswordReuseLookup password_reuse_lookup) {
736   std::string lookup_result;
737   switch (password_reuse_lookup.lookup_result()) {
738     case PasswordReuseLookup::UNSPECIFIED:
739       lookup_result = "UNSPECIFIED";
740       break;
741     case PasswordReuseLookup::WHITELIST_HIT:
742       lookup_result = "WHITELIST_HIT";
743       break;
744     case PasswordReuseLookup::CACHE_HIT:
745       lookup_result = "CACHE_HIT";
746       break;
747     case PasswordReuseLookup::REQUEST_SUCCESS:
748       lookup_result = "REQUEST_SUCCESS";
749       break;
750     case PasswordReuseLookup::REQUEST_FAILURE:
751       lookup_result = "REQUEST_FAILURE";
752       break;
753     case PasswordReuseLookup::URL_UNSUPPORTED:
754       lookup_result = "URL_UNSUPPORTED";
755       break;
756     case PasswordReuseLookup::ENTERPRISE_WHITELIST_HIT:
757       lookup_result = "ENTERPRISE_WHITELIST_HIT";
758       break;
759     case PasswordReuseLookup::TURNED_OFF_BY_POLICY:
760       lookup_result = "TURNED_OFF_BY_POLICY";
761       break;
762   }
763   return base::Value(lookup_result);
764 }
765 
SerializeVerdict(const PasswordReuseLookup password_reuse_lookup)766 base::Value SerializeVerdict(const PasswordReuseLookup password_reuse_lookup) {
767   std::string verdict;
768   switch (password_reuse_lookup.verdict()) {
769     case PasswordReuseLookup::VERDICT_UNSPECIFIED:
770       verdict = "VERDICT_UNSPECIFIED";
771       break;
772     case PasswordReuseLookup::SAFE:
773       verdict = "SAFE";
774       break;
775     case PasswordReuseLookup::LOW_REPUTATION:
776       verdict = "LOW_REPUTATION";
777       break;
778     case PasswordReuseLookup::PHISHING:
779       verdict = "PHISHING";
780       break;
781   }
782   return base::Value(verdict);
783 }
784 
SerializePGEvent(const sync_pb::UserEventSpecifics & event)785 base::DictionaryValue SerializePGEvent(
786     const sync_pb::UserEventSpecifics& event) {
787   base::DictionaryValue result;
788 
789   base::Time timestamp = base::Time::FromDeltaSinceWindowsEpoch(
790       base::TimeDelta::FromMicroseconds(event.event_time_usec()));
791   result.SetDouble("time", timestamp.ToJsTime());
792 
793   base::DictionaryValue event_dict;
794 
795   // Nominally only one of the following if() statements would be true.
796   // Note that top-level path is either password_captured, or one of the fields
797   // under GaiaPasswordReuse (ie. we've flattened the namespace for simplicity).
798 
799   if (event.has_gaia_password_captured_event()) {
800     std::string event_trigger;
801 
802     switch (event.gaia_password_captured_event().event_trigger()) {
803       case PasswordCaptured::UNSPECIFIED:
804         event_trigger = "UNSPECIFIED";
805         break;
806       case PasswordCaptured::USER_LOGGED_IN:
807         event_trigger = "USER_LOGGED_IN";
808         break;
809       case PasswordCaptured::EXPIRED_28D_TIMER:
810         event_trigger = "EXPIRED_28D_TIMER";
811         break;
812     }
813 
814     event_dict.SetPath({"password_captured", "event_trigger"},
815                        base::Value(event_trigger));
816   }
817 
818   GaiaPasswordReuse reuse = event.gaia_password_reuse_event();
819   if (reuse.has_reuse_detected()) {
820     event_dict.SetPath({"reuse_detected", "status", "enabled"},
821                        base::Value(reuse.reuse_detected().status().enabled()));
822 
823     std::string reporting_population;
824     switch (
825         reuse.reuse_detected().status().safe_browsing_reporting_population()) {
826       case PasswordReuseDetected::SafeBrowsingStatus::
827           REPORTING_POPULATION_UNSPECIFIED:
828         reporting_population = "REPORTING_POPULATION_UNSPECIFIED";
829         break;
830       case PasswordReuseDetected::SafeBrowsingStatus::NONE:
831         reporting_population = "NONE";
832         break;
833       case PasswordReuseDetected::SafeBrowsingStatus::EXTENDED_REPORTING:
834         reporting_population = "EXTENDED_REPORTING";
835         break;
836       case PasswordReuseDetected::SafeBrowsingStatus::SCOUT:
837         reporting_population = "SCOUT";
838         break;
839     }
840     event_dict.SetPath({"reuse_detected", "status", "reporting_population"},
841                        base::Value(reporting_population));
842   }
843 
844   if (reuse.has_reuse_lookup()) {
845     event_dict.SetPath({"reuse_lookup", "lookup_result"},
846                        SerializeReuseLookup(reuse.reuse_lookup()));
847     event_dict.SetPath({"reuse_lookup", "verdict"},
848                        SerializeVerdict(reuse.reuse_lookup()));
849     event_dict.SetPath({"reuse_lookup", "verdict_token"},
850                        base::Value(reuse.reuse_lookup().verdict_token()));
851   }
852 
853   if (reuse.has_dialog_interaction()) {
854     std::string interaction_result;
855     switch (reuse.dialog_interaction().interaction_result()) {
856       case PasswordReuseDialogInteraction::UNSPECIFIED:
857         interaction_result = "UNSPECIFIED";
858         break;
859       case PasswordReuseDialogInteraction::WARNING_ACTION_TAKEN:
860         interaction_result = "WARNING_ACTION_TAKEN";
861         break;
862       case PasswordReuseDialogInteraction::WARNING_ACTION_IGNORED:
863         interaction_result = "WARNING_ACTION_IGNORED";
864         break;
865       case PasswordReuseDialogInteraction::WARNING_UI_IGNORED:
866         interaction_result = "WARNING_UI_IGNORED";
867         break;
868       case PasswordReuseDialogInteraction::WARNING_ACTION_TAKEN_ON_SETTINGS:
869         interaction_result = "WARNING_ACTION_TAKEN_ON_SETTINGS";
870         break;
871     }
872     event_dict.SetPath({"dialog_interaction", "interaction_result"},
873                        base::Value(interaction_result));
874   }
875 
876   std::string event_serialized;
877   JSONStringValueSerializer serializer(&event_serialized);
878   serializer.set_pretty_print(true);
879   serializer.Serialize(event_dict);
880   result.SetString("message", event_serialized);
881   return result;
882 }
883 
SerializeSecurityEvent(const sync_pb::GaiaPasswordReuse & event)884 base::DictionaryValue SerializeSecurityEvent(
885     const sync_pb::GaiaPasswordReuse& event) {
886   base::DictionaryValue result;
887 
888   base::DictionaryValue event_dict;
889   if (event.has_reuse_lookup()) {
890     event_dict.SetPath({"reuse_lookup", "lookup_result"},
891                        SerializeReuseLookup(event.reuse_lookup()));
892     event_dict.SetPath({"reuse_lookup", "verdict"},
893                        SerializeVerdict(event.reuse_lookup()));
894     event_dict.SetPath({"reuse_lookup", "verdict_token"},
895                        base::Value(event.reuse_lookup().verdict_token()));
896   }
897 
898   std::string event_serialized;
899   JSONStringValueSerializer serializer(&event_serialized);
900   serializer.set_pretty_print(true);
901   serializer.Serialize(event_dict);
902   result.SetString("message", event_serialized);
903   return result;
904 }
905 
SerializeFrame(const LoginReputationClientRequest::Frame & frame)906 base::Value SerializeFrame(const LoginReputationClientRequest::Frame& frame) {
907   base::DictionaryValue frame_dict;
908   frame_dict.SetKey("frame_index", base::Value(frame.frame_index()));
909   frame_dict.SetKey("parent_frame_index",
910                     base::Value(frame.parent_frame_index()));
911   frame_dict.SetKey("url", base::Value(frame.url()));
912   frame_dict.SetKey("has_password_field",
913                     base::Value(frame.has_password_field()));
914 
915   base::ListValue referrer_list;
916   for (const ReferrerChainEntry& referrer : frame.referrer_chain()) {
917     referrer_list.Append(SerializeReferrer(referrer));
918   }
919   frame_dict.SetKey("referrer_chain", std::move(referrer_list));
920 
921   frame_dict.SetPath(
922       {"referrer_chain_options", "recent_navigations_to_collect"},
923       base::Value(
924           frame.referrer_chain_options().recent_navigations_to_collect()));
925 
926   base::ListValue form_list;
927   for (const LoginReputationClientRequest::Frame::Form& form : frame.forms()) {
928     base::DictionaryValue form_dict;
929     form_dict.SetKey("action_url", base::Value(form.action_url()));
930     form_dict.SetKey("has_password_field",
931                      base::Value(form.has_password_field()));
932     form_list.Append(std::move(form_dict));
933   }
934   frame_dict.SetKey("forms", std::move(form_list));
935 
936   return std::move(frame_dict);
937 }
938 
SerializePasswordReuseEvent(const LoginReputationClientRequest::PasswordReuseEvent & event)939 base::Value SerializePasswordReuseEvent(
940     const LoginReputationClientRequest::PasswordReuseEvent& event) {
941   base::DictionaryValue event_dict;
942 
943   base::ListValue domains_list;
944   for (const std::string& domain : event.domains_matching_password()) {
945     domains_list.Append(base::Value(domain));
946   }
947   event_dict.SetKey("domains_matching_password", std::move(domains_list));
948 
949   event_dict.SetKey("frame_id", base::Value(event.frame_id()));
950   event_dict.SetKey("is_chrome_signin_password",
951                     base::Value(event.is_chrome_signin_password()));
952 
953   std::string sync_account_type;
954   switch (event.sync_account_type()) {
955     case LoginReputationClientRequest::PasswordReuseEvent::NOT_SIGNED_IN:
956       sync_account_type = "NOT_SIGNED_IN";
957       break;
958     case LoginReputationClientRequest::PasswordReuseEvent::GMAIL:
959       sync_account_type = "GMAIL";
960       break;
961     case LoginReputationClientRequest::PasswordReuseEvent::GSUITE:
962       sync_account_type = "GSUITE";
963       break;
964   }
965   event_dict.SetKey("sync_account_type", base::Value(sync_account_type));
966 
967   std::string reused_password_type;
968   switch (event.reused_password_type()) {
969     case LoginReputationClientRequest::PasswordReuseEvent::
970         REUSED_PASSWORD_TYPE_UNKNOWN:
971       reused_password_type = "REUSED_PASSWORD_TYPE_UNKNOWN";
972       break;
973     case LoginReputationClientRequest::PasswordReuseEvent::SAVED_PASSWORD:
974       reused_password_type = "SAVED_PASSWORD";
975       break;
976     case LoginReputationClientRequest::PasswordReuseEvent::SIGN_IN_PASSWORD:
977       reused_password_type = "SIGN_IN_PASSWORD";
978       break;
979     case LoginReputationClientRequest::PasswordReuseEvent::OTHER_GAIA_PASSWORD:
980       reused_password_type = "OTHER_GAIA_PASSWORD";
981       break;
982     case LoginReputationClientRequest::PasswordReuseEvent::ENTERPRISE_PASSWORD:
983       reused_password_type = "ENTERPRISE_PASSWORD";
984       break;
985   }
986   event_dict.SetKey("reused_password_type", base::Value(reused_password_type));
987 
988   return std::move(event_dict);
989 }
990 
SerializeChromeUserPopulation(const ChromeUserPopulation & population)991 base::Value SerializeChromeUserPopulation(
992     const ChromeUserPopulation& population) {
993   base::DictionaryValue population_dict;
994 
995   std::string user_population;
996   switch (population.user_population()) {
997     case ChromeUserPopulation::UNKNOWN_USER_POPULATION:
998       user_population = "UNKNOWN_USER_POPULATION";
999       break;
1000     case ChromeUserPopulation::SAFE_BROWSING:
1001       user_population = "SAFE_BROWSING";
1002       break;
1003     case ChromeUserPopulation::EXTENDED_REPORTING:
1004       user_population = "EXTENDED_REPORTING";
1005       break;
1006     case ChromeUserPopulation::ENHANCED_PROTECTION:
1007       user_population = "ENHANCED_PROTECTION";
1008       break;
1009   }
1010   population_dict.SetKey("user_population", base::Value(user_population));
1011 
1012   population_dict.SetKey("is_history_sync_enabled",
1013                          base::Value(population.is_history_sync_enabled()));
1014 
1015   base::ListValue finch_list;
1016   for (const std::string& finch_group : population.finch_active_groups()) {
1017     finch_list.Append(base::Value(finch_group));
1018   }
1019   population_dict.SetKey("finch_active_groups", std::move(finch_list));
1020 
1021   std::string management_status;
1022   switch (population.profile_management_status()) {
1023     case ChromeUserPopulation::UNKNOWN:
1024       management_status = "UNKNOWN";
1025       break;
1026     case ChromeUserPopulation::UNAVAILABLE:
1027       management_status = "UNAVAILABLE";
1028       break;
1029     case ChromeUserPopulation::NOT_MANAGED:
1030       management_status = "NOT_MANAGED";
1031       break;
1032     case ChromeUserPopulation::ENTERPRISE_MANAGED:
1033       management_status = "ENTERPRISE_MANAGED";
1034       break;
1035   }
1036   population_dict.SetKey("profile_management_status",
1037                          base::Value(management_status));
1038   population_dict.SetKey(
1039       "is_under_advanced_protection",
1040       base::Value(population.is_under_advanced_protection()));
1041   population_dict.SetKey("is_incognito",
1042                          base::Value(population.is_incognito()));
1043 
1044   return std::move(population_dict);
1045 }
1046 
SerializeRTThreatInfo(const RTLookupResponse::ThreatInfo & threat_info)1047 base::Value SerializeRTThreatInfo(
1048     const RTLookupResponse::ThreatInfo& threat_info) {
1049   base::DictionaryValue threat_info_dict;
1050   std::string threat_type;
1051   switch (threat_info.threat_type()) {
1052     case RTLookupResponse::ThreatInfo::THREAT_TYPE_UNSPECIFIED:
1053       threat_type = "THREAT_TYPE_UNSPECIFIED";
1054       break;
1055     case RTLookupResponse::ThreatInfo::WEB_MALWARE:
1056       threat_type = "WEB_MALWARE";
1057       break;
1058     case RTLookupResponse::ThreatInfo::SOCIAL_ENGINEERING:
1059       threat_type = "SOCIAL_ENGINEERING";
1060       break;
1061     case RTLookupResponse::ThreatInfo::UNWANTED_SOFTWARE:
1062       threat_type = "UNWANTED_SOFTWARE";
1063       break;
1064     case RTLookupResponse::ThreatInfo::UNCLEAR_BILLING:
1065       threat_type = "UNCLEAR_BILLING";
1066       break;
1067   }
1068   threat_info_dict.SetKey("threat_type", base::Value(threat_type));
1069 
1070   threat_info_dict.SetKey(
1071       "cache_duration_sec",
1072       base::Value(static_cast<double>(threat_info.cache_duration_sec())));
1073 
1074   threat_info_dict.SetKey("cache_expression",
1075                           base::Value(threat_info.cache_expression()));
1076 
1077   std::string verdict_type;
1078   switch (threat_info.verdict_type()) {
1079     case RTLookupResponse::ThreatInfo::VERDICT_TYPE_UNSPECIFIED:
1080       verdict_type = "VERDICT_TYPE_UNSPECIFIED";
1081       break;
1082     case RTLookupResponse::ThreatInfo::SAFE:
1083       verdict_type = "SAFE";
1084       break;
1085     case RTLookupResponse::ThreatInfo::DANGEROUS:
1086       verdict_type = "DANGEROUS";
1087       break;
1088   }
1089   threat_info_dict.SetKey("verdict_type", base::Value(verdict_type));
1090 
1091   std::string cache_expression_match_type;
1092   switch (threat_info.cache_expression_match_type()) {
1093     case RTLookupResponse::ThreatInfo::MATCH_TYPE_UNSPECIFIED:
1094       cache_expression_match_type = "MATCH_TYPE_UNSPECIFIED";
1095       break;
1096     case RTLookupResponse::ThreatInfo::COVERING_MATCH:
1097       cache_expression_match_type = "COVERING_MATCH";
1098       break;
1099     case RTLookupResponse::ThreatInfo::EXACT_MATCH:
1100       cache_expression_match_type = "EXACT_MATCH";
1101       break;
1102   }
1103 
1104   threat_info_dict.SetKey("cache_expression_match_type",
1105                           base::Value(cache_expression_match_type));
1106   threat_info_dict.SetKey(
1107       "cache_expression_using_match_type",
1108       base::Value(threat_info.cache_expression_using_match_type()));
1109   return std::move(threat_info_dict);
1110 }
1111 
SerializeDomFeatures(const DomFeatures & dom_features)1112 base::Value SerializeDomFeatures(const DomFeatures& dom_features) {
1113   base::DictionaryValue dom_features_dict;
1114   auto feature_map = std::make_unique<base::ListValue>();
1115   for (const auto& feature : dom_features.feature_map()) {
1116     auto feature_dict = std::make_unique<base::DictionaryValue>();
1117     feature_dict->SetStringKey("name", feature.name());
1118     feature_dict->SetDoubleKey("value", feature.value());
1119     feature_map->Append(std::move(feature_dict));
1120   }
1121   dom_features_dict.SetList("feature_map", std::move(feature_map));
1122 
1123   auto shingle_hashes = std::make_unique<base::ListValue>();
1124   for (const auto& hash : dom_features.shingle_hashes()) {
1125     shingle_hashes->AppendInteger(hash);
1126   }
1127   dom_features_dict.SetList("shingle_hashes", std::move(shingle_hashes));
1128 
1129   dom_features_dict.SetInteger("model_version", dom_features.model_version());
1130 
1131   return std::move(dom_features_dict);
1132 }
1133 
SerializePGPing(const LoginReputationClientRequest & request)1134 std::string SerializePGPing(const LoginReputationClientRequest& request) {
1135   base::DictionaryValue request_dict;
1136 
1137   request_dict.SetKey("page_url", base::Value(request.page_url()));
1138 
1139   std::string trigger_type;
1140   switch (request.trigger_type()) {
1141     case LoginReputationClientRequest::TRIGGER_TYPE_UNSPECIFIED:
1142       trigger_type = "TRIGGER_TYPE_UNSPECIFIED";
1143       break;
1144     case LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE:
1145       trigger_type = "UNFAMILIAR_LOGIN_PAGE";
1146       break;
1147     case LoginReputationClientRequest::PASSWORD_REUSE_EVENT:
1148       trigger_type = "PASSWORD_REUSE_EVENT";
1149       break;
1150   }
1151   request_dict.SetKey("trigger_type", base::Value(trigger_type));
1152 
1153   base::ListValue frames_list;
1154   for (const LoginReputationClientRequest::Frame& frame : request.frames()) {
1155     frames_list.Append(SerializeFrame(frame));
1156   }
1157   request_dict.SetKey("frames", std::move(frames_list));
1158 
1159   request_dict.SetKey(
1160       "password_reuse_event",
1161       SerializePasswordReuseEvent(request.password_reuse_event()));
1162   request_dict.SetKey("stored_verdict_cnt",
1163                       base::Value(request.stored_verdict_cnt()));
1164   request_dict.SetKey("population",
1165                       SerializeChromeUserPopulation(request.population()));
1166   request_dict.SetKey("clicked_through_interstitial",
1167                       base::Value(request.clicked_through_interstitial()));
1168   request_dict.SetKey("content_type", base::Value(request.content_type()));
1169 
1170   if (request.has_content_area_height()) {
1171     request_dict.SetKey("content_area_height",
1172                         base::Value(request.content_area_height()));
1173   }
1174   if (request.has_content_area_width()) {
1175     request_dict.SetKey("content_area_width",
1176                         base::Value(request.content_area_width()));
1177   }
1178 
1179   if (request.has_dom_features()) {
1180     request_dict.SetKey("dom_features",
1181                         SerializeDomFeatures(request.dom_features()));
1182   }
1183 
1184   std::string request_serialized;
1185   JSONStringValueSerializer serializer(&request_serialized);
1186   serializer.set_pretty_print(true);
1187   serializer.Serialize(request_dict);
1188   return request_serialized;
1189 }
1190 
SerializePGResponse(const LoginReputationClientResponse & response)1191 std::string SerializePGResponse(const LoginReputationClientResponse& response) {
1192   base::DictionaryValue response_dict;
1193 
1194   std::string verdict;
1195   switch (response.verdict_type()) {
1196     case LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED:
1197       verdict = "VERDICT_TYPE_UNSPECIFIED";
1198       break;
1199     case LoginReputationClientResponse::SAFE:
1200       verdict = "SAFE";
1201       break;
1202     case LoginReputationClientResponse::LOW_REPUTATION:
1203       verdict = "LOW_REPUTATION";
1204       break;
1205     case LoginReputationClientResponse::PHISHING:
1206       verdict = "PHISHING";
1207       break;
1208   }
1209   response_dict.SetKey("verdict_type", base::Value(verdict));
1210   response_dict.SetKey("cache_duration_sec",
1211                        base::Value(int(response.cache_duration_sec())));
1212   response_dict.SetKey("cache_expression",
1213                        base::Value(response.cache_expression()));
1214   response_dict.SetKey("verdict_token", base::Value(response.verdict_token()));
1215 
1216   std::string response_serialized;
1217   JSONStringValueSerializer serializer(&response_serialized);
1218   serializer.set_pretty_print(true);
1219   serializer.Serialize(response_dict);
1220   return response_serialized;
1221 }
1222 
SerializeRTLookupPing(const RTLookupRequest & request)1223 std::string SerializeRTLookupPing(const RTLookupRequest& request) {
1224   base::DictionaryValue request_dict;
1225 
1226   request_dict.SetKey("url", base::Value(request.url()));
1227   request_dict.SetKey("population",
1228                       SerializeChromeUserPopulation(request.population()));
1229   request_dict.SetKey("scoped_oauth_token",
1230                       base::Value(request.scoped_oauth_token()));
1231 
1232   std::string lookupType;
1233   switch (request.lookup_type()) {
1234     case RTLookupRequest::LOOKUP_TYPE_UNSPECIFIED:
1235       lookupType = "LOOKUP_TYPE_UNSPECIFIED";
1236       break;
1237     case RTLookupRequest::NAVIGATION:
1238       lookupType = "NAVIGATION";
1239       break;
1240     case RTLookupRequest::DOWNLOAD:
1241       lookupType = "DOWNLOAD";
1242       break;
1243   }
1244 
1245   request_dict.SetKey("lookup_type", base::Value(lookupType));
1246 
1247   std::string request_serialized;
1248   JSONStringValueSerializer serializer(&request_serialized);
1249   serializer.set_pretty_print(true);
1250   serializer.Serialize(request_dict);
1251   return request_serialized;
1252 }
1253 
SerializeRTLookupResponse(const RTLookupResponse & response)1254 std::string SerializeRTLookupResponse(const RTLookupResponse& response) {
1255   base::DictionaryValue response_dict;
1256 
1257   base::ListValue threat_info_list;
1258   for (const RTLookupResponse::ThreatInfo& threat_info :
1259        response.threat_info()) {
1260     threat_info_list.Append(SerializeRTThreatInfo(threat_info));
1261   }
1262   response_dict.SetKey("threat_infos", std::move(threat_info_list));
1263 
1264   std::string response_serialized;
1265   JSONStringValueSerializer serializer(&response_serialized);
1266   serializer.set_pretty_print(true);
1267   serializer.Serialize(response_dict);
1268   return response_serialized;
1269 }
1270 
SerializeLogMessage(const base::Time & timestamp,const std::string & message)1271 base::Value SerializeLogMessage(const base::Time& timestamp,
1272                                 const std::string& message) {
1273   base::DictionaryValue result;
1274   result.SetDouble("time", timestamp.ToJsTime());
1275   result.SetString("message", message);
1276   return std::move(result);
1277 }
1278 
SerializeReportingEvent(const base::Value & event)1279 base::Value SerializeReportingEvent(const base::Value& event) {
1280   base::DictionaryValue result;
1281 
1282   std::string event_serialized;
1283   JSONStringValueSerializer serializer(&event_serialized);
1284   serializer.set_pretty_print(true);
1285   serializer.Serialize(event);
1286 
1287   result.SetString("message", event_serialized);
1288 
1289   return std::move(result);
1290 }
1291 
1292 #if BUILDFLAG(FULL_SAFE_BROWSING)
SerializeDeepScanningRequest(const DeepScanningClientRequest & request)1293 std::string SerializeDeepScanningRequest(
1294     const DeepScanningClientRequest& request) {
1295   base::DictionaryValue request_dict;
1296 
1297   request_dict.SetKey("dm_token", base::Value(request.dm_token()));
1298   request_dict.SetKey("fcm_notification_token",
1299                       base::Value(request.fcm_notification_token()));
1300 
1301   if (request.has_malware_scan_request()) {
1302     base::DictionaryValue malware_request;
1303 
1304     switch (request.malware_scan_request().population()) {
1305       case MalwareDeepScanningClientRequest::POPULATION_UNKNOWN:
1306         malware_request.SetStringKey("population", "POPULATION_UNKNOWN");
1307         break;
1308       case MalwareDeepScanningClientRequest::POPULATION_ENTERPRISE:
1309         malware_request.SetStringKey("population", "POPULATION_ENTERPRISE");
1310         break;
1311       case MalwareDeepScanningClientRequest::POPULATION_TITANIUM:
1312         malware_request.SetStringKey("population", "POPULATION_TITANIUM");
1313         break;
1314     }
1315 
1316     request_dict.SetKey("malware_scan_request", std::move(malware_request));
1317   }
1318 
1319   if (request.has_dlp_scan_request()) {
1320     base::DictionaryValue dlp_request;
1321 
1322     switch (request.dlp_scan_request().content_source()) {
1323       case DlpDeepScanningClientRequest::CONTENT_SOURCE_UNKNOWN:
1324         dlp_request.SetStringKey("content_source", "CONTENT_SOURCE_UNKNOWN");
1325         break;
1326       case DlpDeepScanningClientRequest::FILE_DOWNLOAD:
1327         dlp_request.SetStringKey("content_source", "FILE_DOWNLOAD");
1328         break;
1329       case DlpDeepScanningClientRequest::FILE_UPLOAD:
1330         dlp_request.SetStringKey("content_source", "FILE_UPLOAD");
1331         break;
1332       case DlpDeepScanningClientRequest::WEB_CONTENT_UPLOAD:
1333         dlp_request.SetStringKey("content_source", "WEB_CONTENT_UPLOAD");
1334         break;
1335     }
1336 
1337     request_dict.SetKey("dlp_scan_request", std::move(dlp_request));
1338   }
1339 
1340   request_dict.SetKey("request_token", base::Value(request.request_token()));
1341   request_dict.SetKey("filename", base::Value(request.filename()));
1342   request_dict.SetKey("digest", base::Value(request.digest()));
1343 
1344   std::string request_serialized;
1345   JSONStringValueSerializer serializer(&request_serialized);
1346   serializer.set_pretty_print(true);
1347   serializer.Serialize(request_dict);
1348   return request_serialized;
1349 }
1350 
SerializeDeepScanningResponse(const DeepScanningClientResponse & response)1351 std::string SerializeDeepScanningResponse(
1352     const DeepScanningClientResponse& response) {
1353   base::DictionaryValue response_dict;
1354 
1355   response_dict.SetStringKey("token", response.token());
1356 
1357   if (response.has_malware_scan_verdict()) {
1358     base::DictionaryValue malware_verdict;
1359 
1360     switch (response.malware_scan_verdict().verdict()) {
1361       case MalwareDeepScanningVerdict::VERDICT_UNSPECIFIED:
1362         malware_verdict.SetStringKey("verdict", "VERDICT_UNSPECIFIED");
1363         break;
1364       case MalwareDeepScanningVerdict::CLEAN:
1365         malware_verdict.SetStringKey("verdict", "CLEAN");
1366         break;
1367       case MalwareDeepScanningVerdict::UWS:
1368         malware_verdict.SetStringKey("verdict", "UWS");
1369         break;
1370       case MalwareDeepScanningVerdict::MALWARE:
1371         malware_verdict.SetStringKey("verdict", "MALWARE");
1372         break;
1373       case MalwareDeepScanningVerdict::SCAN_FAILURE:
1374         malware_verdict.SetStringKey("verdict", "SCAN_FAILURE");
1375         break;
1376     }
1377 
1378     response_dict.SetKey("malware_scan_verdict", std::move(malware_verdict));
1379   }
1380 
1381   if (response.has_dlp_scan_verdict()) {
1382     base::DictionaryValue dlp_verdict;
1383 
1384     switch (response.dlp_scan_verdict().status()) {
1385       case DlpDeepScanningVerdict::STATUS_UNKNOWN:
1386         dlp_verdict.SetStringKey("status", "STATUS_UNKNOWN");
1387         break;
1388       case DlpDeepScanningVerdict::SUCCESS:
1389         dlp_verdict.SetStringKey("status", "SUCCESS");
1390         break;
1391       case DlpDeepScanningVerdict::FAILURE:
1392         dlp_verdict.SetStringKey("status", "FAILURE");
1393         break;
1394     }
1395 
1396     base::ListValue triggered_rules;
1397     for (const DlpDeepScanningVerdict::TriggeredRule& rule :
1398          response.dlp_scan_verdict().triggered_rules()) {
1399       base::DictionaryValue rule_value;
1400 
1401       switch (rule.action()) {
1402         case DlpDeepScanningVerdict::TriggeredRule::ACTION_UNKNOWN:
1403           rule_value.SetStringKey("action", "ACTION_UNKNOWN");
1404           break;
1405         case DlpDeepScanningVerdict::TriggeredRule::REPORT_ONLY:
1406           rule_value.SetStringKey("action", "REPORT_ONLY");
1407           break;
1408         case DlpDeepScanningVerdict::TriggeredRule::WARN:
1409           rule_value.SetStringKey("action", "WARN");
1410           break;
1411         case DlpDeepScanningVerdict::TriggeredRule::BLOCK:
1412           rule_value.SetStringKey("action", "BLOCK");
1413           break;
1414       }
1415 
1416       rule_value.SetStringKey("rule_name", rule.rule_name());
1417       rule_value.SetDoubleKey("rule_id", rule.rule_id());
1418       rule_value.SetStringKey("rule_resource_name", rule.rule_resource_name());
1419       rule_value.SetStringKey("rule_severity", rule.rule_severity());
1420 
1421       base::ListValue matched_detectors;
1422       for (const DlpDeepScanningVerdict::MatchedDetector& detector :
1423            rule.matched_detectors()) {
1424         base::DictionaryValue detector_value;
1425         detector_value.SetStringKey("detector_id", detector.detector_id());
1426         detector_value.SetStringKey("display_name", detector.display_name());
1427         detector_value.SetStringKey("detector_type", detector.detector_type());
1428         matched_detectors.Append(std::move(detector_value));
1429       }
1430 
1431       rule_value.SetKey("matched_detectors", std::move(matched_detectors));
1432 
1433       triggered_rules.Append(std::move(rule_value));
1434     }
1435 
1436     dlp_verdict.SetKey("triggered_rules", std::move(triggered_rules));
1437   }
1438 
1439   std::string response_serialized;
1440   JSONStringValueSerializer serializer(&response_serialized);
1441   serializer.set_pretty_print(true);
1442   serializer.Serialize(response_dict);
1443   return response_serialized;
1444 }
1445 #endif
1446 }  // namespace
1447 
SafeBrowsingUI(content::WebUI * web_ui)1448 SafeBrowsingUI::SafeBrowsingUI(content::WebUI* web_ui)
1449     : content::WebUIController(web_ui) {
1450   // Set up the chrome://safe-browsing source.
1451 
1452   content::WebUIDataSource* html_source = content::WebUIDataSource::Create(
1453       safe_browsing::kChromeUISafeBrowsingHost);
1454 
1455   content::BrowserContext* browser_context =
1456       web_ui->GetWebContents()->GetBrowserContext();
1457 
1458   // Register callback handler.
1459   // Handles messages from JavaScript to C++ via chrome.send().
1460   web_ui->AddMessageHandler(
1461       std::make_unique<SafeBrowsingUIHandler>(browser_context));
1462 
1463   // Add required resources.
1464   html_source->AddResourcePath("safe_browsing.css", IDR_SAFE_BROWSING_CSS);
1465   html_source->AddResourcePath("safe_browsing.js", IDR_SAFE_BROWSING_JS);
1466   html_source->SetDefaultResource(IDR_SAFE_BROWSING_HTML);
1467 
1468   content::WebUIDataSource::Add(browser_context, html_source);
1469 }
1470 
~SafeBrowsingUI()1471 SafeBrowsingUI::~SafeBrowsingUI() {}
1472 
SafeBrowsingUIHandler(content::BrowserContext * context)1473 SafeBrowsingUIHandler::SafeBrowsingUIHandler(content::BrowserContext* context)
1474     : browser_context_(context) {}
1475 
~SafeBrowsingUIHandler()1476 SafeBrowsingUIHandler::~SafeBrowsingUIHandler() {
1477   WebUIInfoSingleton::GetInstance()->UnregisterWebUIInstance(this);
1478 }
1479 
OnJavascriptAllowed()1480 void SafeBrowsingUIHandler::OnJavascriptAllowed() {
1481   // We don't want to register the SafeBrowsingUIHandler with the
1482   // WebUIInfoSingleton at construction, since this can lead to
1483   // messages being sent to the renderer before it's ready. So register it here.
1484   WebUIInfoSingleton::GetInstance()->RegisterWebUIInstance(this);
1485 }
1486 
OnJavascriptDisallowed()1487 void SafeBrowsingUIHandler::OnJavascriptDisallowed() {
1488   // In certain situations, Javascript can become disallowed before the
1489   // destructor is called (e.g. tab refresh/renderer crash). In these situation,
1490   // we want to stop receiving JS messages.
1491   WebUIInfoSingleton::GetInstance()->UnregisterWebUIInstance(this);
1492 }
1493 
GetExperiments(const base::ListValue * args)1494 void SafeBrowsingUIHandler::GetExperiments(const base::ListValue* args) {
1495   AllowJavascript();
1496   std::string callback_id;
1497   args->GetString(0, &callback_id);
1498   ResolveJavascriptCallback(base::Value(callback_id), GetFeatureStatusList());
1499 }
1500 
GetPrefs(const base::ListValue * args)1501 void SafeBrowsingUIHandler::GetPrefs(const base::ListValue* args) {
1502   AllowJavascript();
1503   std::string callback_id;
1504   args->GetString(0, &callback_id);
1505   ResolveJavascriptCallback(base::Value(callback_id),
1506                             safe_browsing::GetSafeBrowsingPreferencesList(
1507                                 user_prefs::UserPrefs::Get(browser_context_)));
1508 }
1509 
GetCookie(const base::ListValue * args)1510 void SafeBrowsingUIHandler::GetCookie(const base::ListValue* args) {
1511   std::string callback_id;
1512   args->GetString(0, &callback_id);
1513 
1514   WebUIInfoSingleton::GetInstance()->GetCookieManager()->GetAllCookies(
1515       base::BindOnce(&SafeBrowsingUIHandler::OnGetCookie,
1516                      weak_factory_.GetWeakPtr(), std::move(callback_id)));
1517 }
1518 
OnGetCookie(const std::string & callback_id,const std::vector<net::CanonicalCookie> & cookies)1519 void SafeBrowsingUIHandler::OnGetCookie(
1520     const std::string& callback_id,
1521     const std::vector<net::CanonicalCookie>& cookies) {
1522   DCHECK_GE(1u, cookies.size());
1523 
1524   std::string cookie = "No cookie";
1525   double time = 0.0;
1526   if (!cookies.empty()) {
1527     cookie = cookies[0].Value();
1528     time = cookies[0].CreationDate().ToJsTime();
1529   }
1530 
1531   base::Value response(base::Value::Type::LIST);
1532   response.Append(base::Value(cookie));
1533   response.Append(base::Value(time));
1534 
1535   AllowJavascript();
1536   ResolveJavascriptCallback(base::Value(callback_id), std::move(response));
1537 }
1538 
GetSavedPasswords(const base::ListValue * args)1539 void SafeBrowsingUIHandler::GetSavedPasswords(const base::ListValue* args) {
1540   password_manager::HashPasswordManager hash_manager(
1541       user_prefs::UserPrefs::Get(browser_context_));
1542 
1543   base::ListValue saved_passwords;
1544   for (const password_manager::PasswordHashData& hash_data :
1545        hash_manager.RetrieveAllPasswordHashes()) {
1546     saved_passwords.AppendString(hash_data.username);
1547     saved_passwords.AppendBoolean(hash_data.is_gaia_password);
1548   }
1549 
1550   AllowJavascript();
1551   std::string callback_id;
1552   args->GetString(0, &callback_id);
1553   ResolveJavascriptCallback(base::Value(callback_id), saved_passwords);
1554 }
1555 
GetDatabaseManagerInfo(const base::ListValue * args)1556 void SafeBrowsingUIHandler::GetDatabaseManagerInfo(
1557     const base::ListValue* args) {
1558   base::ListValue database_manager_info;
1559 
1560 #if BUILDFLAG(SAFE_BROWSING_DB_LOCAL)
1561   const V4LocalDatabaseManager* local_database_manager_instance =
1562       V4LocalDatabaseManager::current_local_database_manager();
1563   if (local_database_manager_instance) {
1564     DatabaseManagerInfo database_manager_info_proto;
1565     FullHashCacheInfo full_hash_cache_info_proto;
1566 
1567     local_database_manager_instance->CollectDatabaseManagerInfo(
1568         &database_manager_info_proto, &full_hash_cache_info_proto);
1569 
1570     if (database_manager_info_proto.has_update_info()) {
1571       AddUpdateInfo(database_manager_info_proto.update_info(),
1572                     &database_manager_info);
1573     }
1574     if (database_manager_info_proto.has_database_info()) {
1575       AddDatabaseInfo(database_manager_info_proto.database_info(),
1576                       &database_manager_info);
1577     }
1578 
1579     database_manager_info.Append(
1580         base::Value(AddFullHashCacheInfo(full_hash_cache_info_proto)));
1581   }
1582 #endif
1583 
1584   AllowJavascript();
1585   std::string callback_id;
1586   args->GetString(0, &callback_id);
1587 
1588   ResolveJavascriptCallback(base::Value(callback_id), database_manager_info);
1589 }
1590 
GetSentClientDownloadRequests(const base::ListValue * args)1591 void SafeBrowsingUIHandler::GetSentClientDownloadRequests(
1592     const base::ListValue* args) {
1593   const std::vector<std::unique_ptr<ClientDownloadRequest>>& cdrs =
1594       WebUIInfoSingleton::GetInstance()->client_download_requests_sent();
1595 
1596   base::ListValue cdrs_sent;
1597 
1598   for (const auto& cdr : cdrs) {
1599     cdrs_sent.Append(base::Value(SerializeClientDownloadRequest(*cdr)));
1600   }
1601 
1602   AllowJavascript();
1603   std::string callback_id;
1604   args->GetString(0, &callback_id);
1605   ResolveJavascriptCallback(base::Value(callback_id), cdrs_sent);
1606 }
1607 
GetReceivedClientDownloadResponses(const base::ListValue * args)1608 void SafeBrowsingUIHandler::GetReceivedClientDownloadResponses(
1609     const base::ListValue* args) {
1610   const std::vector<std::unique_ptr<ClientDownloadResponse>>& cdrs =
1611       WebUIInfoSingleton::GetInstance()->client_download_responses_received();
1612 
1613   base::ListValue cdrs_received;
1614 
1615   for (const auto& cdr : cdrs) {
1616     cdrs_received.Append(base::Value(SerializeClientDownloadResponse(*cdr)));
1617   }
1618 
1619   AllowJavascript();
1620   std::string callback_id;
1621   args->GetString(0, &callback_id);
1622   ResolveJavascriptCallback(base::Value(callback_id), cdrs_received);
1623 }
1624 
GetSentCSBRRs(const base::ListValue * args)1625 void SafeBrowsingUIHandler::GetSentCSBRRs(const base::ListValue* args) {
1626   const std::vector<std::unique_ptr<ClientSafeBrowsingReportRequest>>& reports =
1627       WebUIInfoSingleton::GetInstance()->csbrrs_sent();
1628 
1629   base::ListValue sent_reports;
1630 
1631   for (const auto& report : reports) {
1632     sent_reports.Append(base::Value(SerializeCSBRR(*report)));
1633   }
1634 
1635   AllowJavascript();
1636   std::string callback_id;
1637   args->GetString(0, &callback_id);
1638   ResolveJavascriptCallback(base::Value(callback_id), sent_reports);
1639 }
1640 
GetPGEvents(const base::ListValue * args)1641 void SafeBrowsingUIHandler::GetPGEvents(const base::ListValue* args) {
1642   const std::vector<sync_pb::UserEventSpecifics>& events =
1643       WebUIInfoSingleton::GetInstance()->pg_event_log();
1644 
1645   base::ListValue events_sent;
1646 
1647   for (const sync_pb::UserEventSpecifics& event : events)
1648     events_sent.Append(SerializePGEvent(event));
1649 
1650   AllowJavascript();
1651   std::string callback_id;
1652   args->GetString(0, &callback_id);
1653   ResolveJavascriptCallback(base::Value(callback_id), events_sent);
1654 }
1655 
GetSecurityEvents(const base::ListValue * args)1656 void SafeBrowsingUIHandler::GetSecurityEvents(const base::ListValue* args) {
1657   const std::vector<sync_pb::GaiaPasswordReuse>& events =
1658       WebUIInfoSingleton::GetInstance()->security_event_log();
1659 
1660   base::ListValue events_sent;
1661 
1662   for (const sync_pb::GaiaPasswordReuse& event : events)
1663     events_sent.Append(SerializeSecurityEvent(event));
1664 
1665   AllowJavascript();
1666   std::string callback_id;
1667   args->GetString(0, &callback_id);
1668   ResolveJavascriptCallback(base::Value(callback_id), events_sent);
1669 }
1670 
GetPGPings(const base::ListValue * args)1671 void SafeBrowsingUIHandler::GetPGPings(const base::ListValue* args) {
1672   const std::vector<LoginReputationClientRequest> requests =
1673       WebUIInfoSingleton::GetInstance()->pg_pings();
1674 
1675   base::ListValue pings_sent;
1676   for (size_t request_index = 0; request_index < requests.size();
1677        request_index++) {
1678     base::ListValue ping_entry;
1679     ping_entry.Append(base::Value(int(request_index)));
1680     ping_entry.Append(base::Value(SerializePGPing(requests[request_index])));
1681     pings_sent.Append(std::move(ping_entry));
1682   }
1683 
1684   AllowJavascript();
1685   std::string callback_id;
1686   args->GetString(0, &callback_id);
1687   ResolveJavascriptCallback(base::Value(callback_id), pings_sent);
1688 }
1689 
GetPGResponses(const base::ListValue * args)1690 void SafeBrowsingUIHandler::GetPGResponses(const base::ListValue* args) {
1691   const std::map<int, LoginReputationClientResponse> responses =
1692       WebUIInfoSingleton::GetInstance()->pg_responses();
1693 
1694   base::ListValue responses_sent;
1695   for (const auto& token_and_response : responses) {
1696     base::ListValue response_entry;
1697     response_entry.Append(base::Value(token_and_response.first));
1698     response_entry.Append(
1699         base::Value(SerializePGResponse(token_and_response.second)));
1700     responses_sent.Append(std::move(response_entry));
1701   }
1702 
1703   AllowJavascript();
1704   std::string callback_id;
1705   args->GetString(0, &callback_id);
1706   ResolveJavascriptCallback(base::Value(callback_id), responses_sent);
1707 }
1708 
GetRTLookupPings(const base::ListValue * args)1709 void SafeBrowsingUIHandler::GetRTLookupPings(const base::ListValue* args) {
1710   const std::vector<RTLookupRequest> requests =
1711       WebUIInfoSingleton::GetInstance()->rt_lookup_pings();
1712 
1713   base::ListValue pings_sent;
1714   for (size_t request_index = 0; request_index < requests.size();
1715        request_index++) {
1716     base::ListValue ping_entry;
1717     ping_entry.Append(base::Value(int(request_index)));
1718     ping_entry.Append(
1719         base::Value(SerializeRTLookupPing(requests[request_index])));
1720     pings_sent.Append(std::move(ping_entry));
1721   }
1722 
1723   AllowJavascript();
1724   std::string callback_id;
1725   args->GetString(0, &callback_id);
1726   ResolveJavascriptCallback(base::Value(callback_id), pings_sent);
1727 }
1728 
GetRTLookupResponses(const base::ListValue * args)1729 void SafeBrowsingUIHandler::GetRTLookupResponses(const base::ListValue* args) {
1730   const std::map<int, RTLookupResponse> responses =
1731       WebUIInfoSingleton::GetInstance()->rt_lookup_responses();
1732 
1733   base::ListValue responses_sent;
1734   for (const auto& token_and_response : responses) {
1735     base::ListValue response_entry;
1736     response_entry.Append(base::Value(token_and_response.first));
1737     response_entry.Append(
1738         base::Value(SerializeRTLookupResponse(token_and_response.second)));
1739     responses_sent.Append(std::move(response_entry));
1740   }
1741 
1742   AllowJavascript();
1743   std::string callback_id;
1744   args->GetString(0, &callback_id);
1745   ResolveJavascriptCallback(base::Value(callback_id), responses_sent);
1746 }
1747 
GetRTLookupExperimentEnabled(const base::ListValue * args)1748 void SafeBrowsingUIHandler::GetRTLookupExperimentEnabled(
1749     const base::ListValue* args) {
1750   base::ListValue value;
1751   value.Append(base::Value(RealTimePolicyEngine::IsUrlLookupEnabled()));
1752 
1753   AllowJavascript();
1754   std::string callback_id;
1755   args->GetString(0, &callback_id);
1756   ResolveJavascriptCallback(base::Value(callback_id), value);
1757 }
1758 
GetReferrerChain(const base::ListValue * args)1759 void SafeBrowsingUIHandler::GetReferrerChain(const base::ListValue* args) {
1760   std::string url_string;
1761   args->GetString(1, &url_string);
1762 
1763   ReferrerChainProvider* provider =
1764       WebUIInfoSingleton::GetInstance()->referrer_chain_provider();
1765 
1766   std::string callback_id;
1767   args->GetString(0, &callback_id);
1768 
1769   if (!provider) {
1770     AllowJavascript();
1771     ResolveJavascriptCallback(base::Value(callback_id), base::Value(""));
1772     return;
1773   }
1774 
1775   ReferrerChain referrer_chain;
1776   provider->IdentifyReferrerChainByEventURL(
1777       GURL(url_string), SessionID::InvalidValue(), 2, &referrer_chain);
1778 
1779   base::ListValue referrer_list;
1780   for (const ReferrerChainEntry& entry : referrer_chain) {
1781     referrer_list.Append(SerializeReferrer(entry));
1782   }
1783 
1784   std::string referrer_chain_serialized;
1785   JSONStringValueSerializer serializer(&referrer_chain_serialized);
1786   serializer.set_pretty_print(true);
1787   serializer.Serialize(referrer_list);
1788 
1789   AllowJavascript();
1790   ResolveJavascriptCallback(base::Value(callback_id),
1791                             base::Value(referrer_chain_serialized));
1792 }
1793 
GetReportingEvents(const base::ListValue * args)1794 void SafeBrowsingUIHandler::GetReportingEvents(const base::ListValue* args) {
1795   base::ListValue reporting_events;
1796   for (const auto& reporting_event :
1797        WebUIInfoSingleton::GetInstance()->reporting_events()) {
1798     reporting_events.Append(reporting_event.Clone());
1799   }
1800 
1801   AllowJavascript();
1802   std::string callback_id;
1803   args->GetString(0, &callback_id);
1804   ResolveJavascriptCallback(base::Value(callback_id), reporting_events);
1805 }
1806 
GetLogMessages(const base::ListValue * args)1807 void SafeBrowsingUIHandler::GetLogMessages(const base::ListValue* args) {
1808   const std::vector<std::pair<base::Time, std::string>>& log_messages =
1809       WebUIInfoSingleton::GetInstance()->log_messages();
1810 
1811   base::ListValue messages_received;
1812   for (const auto& message : log_messages) {
1813     messages_received.Append(
1814         base::Value(SerializeLogMessage(message.first, message.second)));
1815   }
1816 
1817   AllowJavascript();
1818   std::string callback_id;
1819   args->GetString(0, &callback_id);
1820   ResolveJavascriptCallback(base::Value(callback_id), messages_received);
1821 }
1822 
1823 #if BUILDFLAG(FULL_SAFE_BROWSING)
GetDeepScanRequests(const base::ListValue * args)1824 void SafeBrowsingUIHandler::GetDeepScanRequests(const base::ListValue* args) {
1825   base::ListValue pings_sent;
1826   for (const auto& token_and_request :
1827        WebUIInfoSingleton::GetInstance()->deep_scan_requests()) {
1828     base::ListValue ping_entry;
1829     ping_entry.Append(base::Value(token_and_request.first));
1830     ping_entry.Append(
1831         base::Value(SerializeDeepScanningRequest(token_and_request.second)));
1832     pings_sent.Append(std::move(ping_entry));
1833   }
1834 
1835   AllowJavascript();
1836   std::string callback_id;
1837   args->GetString(0, &callback_id);
1838   ResolveJavascriptCallback(base::Value(callback_id), pings_sent);
1839 }
1840 
GetDeepScanResponses(const base::ListValue * args)1841 void SafeBrowsingUIHandler::GetDeepScanResponses(const base::ListValue* args) {
1842   const WebUIInfoSingleton::StatusAndDeepScanningResponseMap& responses =
1843       WebUIInfoSingleton::GetInstance()->deep_scan_responses();
1844 
1845   base::ListValue responses_sent;
1846   for (const auto& token_and_status_and_response : responses) {
1847     const std::string& token = token_and_status_and_response.first;
1848     const std::string& status = token_and_status_and_response.second.first;
1849     const DeepScanningClientResponse& response =
1850         token_and_status_and_response.second.second;
1851 
1852     base::ListValue response_entry;
1853     response_entry.Append(base::Value(token));
1854     response_entry.Append(base::Value(status));
1855     response_entry.Append(base::Value(SerializeDeepScanningResponse(response)));
1856     responses_sent.Append(std::move(response_entry));
1857   }
1858 
1859   AllowJavascript();
1860   std::string callback_id;
1861   args->GetString(0, &callback_id);
1862   ResolveJavascriptCallback(base::Value(callback_id), responses_sent);
1863 }
1864 #endif
NotifyClientDownloadRequestJsListener(ClientDownloadRequest * client_download_request)1865 void SafeBrowsingUIHandler::NotifyClientDownloadRequestJsListener(
1866     ClientDownloadRequest* client_download_request) {
1867   AllowJavascript();
1868   FireWebUIListener(
1869       "sent-client-download-requests-update",
1870       base::Value(SerializeClientDownloadRequest(*client_download_request)));
1871 }
1872 
NotifyClientDownloadResponseJsListener(ClientDownloadResponse * client_download_response)1873 void SafeBrowsingUIHandler::NotifyClientDownloadResponseJsListener(
1874     ClientDownloadResponse* client_download_response) {
1875   AllowJavascript();
1876   FireWebUIListener(
1877       "received-client-download-responses-update",
1878       base::Value(SerializeClientDownloadResponse(*client_download_response)));
1879 }
1880 
NotifyCSBRRJsListener(ClientSafeBrowsingReportRequest * csbrr)1881 void SafeBrowsingUIHandler::NotifyCSBRRJsListener(
1882     ClientSafeBrowsingReportRequest* csbrr) {
1883   AllowJavascript();
1884   FireWebUIListener("sent-csbrr-update", base::Value(SerializeCSBRR(*csbrr)));
1885 }
1886 
NotifyPGEventJsListener(const sync_pb::UserEventSpecifics & event)1887 void SafeBrowsingUIHandler::NotifyPGEventJsListener(
1888     const sync_pb::UserEventSpecifics& event) {
1889   AllowJavascript();
1890   FireWebUIListener("sent-pg-event", SerializePGEvent(event));
1891 }
1892 
NotifySecurityEventJsListener(const sync_pb::GaiaPasswordReuse & event)1893 void SafeBrowsingUIHandler::NotifySecurityEventJsListener(
1894     const sync_pb::GaiaPasswordReuse& event) {
1895   AllowJavascript();
1896   FireWebUIListener("sent-security-event", SerializeSecurityEvent(event));
1897 }
1898 
NotifyPGPingJsListener(int token,const LoginReputationClientRequest & request)1899 void SafeBrowsingUIHandler::NotifyPGPingJsListener(
1900     int token,
1901     const LoginReputationClientRequest& request) {
1902   base::ListValue request_list;
1903   request_list.Append(base::Value(token));
1904   request_list.Append(base::Value(SerializePGPing(request)));
1905 
1906   AllowJavascript();
1907   FireWebUIListener("pg-pings-update", request_list);
1908 }
1909 
NotifyPGResponseJsListener(int token,const LoginReputationClientResponse & response)1910 void SafeBrowsingUIHandler::NotifyPGResponseJsListener(
1911     int token,
1912     const LoginReputationClientResponse& response) {
1913   base::ListValue response_list;
1914   response_list.Append(base::Value(token));
1915   response_list.Append(base::Value(SerializePGResponse(response)));
1916 
1917   AllowJavascript();
1918   FireWebUIListener("pg-responses-update", response_list);
1919 }
1920 
NotifyRTLookupPingJsListener(int token,const RTLookupRequest & request)1921 void SafeBrowsingUIHandler::NotifyRTLookupPingJsListener(
1922     int token,
1923     const RTLookupRequest& request) {
1924   base::ListValue request_list;
1925   request_list.Append(base::Value(token));
1926   request_list.Append(base::Value(SerializeRTLookupPing(request)));
1927 
1928   AllowJavascript();
1929   FireWebUIListener("rt-lookup-pings-update", request_list);
1930 }
1931 
NotifyRTLookupResponseJsListener(int token,const RTLookupResponse & response)1932 void SafeBrowsingUIHandler::NotifyRTLookupResponseJsListener(
1933     int token,
1934     const RTLookupResponse& response) {
1935   base::ListValue response_list;
1936   response_list.Append(base::Value(token));
1937   response_list.Append(base::Value(SerializeRTLookupResponse(response)));
1938 
1939   AllowJavascript();
1940   FireWebUIListener("rt-lookup-responses-update", response_list);
1941 }
1942 
NotifyLogMessageJsListener(const base::Time & timestamp,const std::string & message)1943 void SafeBrowsingUIHandler::NotifyLogMessageJsListener(
1944     const base::Time& timestamp,
1945     const std::string& message) {
1946   AllowJavascript();
1947   FireWebUIListener("log-messages-update",
1948                     base::Value(SerializeLogMessage(timestamp, message)));
1949 }
1950 
NotifyReportingEventJsListener(const base::Value & event)1951 void SafeBrowsingUIHandler::NotifyReportingEventJsListener(
1952     const base::Value& event) {
1953   AllowJavascript();
1954   FireWebUIListener("reporting-events-update", SerializeReportingEvent(event));
1955 }
1956 
1957 #if BUILDFLAG(FULL_SAFE_BROWSING)
NotifyDeepScanRequestJsListener(const DeepScanningClientRequest & request)1958 void SafeBrowsingUIHandler::NotifyDeepScanRequestJsListener(
1959     const DeepScanningClientRequest& request) {
1960   base::ListValue request_list;
1961   request_list.Append(base::Value(request.request_token()));
1962   request_list.Append(base::Value(SerializeDeepScanningRequest(request)));
1963 
1964   AllowJavascript();
1965   FireWebUIListener("deep-scan-request-update", request_list);
1966 }
1967 
NotifyDeepScanResponseJsListener(const std::string & token,const std::string & status,const DeepScanningClientResponse & response)1968 void SafeBrowsingUIHandler::NotifyDeepScanResponseJsListener(
1969     const std::string& token,
1970     const std::string& status,
1971     const DeepScanningClientResponse& response) {
1972   base::ListValue response_list;
1973   response_list.Append(base::Value(token));
1974   response_list.Append(base::Value(status));
1975   response_list.Append(base::Value(SerializeDeepScanningResponse(response)));
1976 
1977   AllowJavascript();
1978   FireWebUIListener("deep-scan-response-update", response_list);
1979 }
1980 #endif
1981 
RegisterMessages()1982 void SafeBrowsingUIHandler::RegisterMessages() {
1983   web_ui()->RegisterMessageCallback(
1984       "getExperiments",
1985       base::BindRepeating(&SafeBrowsingUIHandler::GetExperiments,
1986                           base::Unretained(this)));
1987   web_ui()->RegisterMessageCallback(
1988       "getPrefs", base::BindRepeating(&SafeBrowsingUIHandler::GetPrefs,
1989                                       base::Unretained(this)));
1990   web_ui()->RegisterMessageCallback(
1991       "getCookie", base::BindRepeating(&SafeBrowsingUIHandler::GetCookie,
1992                                        base::Unretained(this)));
1993   web_ui()->RegisterMessageCallback(
1994       "getSavedPasswords",
1995       base::BindRepeating(&SafeBrowsingUIHandler::GetSavedPasswords,
1996                           base::Unretained(this)));
1997   web_ui()->RegisterMessageCallback(
1998       "getDatabaseManagerInfo",
1999       base::BindRepeating(&SafeBrowsingUIHandler::GetDatabaseManagerInfo,
2000                           base::Unretained(this)));
2001   web_ui()->RegisterMessageCallback(
2002       "getSentClientDownloadRequests",
2003       base::BindRepeating(&SafeBrowsingUIHandler::GetSentClientDownloadRequests,
2004                           base::Unretained(this)));
2005   web_ui()->RegisterMessageCallback(
2006       "getReceivedClientDownloadResponses",
2007       base::BindRepeating(
2008           &SafeBrowsingUIHandler::GetReceivedClientDownloadResponses,
2009           base::Unretained(this)));
2010   web_ui()->RegisterMessageCallback(
2011       "getSentCSBRRs",
2012       base::BindRepeating(&SafeBrowsingUIHandler::GetSentCSBRRs,
2013                           base::Unretained(this)));
2014   web_ui()->RegisterMessageCallback(
2015       "getPGEvents", base::BindRepeating(&SafeBrowsingUIHandler::GetPGEvents,
2016                                          base::Unretained(this)));
2017   web_ui()->RegisterMessageCallback(
2018       "getSecurityEvents",
2019       base::BindRepeating(&SafeBrowsingUIHandler::GetSecurityEvents,
2020                           base::Unretained(this)));
2021   web_ui()->RegisterMessageCallback(
2022       "getPGPings", base::BindRepeating(&SafeBrowsingUIHandler::GetPGPings,
2023                                         base::Unretained(this)));
2024   web_ui()->RegisterMessageCallback(
2025       "getPGResponses",
2026       base::BindRepeating(&SafeBrowsingUIHandler::GetPGResponses,
2027                           base::Unretained(this)));
2028   web_ui()->RegisterMessageCallback(
2029       "getRTLookupPings",
2030       base::BindRepeating(&SafeBrowsingUIHandler::GetRTLookupPings,
2031                           base::Unretained(this)));
2032   web_ui()->RegisterMessageCallback(
2033       "getRTLookupResponses",
2034       base::BindRepeating(&SafeBrowsingUIHandler::GetRTLookupResponses,
2035                           base::Unretained(this)));
2036   web_ui()->RegisterMessageCallback(
2037       "getRTLookupExperimentEnabled",
2038       base::BindRepeating(&SafeBrowsingUIHandler::GetRTLookupExperimentEnabled,
2039                           base::Unretained(this)));
2040   web_ui()->RegisterMessageCallback(
2041       "getLogMessages",
2042       base::BindRepeating(&SafeBrowsingUIHandler::GetLogMessages,
2043                           base::Unretained(this)));
2044   web_ui()->RegisterMessageCallback(
2045       "getReferrerChain",
2046       base::BindRepeating(&SafeBrowsingUIHandler::GetReferrerChain,
2047                           base::Unretained(this)));
2048   web_ui()->RegisterMessageCallback(
2049       "getReportingEvents",
2050       base::BindRepeating(&SafeBrowsingUIHandler::GetReportingEvents,
2051                           base::Unretained(this)));
2052 #if BUILDFLAG(FULL_SAFE_BROWSING)
2053   web_ui()->RegisterMessageCallback(
2054       "getDeepScanRequests",
2055       base::BindRepeating(&SafeBrowsingUIHandler::GetDeepScanRequests,
2056                           base::Unretained(this)));
2057   web_ui()->RegisterMessageCallback(
2058       "getDeepScanResponses",
2059       base::BindRepeating(&SafeBrowsingUIHandler::GetDeepScanResponses,
2060                           base::Unretained(this)));
2061 #endif
2062 }
2063 
SetWebUIForTesting(content::WebUI * web_ui)2064 void SafeBrowsingUIHandler::SetWebUIForTesting(content::WebUI* web_ui) {
2065   set_web_ui(web_ui);
2066 }
2067 
CrSBLogMessage()2068 CrSBLogMessage::CrSBLogMessage() {}
2069 
~CrSBLogMessage()2070 CrSBLogMessage::~CrSBLogMessage() {
2071   WebUIInfoSingleton::GetInstance()->LogMessage(stream_.str());
2072   DLOG(WARNING) << stream_.str();
2073 }
2074 
2075 }  // namespace safe_browsing
2076