Roll src/third_party/WebKit d10c917:a1123a1 (svn 198729:198730)
[chromium-blink-merge.git] / components / proximity_auth / webui / proximity_auth_webui_handler.cc
blobf660c8f70ba9883e48df88daf007bc9f12ad0330
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/proto/cryptauth_api.pb.h"
15 #include "components/proximity_auth/logging/logging.h"
16 #include "components/proximity_auth/webui/cryptauth_enroller_factory_impl.h"
17 #include "components/proximity_auth/webui/proximity_auth_ui_delegate.h"
18 #include "content/public/browser/web_ui.h"
20 namespace proximity_auth {
22 namespace {
24 // Keys in the JSON representation of a log message.
25 const char kLogMessageTextKey[] = "text";
26 const char kLogMessageTimeKey[] = "time";
27 const char kLogMessageFileKey[] = "file";
28 const char kLogMessageLineKey[] = "line";
29 const char kLogMessageSeverityKey[] = "severity";
31 // Keys in the JSON representation of a SyncState object for enrollment or
32 // device sync.
33 const char kSyncStateLastSuccessTime[] = "lastSuccessTime";
34 const char kSyncStateNextRefreshTime[] = "nextRefreshTime";
35 const char kSyncStateRecoveringFromFailure[] = "recoveringFromFailure";
36 const char kSyncStateOperationInProgress[] = "operationInProgress";
38 // Converts |log_message| to a raw dictionary value used as a JSON argument to
39 // JavaScript functions.
40 scoped_ptr<base::DictionaryValue> LogMessageToDictionary(
41 const LogBuffer::LogMessage& log_message) {
42 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue());
43 dictionary->SetString(kLogMessageTextKey, log_message.text);
44 dictionary->SetString(
45 kLogMessageTimeKey,
46 base::TimeFormatTimeOfDayWithMilliseconds(log_message.time));
47 dictionary->SetString(kLogMessageFileKey, log_message.file);
48 dictionary->SetInteger(kLogMessageLineKey, log_message.line);
49 dictionary->SetInteger(kLogMessageSeverityKey,
50 static_cast<int>(log_message.severity));
51 return dictionary.Pass();
54 // Keys in the JSON representation of an ExternalDeviceInfo proto.
55 const char kExternalDevicePublicKey[] = "publicKey";
56 const char kExternalDeviceFriendlyName[] = "friendlyDeviceName";
57 const char kExternalDeviceUnlockKey[] = "unlockKey";
58 const char kExternalDeviceConnectionStatus[] = "connectionStatus";
60 // The possible values of the |kExternalDeviceConnectionStatus| field.
61 const char kExternalDeviceDisconnected[] = "disconnected";
63 // Converts an ExternalDeviceInfo proto to a JSON dictionary used in JavaScript.
64 scoped_ptr<base::DictionaryValue> ExternalDeviceInfoToDictionary(
65 const cryptauth::ExternalDeviceInfo& device_info) {
66 std::string base64_public_key;
67 Base64UrlEncode(device_info.public_key(), &base64_public_key);
69 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue());
70 dictionary->SetString(kExternalDevicePublicKey, base64_public_key);
71 dictionary->SetString(kExternalDeviceFriendlyName,
72 device_info.friendly_device_name());
73 dictionary->SetBoolean(kExternalDeviceUnlockKey, device_info.unlock_key());
74 dictionary->SetString(kExternalDeviceConnectionStatus,
75 kExternalDeviceDisconnected);
76 return dictionary.Pass();
79 // Keys in the JSON representation of an IneligibleDevice proto.
80 const char kIneligibleDeviceReasons[] = "ineligibilityReasons";
82 // Converts an IneligibleDevice proto to a JSON dictionary used in JavaScript.
83 scoped_ptr<base::DictionaryValue> IneligibleDeviceToDictionary(
84 const cryptauth::IneligibleDevice& ineligible_device) {
85 scoped_ptr<base::ListValue> ineligibility_reasons(new base::ListValue());
86 for (const std::string& reason : ineligible_device.reasons()) {
87 ineligibility_reasons->AppendString(reason);
90 scoped_ptr<base::DictionaryValue> device_dictionary =
91 ExternalDeviceInfoToDictionary(ineligible_device.device());
92 device_dictionary->Set(kIneligibleDeviceReasons,
93 ineligibility_reasons.Pass());
94 return device_dictionary;
97 // Creates a SyncState JSON object that can be passed to the WebUI.
98 scoped_ptr<base::DictionaryValue> CreateSyncStateDictionary(
99 double last_success_time,
100 double next_refresh_time,
101 bool is_recovering_from_failure,
102 bool is_enrollment_in_progress) {
103 scoped_ptr<base::DictionaryValue> sync_state(new base::DictionaryValue());
104 sync_state->SetDouble(kSyncStateLastSuccessTime, last_success_time);
105 sync_state->SetDouble(kSyncStateNextRefreshTime, next_refresh_time);
106 sync_state->SetBoolean(kSyncStateRecoveringFromFailure,
107 is_recovering_from_failure);
108 sync_state->SetBoolean(kSyncStateOperationInProgress,
109 is_enrollment_in_progress);
110 return sync_state;
113 } // namespace
115 ProximityAuthWebUIHandler::ProximityAuthWebUIHandler(
116 ProximityAuthUIDelegate* delegate)
117 : delegate_(delegate), weak_ptr_factory_(this) {
118 cryptauth_client_factory_ = delegate_->CreateCryptAuthClientFactory();
121 ProximityAuthWebUIHandler::~ProximityAuthWebUIHandler() {
122 LogBuffer::GetInstance()->RemoveObserver(this);
123 if (enrollment_manager_)
124 enrollment_manager_->RemoveObserver(this);
127 void ProximityAuthWebUIHandler::RegisterMessages() {
128 web_ui()->RegisterMessageCallback(
129 "clearLogBuffer", base::Bind(&ProximityAuthWebUIHandler::ClearLogBuffer,
130 base::Unretained(this)));
132 web_ui()->RegisterMessageCallback(
133 "getLogMessages", base::Bind(&ProximityAuthWebUIHandler::GetLogMessages,
134 base::Unretained(this)));
136 web_ui()->RegisterMessageCallback(
137 "findEligibleUnlockDevices",
138 base::Bind(&ProximityAuthWebUIHandler::FindEligibleUnlockDevices,
139 base::Unretained(this)));
141 web_ui()->RegisterMessageCallback(
142 "getSyncStates", base::Bind(&ProximityAuthWebUIHandler::GetSyncStates,
143 base::Unretained(this)));
145 web_ui()->RegisterMessageCallback(
146 "forceEnrollment", base::Bind(&ProximityAuthWebUIHandler::ForceEnrollment,
147 base::Unretained(this)));
149 web_ui()->RegisterMessageCallback(
150 "forceDeviceSync", base::Bind(&ProximityAuthWebUIHandler::ForceDeviceSync,
151 base::Unretained(this)));
153 LogBuffer::GetInstance()->AddObserver(this);
154 InitEnrollmentManager();
155 InitDeviceManager();
158 void ProximityAuthWebUIHandler::OnLogMessageAdded(
159 const LogBuffer::LogMessage& log_message) {
160 scoped_ptr<base::DictionaryValue> dictionary =
161 LogMessageToDictionary(log_message);
162 web_ui()->CallJavascriptFunction("LogBufferInterface.onLogMessageAdded",
163 *dictionary);
166 void ProximityAuthWebUIHandler::OnLogBufferCleared() {
167 web_ui()->CallJavascriptFunction("LogBufferInterface.onLogBufferCleared");
170 void ProximityAuthWebUIHandler::OnEnrollmentStarted() {
171 web_ui()->CallJavascriptFunction(
172 "SyncStateInterface.onEnrollmentStateChanged",
173 *GetEnrollmentStateDictionary());
176 void ProximityAuthWebUIHandler::OnEnrollmentFinished(bool success) {
177 scoped_ptr<base::DictionaryValue> enrollment_state =
178 GetEnrollmentStateDictionary();
179 PA_LOG(INFO) << "Enrollment attempt completed with success=" << success
180 << ":\n" << *enrollment_state;
181 web_ui()->CallJavascriptFunction(
182 "SyncStateInterface.onEnrollmentStateChanged", *enrollment_state);
185 void ProximityAuthWebUIHandler::OnSyncStarted() {
186 web_ui()->CallJavascriptFunction(
187 "SyncStateInterface.onDeviceSyncStateChanged",
188 *GetDeviceSyncStateDictionary());
191 void ProximityAuthWebUIHandler::OnSyncFinished(
192 CryptAuthDeviceManager::SyncResult sync_result,
193 CryptAuthDeviceManager::DeviceChangeResult device_change_result) {
194 scoped_ptr<base::DictionaryValue> device_sync_state =
195 GetDeviceSyncStateDictionary();
196 PA_LOG(INFO) << "Device sync completed with result="
197 << static_cast<int>(sync_result) << ":\n" << *device_sync_state;
198 web_ui()->CallJavascriptFunction(
199 "SyncStateInterface.onDeviceSyncStateChanged", *device_sync_state);
202 void ProximityAuthWebUIHandler::GetLogMessages(const base::ListValue* args) {
203 base::ListValue json_logs;
204 for (const auto& log : *LogBuffer::GetInstance()->logs()) {
205 json_logs.Append(LogMessageToDictionary(log).release());
207 web_ui()->CallJavascriptFunction("LogBufferInterface.onGotLogMessages",
208 json_logs);
211 void ProximityAuthWebUIHandler::ClearLogBuffer(const base::ListValue* args) {
212 // The OnLogBufferCleared() observer function will be called after the buffer
213 // is cleared.
214 LogBuffer::GetInstance()->Clear();
217 void ProximityAuthWebUIHandler::FindEligibleUnlockDevices(
218 const base::ListValue* args) {
219 cryptauth_client_ = cryptauth_client_factory_->CreateInstance();
221 cryptauth::FindEligibleUnlockDevicesRequest request;
222 *(request.mutable_device_classifier()) = delegate_->GetDeviceClassifier();
223 cryptauth_client_->FindEligibleUnlockDevices(
224 request,
225 base::Bind(&ProximityAuthWebUIHandler::OnFoundEligibleUnlockDevices,
226 weak_ptr_factory_.GetWeakPtr()),
227 base::Bind(&ProximityAuthWebUIHandler::OnCryptAuthClientError,
228 weak_ptr_factory_.GetWeakPtr()));
231 void ProximityAuthWebUIHandler::ForceEnrollment(const base::ListValue* args) {
232 if (enrollment_manager_) {
233 enrollment_manager_->ForceEnrollmentNow(
234 cryptauth::INVOCATION_REASON_MANUAL);
238 void ProximityAuthWebUIHandler::ForceDeviceSync(const base::ListValue* args) {
239 if (device_manager_)
240 device_manager_->ForceSyncNow(cryptauth::INVOCATION_REASON_MANUAL);
243 void ProximityAuthWebUIHandler::InitEnrollmentManager() {
244 #if defined(OS_CHROMEOS)
245 // TODO(tengs): We initialize a CryptAuthEnrollmentManager here for
246 // development and testing purposes until it is ready to be moved into Chrome.
247 // The public/private key pair has been generated and serialized in a previous
248 // session.
249 std::string user_public_key;
250 Base64UrlDecode(
251 "CAESRgohAD1lP_wgQ8XqVVwz4aK_89SqdvAQG5L_NZH5zXxwg5UbEiEAZFMlgCZ9h8OlyE4"
252 "QYKY5oiOBu0FmLSKeTAXEq2jnVJI=",
253 &user_public_key);
255 std::string user_private_key;
256 Base64UrlDecode(
257 "MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP____8AAAABAAAAAAA"
258 "AAAAAAAAA________________MFsEIP____8AAAABAAAAAAAAAAAAAAAA______________"
259 "_8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw-J9JgSwMVAMSdNgiG5wSTamZ44ROdJ"
260 "reBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li_hp_m47n60p8"
261 "D54WK84zV2sxXs7LtkBoN79R9QIhAP____8AAAAA__________-85vqtpxeehPO5ysL8YyV"
262 "RAgEBBG0wawIBAQQgKZ4Dsm5xe4p5U2XPGxjrG376ZWWIa9E6r0y1BdjIntyhRANCAAQ9ZT"
263 "_8IEPF6lVcM-Giv_PUqnbwEBuS_zWR-c18cIOVG2RTJYAmfYfDpchOEGCmOaIjgbtBZi0in"
264 "kwFxKto51SS",
265 &user_private_key);
267 // This serialized DeviceInfo proto was previously captured from a real
268 // CryptAuth enrollment, and is replayed here for testing purposes.
269 std::string serialized_device_info;
270 Base64UrlDecode(
271 "IkoIARJGCiEAX_ZjLSq73EVcrarX-7l7No7nSP86GEC322ocSZKqUKwSIQDbEDu9KN7AgLM"
272 "v_lzZZNui9zSOgXCeDpLhS2tgrYVXijoEbGlua0IFZW4tVVNKSggBEkYKIQBf9mMtKrvcRV"
273 "ytqtf7uXs2judI_zoYQLfbahxJkqpQrBIhANsQO70o3sCAsy_-XNlk26L3NI6BcJ4OkuFLa"
274 "2CthVeKam9Nb3ppbGxhLzUuMCAoWDExOyBDck9TIHg4Nl82NCA3MTM0LjAuMCkgQXBwbGVX"
275 "ZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzQ1LjAuMjQyMi4wIFN"
276 "hZmFyaS81MzcuMzZwLYoBAzEuMJABAZoBIG1rYWVtaWdob2xlYmNnY2hsa2JhbmttaWhrbm"
277 "9qZWFrsAHDPuoBHEJLZEluZWxFZk05VG1adGV3eTRGb19RV1Vicz2AAgKyBqIBQVBBOTFiS"
278 "FZDdlJJNGJFSXppMmFXOTBlZ044eHFBYkhWYnJwSVFuMTk3bWltd3RWWTZYN0JEcEI4Szg3"
279 "RjRubkJnejdLX1BQV2xkcUtDRVhiZkFiMGwyN1VaQXgtVjBWbEE4WlFwdkhETmpHVlh4RlV"
280 "WRDFNY1AzNTgtYTZ3eHRpVG5LQnpMTEVIT1F6Ujdpb0lUMzRtWWY1VmNhbmhPZDh3ugYgs9"
281 "7-c7qNUzzLeEqVCDXb_EaJ8wC3iie_Lpid44iuAh3CPo0CCugBCiMIARACGgi5wHHa82avM"
282 "ioQ7y8xhiUBs7Um73ZC1vQlzzIBABLAAeCqGnWF7RwtnmdfIQJoEqXoXrH1qLw4yqUAA1TW"
283 "M1qxTepJOdDHrh54eiejobW0SKpHqTlZIyiK3ObHAPdfzFum1l640RFdFGZTTTksZFqfD9O"
284 "dftoi0pMrApob4gXj8Pv2g22ArX55BiH56TkTIcDcEE3KKnA_2G0INT1y_clZvZfDw1n0WP"
285 "0Xdg1PLLCOb46WfDWUhHvUk3GzUce8xyxsjOkiZUNh8yvhFXaP2wJgVKVWInf0inuofo9Za"
286 "7p44hIgHgKJIr_4fuVs9Ojf0KcMzxoJTbFUGg58jglUAKFfJBLKPpMBeWEyOS5pQUdTNFZ1"
287 "bF9JVWY4YTJDSmJNbXFqaWpYUFYzaVV5dmJXSVRrR3d1bFRaVUs3RGVZczJtT0h5ZkQ1NWR"
288 "HRXEtdnJTdVc4VEZ2Z1haa2xhVEZTN0dqM2xCVUktSHd5Z0h6bHZHX2NGLWtzQmw0dXdveG"
289 "VPWE1hRlJ3WGJHVUU1Tm9sLS1mdkRIcGVZVnJR",
290 &serialized_device_info);
291 cryptauth::GcmDeviceInfo device_info;
292 device_info.ParseFromString(serialized_device_info);
294 enrollment_manager_.reset(new CryptAuthEnrollmentManager(
295 make_scoped_ptr(new base::DefaultClock()),
296 make_scoped_ptr(new CryptAuthEnrollerFactoryImpl(delegate_)),
297 user_public_key, user_private_key, device_info,
298 delegate_->GetPrefService()));
299 enrollment_manager_->AddObserver(this);
300 enrollment_manager_->Start();
301 #endif
304 void ProximityAuthWebUIHandler::InitDeviceManager() {
305 // TODO(tengs): We initialize a CryptAuthDeviceManager here for
306 // development and testing purposes until it is ready to be moved into Chrome.
307 device_manager_.reset(new CryptAuthDeviceManager(
308 make_scoped_ptr(new base::DefaultClock()),
309 delegate_->CreateCryptAuthClientFactory(), delegate_->GetPrefService()));
310 device_manager_->AddObserver(this);
311 device_manager_->Start();
314 void ProximityAuthWebUIHandler::OnCryptAuthClientError(
315 const std::string& error_message) {
316 PA_LOG(WARNING) << "CryptAuth request failed: " << error_message;
317 base::StringValue error_string(error_message);
318 web_ui()->CallJavascriptFunction("CryptAuthInterface.onError", error_string);
321 void ProximityAuthWebUIHandler::OnFoundEligibleUnlockDevices(
322 const cryptauth::FindEligibleUnlockDevicesResponse& response) {
323 base::ListValue eligible_devices;
324 for (const auto& external_device : response.eligible_devices()) {
325 eligible_devices.Append(ExternalDeviceInfoToDictionary(external_device));
328 base::ListValue ineligible_devices;
329 for (const auto& ineligible_device : response.ineligible_devices()) {
330 ineligible_devices.Append(IneligibleDeviceToDictionary(ineligible_device));
333 PA_LOG(INFO) << "Found " << eligible_devices.GetSize()
334 << " eligible devices and " << ineligible_devices.GetSize()
335 << " ineligible devices.";
336 web_ui()->CallJavascriptFunction("CryptAuthInterface.onGotEligibleDevices",
337 eligible_devices, ineligible_devices);
340 void ProximityAuthWebUIHandler::GetSyncStates(const base::ListValue* args) {
341 scoped_ptr<base::DictionaryValue> enrollment_state =
342 GetEnrollmentStateDictionary();
343 scoped_ptr<base::DictionaryValue> device_sync_state =
344 GetDeviceSyncStateDictionary();
345 PA_LOG(INFO) << "Enrollment State: \n" << *enrollment_state
346 << "Device Sync State: \n" << *device_sync_state;
347 web_ui()->CallJavascriptFunction("SyncStateInterface.onGotSyncStates",
348 *enrollment_state, *device_sync_state);
351 scoped_ptr<base::DictionaryValue>
352 ProximityAuthWebUIHandler::GetEnrollmentStateDictionary() {
353 if (!enrollment_manager_)
354 return make_scoped_ptr(new base::DictionaryValue());
356 return CreateSyncStateDictionary(
357 enrollment_manager_->GetLastEnrollmentTime().ToJsTime(),
358 enrollment_manager_->GetTimeToNextAttempt().InMillisecondsF(),
359 enrollment_manager_->IsRecoveringFromFailure(),
360 enrollment_manager_->IsEnrollmentInProgress());
363 scoped_ptr<base::DictionaryValue>
364 ProximityAuthWebUIHandler::GetDeviceSyncStateDictionary() {
365 if (!device_manager_)
366 return make_scoped_ptr(new base::DictionaryValue());
368 return CreateSyncStateDictionary(
369 device_manager_->GetLastSyncTime().ToJsTime(),
370 device_manager_->GetTimeToNextAttempt().InMillisecondsF(),
371 device_manager_->IsRecoveringFromFailure(),
372 device_manager_->IsSyncInProgress());
375 } // namespace proximity_auth