1 // Copyright 2020 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/ui/webui/nearby_internals/nearby_internals_http_handler.h"
6 
7 #include "base/bind.h"
8 #include "base/json/json_writer.h"
9 #include "base/time/time.h"
10 #include "base/values.h"
11 #include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager.h"
12 #include "chrome/browser/nearby_sharing/client/nearby_share_http_notifier.h"
13 #include "chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager.h"
14 #include "chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.h"
15 #include "chrome/browser/nearby_sharing/logging/logging.h"
16 #include "chrome/browser/nearby_sharing/logging/proto_to_dictionary_conversion.h"
17 #include "chrome/browser/nearby_sharing/nearby_sharing_service.h"
18 #include "chrome/browser/nearby_sharing/nearby_sharing_service_factory.h"
19 
20 namespace {
21 
22 // This enum class needs to stay in sync with the Rpc definition in
23 // chrome/browser/resources/nearby_internals/types.js.
24 enum class Rpc {
25   kCertificate = 0,
26   kContact = 1,
27   kDevice = 2,
28   kDeviceState = 3
29 };
30 
31 // This enum class needs to stay in sync with the Direction definition in
32 // chrome/browser/resources/nearby_internals/types.js.
33 enum class Direction { kRequest = 0, kResponse = 1 };
34 
FormatAsJSON(const base::Value & value)35 std::string FormatAsJSON(const base::Value& value) {
36   std::string json;
37   base::JSONWriter::WriteWithOptions(
38       value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
39   return json;
40 }
41 
GetJavascriptTimestamp()42 base::Value GetJavascriptTimestamp() {
43   return base::Value(base::Time::Now().ToJsTimeIgnoringNull());
44 }
45 
46 // FireWebUIListener message to notify the JavaScript of HTTP message addition.
47 const char kHttpMessageAdded[] = "http-message-added";
48 
49 // Keys in the JSON representation of a Http Message
50 const char kHttpMessageBodyKey[] = "body";
51 const char kHttpMessageTimeKey[] = "time";
52 const char kHttpMessageRpcKey[] = "rpc";
53 const char kHttpMessageDirectionKey[] = "direction";
54 
55 // Converts a RPC request/response to a raw dictionary value used as a
56 // JSON argument to JavaScript functions.
HttpMessageToDictionary(const base::Value & message,Direction dir,Rpc rpc)57 base::Value HttpMessageToDictionary(const base::Value& message,
58                                     Direction dir,
59                                     Rpc rpc) {
60   base::Value dictionary(base::Value::Type::DICTIONARY);
61   dictionary.SetStringKey(kHttpMessageBodyKey, FormatAsJSON(message));
62   dictionary.SetKey(kHttpMessageTimeKey, GetJavascriptTimestamp());
63   dictionary.SetIntKey(kHttpMessageRpcKey, static_cast<int>(rpc));
64   dictionary.SetIntKey(kHttpMessageDirectionKey, static_cast<int>(dir));
65   return dictionary;
66 }
67 
68 }  // namespace
69 
NearbyInternalsHttpHandler(content::BrowserContext * context)70 NearbyInternalsHttpHandler::NearbyInternalsHttpHandler(
71     content::BrowserContext* context)
72     : context_(context) {}
73 
74 NearbyInternalsHttpHandler::~NearbyInternalsHttpHandler() = default;
75 
RegisterMessages()76 void NearbyInternalsHttpHandler::RegisterMessages() {
77   web_ui()->RegisterMessageCallback(
78       "initializeHttp",
79       base::BindRepeating(&NearbyInternalsHttpHandler::InitializeContents,
80                           base::Unretained(this)));
81   web_ui()->RegisterMessageCallback(
82       "updateDevice",
83       base::BindRepeating(&NearbyInternalsHttpHandler::UpdateDevice,
84                           base::Unretained(this)));
85   web_ui()->RegisterMessageCallback(
86       "listContactPeople",
87       base::BindRepeating(&NearbyInternalsHttpHandler::ListContactPeople,
88                           base::Unretained(this)));
89   web_ui()->RegisterMessageCallback(
90       "listPublicCertificates",
91       base::BindRepeating(&NearbyInternalsHttpHandler::ListPublicCertificates,
92                           base::Unretained(this)));
93 }
94 
OnJavascriptAllowed()95 void NearbyInternalsHttpHandler::OnJavascriptAllowed() {
96   NearbySharingService* service_ =
97       NearbySharingServiceFactory::GetForBrowserContext(context_);
98   if (service_) {
99     observer_.Add(service_->GetHttpNotifier());
100   } else {
101     NS_LOG(ERROR) << "No NearbyShareService instance to call.";
102   }
103 }
104 
OnJavascriptDisallowed()105 void NearbyInternalsHttpHandler::OnJavascriptDisallowed() {
106   observer_.RemoveAll();
107 }
108 
InitializeContents(const base::ListValue * args)109 void NearbyInternalsHttpHandler::InitializeContents(
110     const base::ListValue* args) {
111   AllowJavascript();
112 }
113 
UpdateDevice(const base::ListValue * args)114 void NearbyInternalsHttpHandler::UpdateDevice(const base::ListValue* args) {
115   NearbySharingService* service_ =
116       NearbySharingServiceFactory::GetForBrowserContext(context_);
117   if (service_) {
118     service_->GetLocalDeviceDataManager()->DownloadDeviceData();
119   } else {
120     NS_LOG(ERROR) << "No NearbyShareService instance to call.";
121   }
122 }
123 
ListPublicCertificates(const base::ListValue * args)124 void NearbyInternalsHttpHandler::ListPublicCertificates(
125     const base::ListValue* args) {
126   NearbySharingService* service_ =
127       NearbySharingServiceFactory::GetForBrowserContext(context_);
128   if (service_) {
129     service_->GetCertificateManager()->DownloadPublicCertificates();
130   } else {
131     NS_LOG(ERROR) << "No NearbyShareService instance to call.";
132   }
133 }
134 
ListContactPeople(const base::ListValue * args)135 void NearbyInternalsHttpHandler::ListContactPeople(
136     const base::ListValue* args) {
137   NearbySharingService* service_ =
138       NearbySharingServiceFactory::GetForBrowserContext(context_);
139   if (service_) {
140     service_->GetContactManager()->DownloadContacts();
141   } else {
142     NS_LOG(ERROR) << "No NearbyShareService instance to call.";
143   }
144 }
145 
OnUpdateDeviceRequest(const nearbyshare::proto::UpdateDeviceRequest & request)146 void NearbyInternalsHttpHandler::OnUpdateDeviceRequest(
147     const nearbyshare::proto::UpdateDeviceRequest& request) {
148   FireWebUIListener(
149       kHttpMessageAdded,
150       HttpMessageToDictionary(UpdateDeviceRequestToReadableDictionary(request),
151                               Direction::kRequest, Rpc::kDevice));
152 }
153 
OnUpdateDeviceResponse(const nearbyshare::proto::UpdateDeviceResponse & response)154 void NearbyInternalsHttpHandler::OnUpdateDeviceResponse(
155     const nearbyshare::proto::UpdateDeviceResponse& response) {
156   FireWebUIListener(kHttpMessageAdded,
157                     HttpMessageToDictionary(
158                         UpdateDeviceResponseToReadableDictionary(response),
159                         Direction::kResponse, Rpc::kDevice));
160 }
161 
OnListContactPeopleRequest(const nearbyshare::proto::ListContactPeopleRequest & request)162 void NearbyInternalsHttpHandler::OnListContactPeopleRequest(
163     const nearbyshare::proto::ListContactPeopleRequest& request) {
164   FireWebUIListener(kHttpMessageAdded,
165                     HttpMessageToDictionary(
166                         ListContactPeopleRequestToReadableDictionary(request),
167                         Direction::kRequest, Rpc::kContact));
168 }
169 
OnListContactPeopleResponse(const nearbyshare::proto::ListContactPeopleResponse & response)170 void NearbyInternalsHttpHandler::OnListContactPeopleResponse(
171     const nearbyshare::proto::ListContactPeopleResponse& response) {
172   FireWebUIListener(kHttpMessageAdded,
173                     HttpMessageToDictionary(
174                         ListContactPeopleResponseToReadableDictionary(response),
175                         Direction::kResponse, Rpc::kContact));
176 }
177 
OnListPublicCertificatesRequest(const nearbyshare::proto::ListPublicCertificatesRequest & request)178 void NearbyInternalsHttpHandler::OnListPublicCertificatesRequest(
179     const nearbyshare::proto::ListPublicCertificatesRequest& request) {
180   FireWebUIListener(
181       kHttpMessageAdded,
182       HttpMessageToDictionary(
183           ListPublicCertificatesRequestToReadableDictionary(request),
184           Direction::kRequest, Rpc::kCertificate));
185 }
186 
OnListPublicCertificatesResponse(const nearbyshare::proto::ListPublicCertificatesResponse & response)187 void NearbyInternalsHttpHandler::OnListPublicCertificatesResponse(
188     const nearbyshare::proto::ListPublicCertificatesResponse& response) {
189   FireWebUIListener(
190       kHttpMessageAdded,
191       HttpMessageToDictionary(
192           ListPublicCertificatesResponseToReadableDictionary(response),
193           Direction::kResponse, Rpc::kCertificate));
194 }
195