Stack sampling profiler: add fire-and-forget interface
[chromium-blink-merge.git] / components / proximity_auth / webui / proximity_auth_webui_handler.cc
blobc71f04c14264be55b992c3659b05fc45e885d356
1 // Copyright 2015 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.
5 #include "components/proximity_auth/webui/proximity_auth_webui_handler.h"
7 #include "base/bind.h"
8 #include "base/i18n/time_formatting.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/time/default_clock.h"
11 #include "base/values.h"
12 #include "components/proximity_auth/cryptauth/base64url.h"
13 #include "components/proximity_auth/cryptauth/cryptauth_enrollment_manager.h"
14 #include "components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.h"
15 #include "components/proximity_auth/cryptauth/proto/cryptauth_api.pb.h"
16 #include "components/proximity_auth/logging/logging.h"
17 #include "components/proximity_auth/webui/cryptauth_enroller_factory_impl.h"
18 #include "components/proximity_auth/webui/proximity_auth_ui_delegate.h"
19 #include "content/public/browser/web_ui.h"
21 namespace proximity_auth {
23 namespace {
25 // Keys in the JSON representation of a log message.
26 const char kLogMessageTextKey[] = "text";
27 const char kLogMessageTimeKey[] = "time";
28 const char kLogMessageFileKey[] = "file";
29 const char kLogMessageLineKey[] = "line";
30 const char kLogMessageSeverityKey[] = "severity";
32 // Keys in the JSON representation of a SyncState object for enrollment or
33 // device sync.
34 const char kSyncStateLastSuccessTime[] = "lastSuccessTime";
35 const char kSyncStateNextRefreshTime[] = "nextRefreshTime";
36 const char kSyncStateRecoveringFromFailure[] = "recoveringFromFailure";
37 const char kSyncStateOperationInProgress[] = "operationInProgress";
39 // Converts |log_message| to a raw dictionary value used as a JSON argument to
40 // JavaScript functions.
41 scoped_ptr<base::DictionaryValue> LogMessageToDictionary(
42 const LogBuffer::LogMessage& log_message) {
43 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue());
44 dictionary->SetString(kLogMessageTextKey, log_message.text);
45 dictionary->SetString(
46 kLogMessageTimeKey,
47 base::TimeFormatTimeOfDayWithMilliseconds(log_message.time));
48 dictionary->SetString(kLogMessageFileKey, log_message.file);
49 dictionary->SetInteger(kLogMessageLineKey, log_message.line);
50 dictionary->SetInteger(kLogMessageSeverityKey,
51 static_cast<int>(log_message.severity));
52 return dictionary.Pass();
55 // Keys in the JSON representation of an ExternalDeviceInfo proto.
56 const char kExternalDevicePublicKey[] = "publicKey";
57 const char kExternalDeviceFriendlyName[] = "friendlyDeviceName";
58 const char kExternalDeviceUnlockKey[] = "unlockKey";
59 const char kExternalDeviceConnectionStatus[] = "connectionStatus";
61 // The possible values of the |kExternalDeviceConnectionStatus| field.
62 const char kExternalDeviceDisconnected[] = "disconnected";
64 // Converts an ExternalDeviceInfo proto to a JSON dictionary used in JavaScript.
65 scoped_ptr<base::DictionaryValue> ExternalDeviceInfoToDictionary(
66 const cryptauth::ExternalDeviceInfo& device_info) {
67 std::string base64_public_key;
68 Base64UrlEncode(device_info.public_key(), &base64_public_key);
70 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue());
71 dictionary->SetString(kExternalDevicePublicKey, base64_public_key);
72 dictionary->SetString(kExternalDeviceFriendlyName,
73 device_info.friendly_device_name());
74 dictionary->SetBoolean(kExternalDeviceUnlockKey, device_info.unlock_key());
75 dictionary->SetString(kExternalDeviceConnectionStatus,
76 kExternalDeviceDisconnected);
77 return dictionary.Pass();
80 // Keys in the JSON representation of an IneligibleDevice proto.
81 const char kIneligibleDeviceReasons[] = "ineligibilityReasons";
83 // Converts an IneligibleDevice proto to a JSON dictionary used in JavaScript.
84 scoped_ptr<base::DictionaryValue> IneligibleDeviceToDictionary(
85 const cryptauth::IneligibleDevice& ineligible_device) {
86 scoped_ptr<base::ListValue> ineligibility_reasons(new base::ListValue());
87 for (const std::string& reason : ineligible_device.reasons()) {
88 ineligibility_reasons->AppendString(reason);
91 scoped_ptr<base::DictionaryValue> device_dictionary =
92 ExternalDeviceInfoToDictionary(ineligible_device.device());
93 device_dictionary->Set(kIneligibleDeviceReasons,
94 ineligibility_reasons.Pass());
95 return device_dictionary;
98 // Creates a SyncState JSON object that can be passed to the WebUI.
99 scoped_ptr<base::DictionaryValue> CreateSyncStateDictionary(
100 double last_success_time,
101 double next_refresh_time,
102 bool is_recovering_from_failure,
103 bool is_enrollment_in_progress) {
104 scoped_ptr<base::DictionaryValue> sync_state(new base::DictionaryValue());
105 sync_state->SetDouble(kSyncStateLastSuccessTime, last_success_time);
106 sync_state->SetDouble(kSyncStateNextRefreshTime, next_refresh_time);
107 sync_state->SetBoolean(kSyncStateRecoveringFromFailure,
108 is_recovering_from_failure);
109 sync_state->SetBoolean(kSyncStateOperationInProgress,
110 is_enrollment_in_progress);
111 return sync_state;
114 } // namespace
116 ProximityAuthWebUIHandler::ProximityAuthWebUIHandler(
117 ProximityAuthUIDelegate* delegate)
118 : delegate_(delegate), weak_ptr_factory_(this) {
119 cryptauth_client_factory_ = delegate_->CreateCryptAuthClientFactory();
122 ProximityAuthWebUIHandler::~ProximityAuthWebUIHandler() {
123 LogBuffer::GetInstance()->RemoveObserver(this);
124 if (enrollment_manager_)
125 enrollment_manager_->RemoveObserver(this);
128 void ProximityAuthWebUIHandler::RegisterMessages() {
129 web_ui()->RegisterMessageCallback(
130 "clearLogBuffer", base::Bind(&ProximityAuthWebUIHandler::ClearLogBuffer,
131 base::Unretained(this)));
133 web_ui()->RegisterMessageCallback(
134 "getLogMessages", base::Bind(&ProximityAuthWebUIHandler::GetLogMessages,
135 base::Unretained(this)));
137 web_ui()->RegisterMessageCallback(
138 "findEligibleUnlockDevices",
139 base::Bind(&ProximityAuthWebUIHandler::FindEligibleUnlockDevices,
140 base::Unretained(this)));
142 web_ui()->RegisterMessageCallback(
143 "getSyncStates", base::Bind(&ProximityAuthWebUIHandler::GetSyncStates,
144 base::Unretained(this)));
146 web_ui()->RegisterMessageCallback(
147 "forceEnrollment", base::Bind(&ProximityAuthWebUIHandler::ForceEnrollment,
148 base::Unretained(this)));
150 web_ui()->RegisterMessageCallback(
151 "forceDeviceSync", base::Bind(&ProximityAuthWebUIHandler::ForceDeviceSync,
152 base::Unretained(this)));
154 LogBuffer::GetInstance()->AddObserver(this);
156 InitGCMManager();
157 InitEnrollmentManager();
158 InitDeviceManager();
161 void ProximityAuthWebUIHandler::OnLogMessageAdded(
162 const LogBuffer::LogMessage& log_message) {
163 scoped_ptr<base::DictionaryValue> dictionary =
164 LogMessageToDictionary(log_message);
165 web_ui()->CallJavascriptFunction("LogBufferInterface.onLogMessageAdded",
166 *dictionary);
169 void ProximityAuthWebUIHandler::OnLogBufferCleared() {
170 web_ui()->CallJavascriptFunction("LogBufferInterface.onLogBufferCleared");
173 void ProximityAuthWebUIHandler::OnEnrollmentStarted() {
174 web_ui()->CallJavascriptFunction(
175 "SyncStateInterface.onEnrollmentStateChanged",
176 *GetEnrollmentStateDictionary());
179 void ProximityAuthWebUIHandler::OnEnrollmentFinished(bool success) {
180 scoped_ptr<base::DictionaryValue> enrollment_state =
181 GetEnrollmentStateDictionary();
182 PA_LOG(INFO) << "Enrollment attempt completed with success=" << success
183 << ":\n" << *enrollment_state;
184 web_ui()->CallJavascriptFunction(
185 "SyncStateInterface.onEnrollmentStateChanged", *enrollment_state);
188 void ProximityAuthWebUIHandler::OnSyncStarted() {
189 web_ui()->CallJavascriptFunction(
190 "SyncStateInterface.onDeviceSyncStateChanged",
191 *GetDeviceSyncStateDictionary());
194 void ProximityAuthWebUIHandler::OnSyncFinished(
195 CryptAuthDeviceManager::SyncResult sync_result,
196 CryptAuthDeviceManager::DeviceChangeResult device_change_result) {
197 scoped_ptr<base::DictionaryValue> device_sync_state =
198 GetDeviceSyncStateDictionary();
199 PA_LOG(INFO) << "Device sync completed with result="
200 << static_cast<int>(sync_result) << ":\n" << *device_sync_state;
201 web_ui()->CallJavascriptFunction(
202 "SyncStateInterface.onDeviceSyncStateChanged", *device_sync_state);
205 void ProximityAuthWebUIHandler::GetLogMessages(const base::ListValue* args) {
206 base::ListValue json_logs;
207 for (const auto& log : *LogBuffer::GetInstance()->logs()) {
208 json_logs.Append(LogMessageToDictionary(log).release());
210 web_ui()->CallJavascriptFunction("LogBufferInterface.onGotLogMessages",
211 json_logs);
214 void ProximityAuthWebUIHandler::ClearLogBuffer(const base::ListValue* args) {
215 // The OnLogBufferCleared() observer function will be called after the buffer
216 // is cleared.
217 LogBuffer::GetInstance()->Clear();
220 void ProximityAuthWebUIHandler::FindEligibleUnlockDevices(
221 const base::ListValue* args) {
222 cryptauth_client_ = cryptauth_client_factory_->CreateInstance();
224 cryptauth::FindEligibleUnlockDevicesRequest request;
225 *(request.mutable_device_classifier()) = delegate_->GetDeviceClassifier();
226 cryptauth_client_->FindEligibleUnlockDevices(
227 request,
228 base::Bind(&ProximityAuthWebUIHandler::OnFoundEligibleUnlockDevices,
229 weak_ptr_factory_.GetWeakPtr()),
230 base::Bind(&ProximityAuthWebUIHandler::OnCryptAuthClientError,
231 weak_ptr_factory_.GetWeakPtr()));
234 void ProximityAuthWebUIHandler::ForceEnrollment(const base::ListValue* args) {
235 if (enrollment_manager_) {
236 enrollment_manager_->ForceEnrollmentNow(
237 cryptauth::INVOCATION_REASON_MANUAL);
241 void ProximityAuthWebUIHandler::ForceDeviceSync(const base::ListValue* args) {
242 if (device_manager_)
243 device_manager_->ForceSyncNow(cryptauth::INVOCATION_REASON_MANUAL);
246 void ProximityAuthWebUIHandler::InitGCMManager() {
247 gcm_manager_.reset(new CryptAuthGCMManagerImpl(delegate_->GetGCMDriver(),
248 delegate_->GetPrefService()));
251 void ProximityAuthWebUIHandler::InitEnrollmentManager() {
252 #if defined(OS_CHROMEOS)
253 // TODO(tengs): We initialize a CryptAuthEnrollmentManager here for
254 // development and testing purposes until it is ready to be moved into Chrome.
255 // The public/private key pair has been generated and serialized in a previous
256 // session.
257 std::string user_public_key;
258 Base64UrlDecode(
259 "CAESRgohAD1lP_wgQ8XqVVwz4aK_89SqdvAQG5L_NZH5zXxwg5UbEiEAZFMlgCZ9h8OlyE4"
260 "QYKY5oiOBu0FmLSKeTAXEq2jnVJI=",
261 &user_public_key);
263 std::string user_private_key;
264 Base64UrlDecode(
265 "MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP____8AAAABAAAAAAA"
266 "AAAAAAAAA________________MFsEIP____8AAAABAAAAAAAAAAAAAAAA______________"
267 "_8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw-J9JgSwMVAMSdNgiG5wSTamZ44ROdJ"
268 "reBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li_hp_m47n60p8"
269 "D54WK84zV2sxXs7LtkBoN79R9QIhAP____8AAAAA__________-85vqtpxeehPO5ysL8YyV"
270 "RAgEBBG0wawIBAQQgKZ4Dsm5xe4p5U2XPGxjrG376ZWWIa9E6r0y1BdjIntyhRANCAAQ9ZT"
271 "_8IEPF6lVcM-Giv_PUqnbwEBuS_zWR-c18cIOVG2RTJYAmfYfDpchOEGCmOaIjgbtBZi0in"
272 "kwFxKto51SS",
273 &user_private_key);
275 // This serialized DeviceInfo proto was previously captured from a real
276 // CryptAuth enrollment, and is replayed here for testing purposes.
277 std::string serialized_device_info;
278 Base64UrlDecode(
279 "IkoIARJGCiEAX_ZjLSq73EVcrarX-7l7No7nSP86GEC322ocSZKqUKwSIQDbEDu9KN7AgLM"
280 "v_lzZZNui9zSOgXCeDpLhS2tgrYVXijoEbGlua0IFZW4tVVNKSggBEkYKIQBf9mMtKrvcRV"
281 "ytqtf7uXs2judI_zoYQLfbahxJkqpQrBIhANsQO70o3sCAsy_-XNlk26L3NI6BcJ4OkuFLa"
282 "2CthVeKam9Nb3ppbGxhLzUuMCAoWDExOyBDck9TIHg4Nl82NCA3MTM0LjAuMCkgQXBwbGVX"
283 "ZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzQ1LjAuMjQyMi4wIFN"
284 "hZmFyaS81MzcuMzZwLYoBAzEuMJABAZoBIG1rYWVtaWdob2xlYmNnY2hsa2JhbmttaWhrbm"
285 "9qZWFrsAHDPuoBHEJLZEluZWxFZk05VG1adGV3eTRGb19RV1Vicz2AAgKyBqIBQVBBOTFiS"
286 "FZDdlJJNGJFSXppMmFXOTBlZ044eHFBYkhWYnJwSVFuMTk3bWltd3RWWTZYN0JEcEI4Szg3"
287 "RjRubkJnejdLX1BQV2xkcUtDRVhiZkFiMGwyN1VaQXgtVjBWbEE4WlFwdkhETmpHVlh4RlV"
288 "WRDFNY1AzNTgtYTZ3eHRpVG5LQnpMTEVIT1F6Ujdpb0lUMzRtWWY1VmNhbmhPZDh3ugYgs9"
289 "7-c7qNUzzLeEqVCDXb_EaJ8wC3iie_Lpid44iuAh3CPo0CCugBCiMIARACGgi5wHHa82avM"
290 "ioQ7y8xhiUBs7Um73ZC1vQlzzIBABLAAeCqGnWF7RwtnmdfIQJoEqXoXrH1qLw4yqUAA1TW"
291 "M1qxTepJOdDHrh54eiejobW0SKpHqTlZIyiK3ObHAPdfzFum1l640RFdFGZTTTksZFqfD9O"
292 "dftoi0pMrApob4gXj8Pv2g22ArX55BiH56TkTIcDcEE3KKnA_2G0INT1y_clZvZfDw1n0WP"
293 "0Xdg1PLLCOb46WfDWUhHvUk3GzUce8xyxsjOkiZUNh8yvhFXaP2wJgVKVWInf0inuofo9Za"
294 "7p44hIgHgKJIr_4fuVs9Ojf0KcMzxoJTbFUGg58jglUAKFfJBLKPpMBeWEyOS5pQUdTNFZ1"
295 "bF9JVWY4YTJDSmJNbXFqaWpYUFYzaVV5dmJXSVRrR3d1bFRaVUs3RGVZczJtT0h5ZkQ1NWR"
296 "HRXEtdnJTdVc4VEZ2Z1haa2xhVEZTN0dqM2xCVUktSHd5Z0h6bHZHX2NGLWtzQmw0dXdveG"
297 "VPWE1hRlJ3WGJHVUU1Tm9sLS1mdkRIcGVZVnJR",
298 &serialized_device_info);
299 cryptauth::GcmDeviceInfo device_info;
300 device_info.ParseFromString(serialized_device_info);
302 enrollment_manager_.reset(new CryptAuthEnrollmentManager(
303 make_scoped_ptr(new base::DefaultClock()),
304 make_scoped_ptr(new CryptAuthEnrollerFactoryImpl(delegate_)),
305 user_public_key, user_private_key, device_info, gcm_manager_.get(),
306 delegate_->GetPrefService()));
307 enrollment_manager_->AddObserver(this);
308 enrollment_manager_->Start();
309 #endif
312 void ProximityAuthWebUIHandler::InitDeviceManager() {
313 // TODO(tengs): We initialize a CryptAuthDeviceManager here for
314 // development and testing purposes until it is ready to be moved into Chrome.
315 device_manager_.reset(new CryptAuthDeviceManager(
316 make_scoped_ptr(new base::DefaultClock()),
317 delegate_->CreateCryptAuthClientFactory(), gcm_manager_.get(),
318 delegate_->GetPrefService()));
319 device_manager_->AddObserver(this);
320 device_manager_->Start();
323 void ProximityAuthWebUIHandler::OnCryptAuthClientError(
324 const std::string& error_message) {
325 PA_LOG(WARNING) << "CryptAuth request failed: " << error_message;
326 base::StringValue error_string(error_message);
327 web_ui()->CallJavascriptFunction("CryptAuthInterface.onError", error_string);
330 void ProximityAuthWebUIHandler::OnFoundEligibleUnlockDevices(
331 const cryptauth::FindEligibleUnlockDevicesResponse& response) {
332 base::ListValue eligible_devices;
333 for (const auto& external_device : response.eligible_devices()) {
334 eligible_devices.Append(ExternalDeviceInfoToDictionary(external_device));
337 base::ListValue ineligible_devices;
338 for (const auto& ineligible_device : response.ineligible_devices()) {
339 ineligible_devices.Append(IneligibleDeviceToDictionary(ineligible_device));
342 PA_LOG(INFO) << "Found " << eligible_devices.GetSize()
343 << " eligible devices and " << ineligible_devices.GetSize()
344 << " ineligible devices.";
345 web_ui()->CallJavascriptFunction("CryptAuthInterface.onGotEligibleDevices",
346 eligible_devices, ineligible_devices);
349 void ProximityAuthWebUIHandler::GetSyncStates(const base::ListValue* args) {
350 scoped_ptr<base::DictionaryValue> enrollment_state =
351 GetEnrollmentStateDictionary();
352 scoped_ptr<base::DictionaryValue> device_sync_state =
353 GetDeviceSyncStateDictionary();
354 PA_LOG(INFO) << "Enrollment State: \n" << *enrollment_state
355 << "Device Sync State: \n" << *device_sync_state;
356 web_ui()->CallJavascriptFunction("SyncStateInterface.onGotSyncStates",
357 *enrollment_state, *device_sync_state);
360 scoped_ptr<base::DictionaryValue>
361 ProximityAuthWebUIHandler::GetEnrollmentStateDictionary() {
362 if (!enrollment_manager_)
363 return make_scoped_ptr(new base::DictionaryValue());
365 return CreateSyncStateDictionary(
366 enrollment_manager_->GetLastEnrollmentTime().ToJsTime(),
367 enrollment_manager_->GetTimeToNextAttempt().InMillisecondsF(),
368 enrollment_manager_->IsRecoveringFromFailure(),
369 enrollment_manager_->IsEnrollmentInProgress());
372 scoped_ptr<base::DictionaryValue>
373 ProximityAuthWebUIHandler::GetDeviceSyncStateDictionary() {
374 if (!device_manager_)
375 return make_scoped_ptr(new base::DictionaryValue());
377 return CreateSyncStateDictionary(
378 device_manager_->GetLastSyncTime().ToJsTime(),
379 device_manager_->GetTimeToNextAttempt().InMillisecondsF(),
380 device_manager_->IsRecoveringFromFailure(),
381 device_manager_->IsSyncInProgress());
384 } // namespace proximity_auth