From 7c37d21139d766a0cecf1336a2485f019c9cb219 Mon Sep 17 00:00:00 2001 From: "xiyuan@chromium.org" Date: Fri, 15 Aug 2014 21:42:33 +0000 Subject: [PATCH] Wire easy unlock settings UI - Add API to get/set/clear the pairing info into user prefs; - Add an onTurnFlowFinished event so that the app can clear its state; - Extend EasyUnlockService to store pairing info and provide turn-off flow support; - Update settings UI to trigger turn off flow and observe the turn-off flow status to show pending/error or dismiss when done; - Add EasyUnlockToggleFlow to wrap api calls to server; - Update OAuth2ApiFlow to support application/json content-type and handle 204 as success; BUG=397356,394640 Review URL: https://codereview.chromium.org/475483003 Cr-Commit-Position: refs/heads/master@{#290019} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@290019 0039d316-1c4b-4281-b951-d872f2087c98 --- .../easy_unlock_private_api.cc | 98 ++++++++ .../easy_unlock_private_api.h | 77 +++++++ .../resources/options/browser_options.js | 3 + .../options/easy_unlock_turn_off_overlay.js | 76 ++++++- chrome/browser/signin/easy_unlock_service.cc | 131 ++++++++++- chrome/browser/signin/easy_unlock_service.h | 43 ++++ .../signin/easy_unlock_service_observer.h | 17 ++ .../browser/signin/easy_unlock_toggle_flow.cc | 213 ++++++++++++++++++ .../browser/signin/easy_unlock_toggle_flow.h | 69 ++++++ .../webui/options/browser_options_handler.cc | 19 +- .../ui/webui/options/easy_unlock_handler.cc | 107 +++++++++ .../ui/webui/options/easy_unlock_handler.h | 43 ++++ chrome/browser/ui/webui/options/options_ui.cc | 2 + chrome/chrome_browser.gypi | 2 + chrome/chrome_browser_ui.gypi | 2 + .../extensions/api/easy_unlock_private.idl | 63 ++++++ .../extension_function_histogram_value.h | 5 + google_apis/gaia/oauth2_api_call_flow.cc | 9 +- google_apis/gaia/oauth2_api_call_flow.h | 1 + tools/metrics/histograms/histograms.xml | 5 + 20 files changed, 956 insertions(+), 29 deletions(-) create mode 100644 chrome/browser/signin/easy_unlock_service_observer.h create mode 100644 chrome/browser/signin/easy_unlock_toggle_flow.cc create mode 100644 chrome/browser/signin/easy_unlock_toggle_flow.h create mode 100644 chrome/browser/ui/webui/options/easy_unlock_handler.cc create mode 100644 chrome/browser/ui/webui/options/easy_unlock_handler.h diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc index 1b7f87e42255..2c242b1c0af7 100644 --- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc +++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc @@ -424,5 +424,103 @@ bool EasyUnlockPrivateUpdateScreenlockStateFunction::RunSync() { return false; } +EasyUnlockPrivateSetPermitAccessFunction:: + EasyUnlockPrivateSetPermitAccessFunction() { +} + +EasyUnlockPrivateSetPermitAccessFunction:: + ~EasyUnlockPrivateSetPermitAccessFunction() { +} + +bool EasyUnlockPrivateSetPermitAccessFunction::RunSync() { + scoped_ptr params( + easy_unlock_private::SetPermitAccess::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params.get()); + + Profile* profile = Profile::FromBrowserContext(browser_context()); + EasyUnlockService::Get(profile) + ->SetPermitAccess(*params->permit_access.ToValue()); + + return true; +} + +EasyUnlockPrivateGetPermitAccessFunction:: + EasyUnlockPrivateGetPermitAccessFunction() { +} + +EasyUnlockPrivateGetPermitAccessFunction:: + ~EasyUnlockPrivateGetPermitAccessFunction() { +} + +bool EasyUnlockPrivateGetPermitAccessFunction::RunSync() { + Profile* profile = Profile::FromBrowserContext(browser_context()); + const base::DictionaryValue* permit_value = + EasyUnlockService::Get(profile)->GetPermitAccess(); + if (permit_value) { + scoped_ptr permit = + easy_unlock_private::PermitRecord::FromValue(*permit_value); + results_ = easy_unlock_private::GetPermitAccess::Results::Create(*permit); + } + + return true; +} + +EasyUnlockPrivateClearPermitAccessFunction:: + EasyUnlockPrivateClearPermitAccessFunction() { +} + +EasyUnlockPrivateClearPermitAccessFunction:: + ~EasyUnlockPrivateClearPermitAccessFunction() { +} + +bool EasyUnlockPrivateClearPermitAccessFunction::RunSync() { + Profile* profile = Profile::FromBrowserContext(browser_context()); + EasyUnlockService::Get(profile)->ClearPermitAccess(); + return true; +} + +EasyUnlockPrivateSetRemoteDevicesFunction:: + EasyUnlockPrivateSetRemoteDevicesFunction() { +} + +EasyUnlockPrivateSetRemoteDevicesFunction:: + ~EasyUnlockPrivateSetRemoteDevicesFunction() { +} + +bool EasyUnlockPrivateSetRemoteDevicesFunction::RunSync() { + scoped_ptr params( + easy_unlock_private::SetRemoteDevices::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params.get()); + + Profile* profile = Profile::FromBrowserContext(browser_context()); + if (params->devices.empty()) { + EasyUnlockService::Get(profile)->ClearRemoteDevices(); + } else { + base::ListValue devices; + for (size_t i = 0; i < params->devices.size(); ++i) { + devices.Append(params->devices[i]->ToValue().release()); + } + EasyUnlockService::Get(profile)->SetRemoteDevices(devices); + } + + return true; +} + +EasyUnlockPrivateGetRemoteDevicesFunction:: + EasyUnlockPrivateGetRemoteDevicesFunction() { +} + +EasyUnlockPrivateGetRemoteDevicesFunction:: + ~EasyUnlockPrivateGetRemoteDevicesFunction() { +} + +bool EasyUnlockPrivateGetRemoteDevicesFunction::RunSync() { + Profile* profile = Profile::FromBrowserContext(browser_context()); + const base::ListValue* devices = + EasyUnlockService::Get(profile)->GetRemoteDevices(); + SetResult(devices ? devices->DeepCopy() : new base::ListValue()); + return true; +} + } // namespace api } // namespace extensions diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h index 380286134227..215b46973555 100644 --- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h +++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h @@ -8,6 +8,7 @@ #include #include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/browser/extension_function.h" @@ -180,6 +181,82 @@ class EasyUnlockPrivateUpdateScreenlockStateFunction DISALLOW_COPY_AND_ASSIGN(EasyUnlockPrivateUpdateScreenlockStateFunction); }; +class EasyUnlockPrivateSetPermitAccessFunction : public SyncExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("easyUnlockPrivate.setPermitAccess", + EASYUNLOCKPRIVATE_SETPERMITACCESS) + EasyUnlockPrivateSetPermitAccessFunction(); + + private: + virtual ~EasyUnlockPrivateSetPermitAccessFunction(); + + // SyncExtensionFunction: + virtual bool RunSync() OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(EasyUnlockPrivateSetPermitAccessFunction); +}; + +class EasyUnlockPrivateGetPermitAccessFunction : public SyncExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("easyUnlockPrivate.getPermitAccess", + EASYUNLOCKPRIVATE_GETPERMITACCESS) + EasyUnlockPrivateGetPermitAccessFunction(); + + private: + virtual ~EasyUnlockPrivateGetPermitAccessFunction(); + + // SyncExtensionFunction: + virtual bool RunSync() OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(EasyUnlockPrivateGetPermitAccessFunction); +}; + +class EasyUnlockPrivateClearPermitAccessFunction + : public SyncExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("easyUnlockPrivate.clearPermitAccess", + EASYUNLOCKPRIVATE_CLEARPERMITACCESS) + EasyUnlockPrivateClearPermitAccessFunction(); + + private: + virtual ~EasyUnlockPrivateClearPermitAccessFunction(); + + // SyncExtensionFunction: + virtual bool RunSync() OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(EasyUnlockPrivateClearPermitAccessFunction); +}; + +class EasyUnlockPrivateSetRemoteDevicesFunction : public SyncExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("easyUnlockPrivate.setRemoteDevices", + EASYUNLOCKPRIVATE_SETREMOTEDEVICES) + EasyUnlockPrivateSetRemoteDevicesFunction(); + + private: + virtual ~EasyUnlockPrivateSetRemoteDevicesFunction(); + + // SyncExtensionFunction: + virtual bool RunSync() OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(EasyUnlockPrivateSetRemoteDevicesFunction); +}; + +class EasyUnlockPrivateGetRemoteDevicesFunction : public SyncExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("easyUnlockPrivate.getRemoteDevices", + EASYUNLOCKPRIVATE_GETREMOTEDEVICES) + EasyUnlockPrivateGetRemoteDevicesFunction(); + + private: + virtual ~EasyUnlockPrivateGetRemoteDevicesFunction(); + + // SyncExtensionFunction: + virtual bool RunSync() OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(EasyUnlockPrivateGetRemoteDevicesFunction); +}; + } // namespace api } // namespace extensions diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js index 39d2df0cc7d2..d0354edecde8 100644 --- a/chrome/browser/resources/options/browser_options.js +++ b/chrome/browser/resources/options/browser_options.js @@ -1051,6 +1051,9 @@ cr.define('options', function() { updateEasyUnlock_: function(hasPairing) { $('easy-unlock-setup').hidden = hasPairing; $('easy-unlock-enable').hidden = !hasPairing; + if (!hasPairing && EasyUnlockTurnOffOverlay.getInstance().visible) { + EasyUnlockTurnOffOverlay.dismiss(); + } }, /** diff --git a/chrome/browser/resources/options/easy_unlock_turn_off_overlay.js b/chrome/browser/resources/options/easy_unlock_turn_off_overlay.js index dd19b26b67c6..8b2a589843b6 100644 --- a/chrome/browser/resources/options/easy_unlock_turn_off_overlay.js +++ b/chrome/browser/resources/options/easy_unlock_turn_off_overlay.js @@ -6,6 +6,16 @@ cr.define('options', function() { var Page = cr.ui.pageManager.Page; var PageManager = cr.ui.pageManager.PageManager; + // UI state of the turn off overlay. + // @enum {string} + var UIState = { + UNKNOWN: 'unknown', + OFFLINE: 'offline', + IDLE: 'idle', + PENDING: 'pending', + SERVER_ERROR: 'server-error', + }; + /** * EasyUnlockTurnOffOverlay class * Encapsulated handling of the Factory Reset confirmation overlay page. @@ -23,6 +33,37 @@ cr.define('options', function() { // Inherit EasyUnlockTurnOffOverlay from Page. __proto__: Page.prototype, + /** Current UI state */ + uiState_: UIState.UNKNKOWN, + get uiState() { + return this.uiState_; + }, + set uiState(newUiState) { + if (newUiState == this.uiState_) + return; + + this.uiState_ = newUiState; + switch (this.uiState_) { + case UIState.OFFLINE: + this.setUpOfflineUI_(); + break; + case UIState.IDLE: + this.setUpTurnOffUI_(false); + break; + case UIState.PENDING: + this.setUpTurnOffUI_(true); + break; + case UIState.SERVER_ERROR: + this.setUpServerErrorUI_(); + break; + default: + console.error('Unknow Easy unlock turn off UI state: ' + + this.uiState_); + this.setUpTurnOffUI_(false); + break; + } + }, + /** @override */ initializePage: function() { Page.prototype.initializePage.call(this); @@ -31,23 +72,26 @@ cr.define('options', function() { EasyUnlockTurnOffOverlay.dismiss(); }; $('easy-unlock-turn-off-confirm').onclick = function(event) { - $('easy-unlock-turn-off-confirm').disabled = true; - this.setSpinnerVisible_(true); - - // TODO(xiyuan): Wire this up. - // chrome.send('turnOffEasyUnlock'); + this.uiState = UIState.PENDING; + chrome.send('easyUnlockRequestTurnOff'); }.bind(this); }, /** @override */ didShowPage: function() { if (navigator.onLine) { - this.setUpTurnOffUI_(); + this.uiState = UIState.IDLE; + chrome.send('easyUnlockGetTurnOffFlowStatus'); } else { - this.setUpOfflineUI_(); + this.uiState = UIState.OFFLINE; } }, + /** @override */ + didClosePage: function() { + chrome.send('easyUnlockTurnOffOverlayDismissed'); + }, + /** * Returns the button strip element. * @return {HTMLDivElement} The container div of action buttons. @@ -91,9 +135,10 @@ cr.define('options', function() { /** * Set up UI for turning off Easy Unlock. + * @param {boolean} pending Whether there is a pending turn-off call. * @private */ - setUpTurnOffUI_: function() { + setUpTurnOffUI_: function(pending) { $('easy-unlock-turn-off-title').textContent = loadTimeData.getString('easyUnlockTurnOffTitle'); $('easy-unlock-turn-off-messagee').textContent = @@ -102,8 +147,8 @@ cr.define('options', function() { loadTimeData.getString('easyUnlockTurnOffButton'); this.setActionButtonsVisible_(true); - this.setSpinnerVisible_(false); - $('easy-unlock-turn-off-confirm').disabled = false; + this.setSpinnerVisible_(pending); + $('easy-unlock-turn-off-confirm').disabled = pending; $('easy-unlock-turn-off-dismiss').hidden = false; }, @@ -126,10 +171,21 @@ cr.define('options', function() { }, }; + /** + * Closes the Easy unlock turn off overlay. + */ EasyUnlockTurnOffOverlay.dismiss = function() { PageManager.closeOverlay(); }; + /** + * Update UI to reflect the turn off operation status. + * @param {string} newState The UIState string representing the new state. + */ + EasyUnlockTurnOffOverlay.updateUIState = function(newState) { + EasyUnlockTurnOffOverlay.getInstance().uiState = newState; + }; + // Export return { EasyUnlockTurnOffOverlay: EasyUnlockTurnOffOverlay diff --git a/chrome/browser/signin/easy_unlock_service.cc b/chrome/browser/signin/easy_unlock_service.cc index 10dbf203b369..52d9d5c92ba4 100644 --- a/chrome/browser/signin/easy_unlock_service.cc +++ b/chrome/browser/signin/easy_unlock_service.cc @@ -9,12 +9,15 @@ #include "base/logging.h" #include "base/metrics/field_trial.h" #include "base/prefs/pref_service.h" +#include "base/prefs/scoped_user_pref_update.h" #include "base/values.h" #include "chrome/browser/extensions/component_loader.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/easy_unlock_screenlock_state_handler.h" #include "chrome/browser/signin/easy_unlock_service_factory.h" +#include "chrome/browser/signin/easy_unlock_service_observer.h" +#include "chrome/browser/signin/easy_unlock_toggle_flow.h" #include "chrome/browser/signin/screenlock_bridge.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/common/chrome_switches.h" @@ -31,6 +34,15 @@ namespace { +// Key name of the local device permit record dictonary in kEasyUnlockPairing. +const char kKeyPermitAccess[] = "permitAccess"; + +// Key name of the remote device list in kEasyUnlockPairing. +const char kKeyDevices[] = "devices"; + +// Key name of the phone public key in a device dictionary. +const char kKeyPhoneId[] = "permitRecord.id"; + extensions::ComponentLoader* GetComponentLoader( content::BrowserContext* context) { extensions::ExtensionSystem* extension_system = @@ -48,6 +60,7 @@ EasyUnlockService* EasyUnlockService::Get(Profile* profile) { EasyUnlockService::EasyUnlockService(Profile* profile) : profile_(profile), + turn_off_flow_status_(IDLE), weak_ptr_factory_(this) { extensions::ExtensionSystem::Get(profile_)->ready().Post( FROM_HERE, @@ -108,7 +121,6 @@ bool EasyUnlockService::IsAllowed() { #endif } - EasyUnlockScreenlockStateHandler* EasyUnlockService::GetScreenlockStateHandler() { if (!IsAllowed()) @@ -122,6 +134,98 @@ EasyUnlockScreenlockStateHandler* return screenlock_state_handler_.get(); } +const base::DictionaryValue* EasyUnlockService::GetPermitAccess() const { + const base::DictionaryValue* pairing_dict = + profile_->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing); + const base::DictionaryValue* permit_dict = NULL; + if (pairing_dict && + pairing_dict->GetDictionary(kKeyPermitAccess, &permit_dict)) { + return permit_dict; + } + + return NULL; +} + +void EasyUnlockService::SetPermitAccess(const base::DictionaryValue& permit) { + DictionaryPrefUpdate pairing_update(profile_->GetPrefs(), + prefs::kEasyUnlockPairing); + pairing_update->SetWithoutPathExpansion(kKeyPermitAccess, permit.DeepCopy()); +} + +void EasyUnlockService::ClearPermitAccess() { + DictionaryPrefUpdate pairing_update(profile_->GetPrefs(), + prefs::kEasyUnlockPairing); + pairing_update->RemoveWithoutPathExpansion(kKeyPermitAccess, NULL); +} + +const base::ListValue* EasyUnlockService::GetRemoteDevices() const { + const base::DictionaryValue* pairing_dict = + profile_->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing); + const base::ListValue* devices = NULL; + if (pairing_dict && pairing_dict->GetList(kKeyDevices, &devices)) { + return devices; + } + + return NULL; +} + +void EasyUnlockService::SetRemoteDevices(const base::ListValue& devices) { + DictionaryPrefUpdate pairing_update(profile_->GetPrefs(), + prefs::kEasyUnlockPairing); + pairing_update->SetWithoutPathExpansion(kKeyDevices, devices.DeepCopy()); +} + +void EasyUnlockService::ClearRemoteDevices() { + DictionaryPrefUpdate pairing_update(profile_->GetPrefs(), + prefs::kEasyUnlockPairing); + pairing_update->RemoveWithoutPathExpansion(kKeyDevices, NULL); +} + +void EasyUnlockService::AddObserver(EasyUnlockServiceObserver* observer) { + observers_.AddObserver(observer); +} + +void EasyUnlockService::RemoveObserver(EasyUnlockServiceObserver* observer) { + observers_.RemoveObserver(observer); +} + +void EasyUnlockService::RunTurnOffFlow() { + if (turn_off_flow_status_ == PENDING) + return; + + SetTurnOffFlowStatus(PENDING); + + // Currently there should only be one registered phone. + // TODO(xiyuan): Revisit this when server supports toggle for all or + // there are multiple phones. + const base::DictionaryValue* pairing_dict = + profile_->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing); + const base::ListValue* devices_list = NULL; + const base::DictionaryValue* first_device = NULL; + std::string phone_public_key; + if (!pairing_dict || !pairing_dict->GetList(kKeyDevices, &devices_list) || + !devices_list || !devices_list->GetDictionary(0, &first_device) || + !first_device || + !first_device->GetString(kKeyPhoneId, &phone_public_key)) { + LOG(WARNING) << "Bad easy unlock pairing data, wiping out local data"; + OnTurnOffFlowFinished(true); + return; + } + + turn_off_flow_.reset(new EasyUnlockToggleFlow( + profile_, + phone_public_key, + false, + base::Bind(&EasyUnlockService::OnTurnOffFlowFinished, + base::Unretained(this)))); + turn_off_flow_->Start(); +} + +void EasyUnlockService::ResetTurnOffFlow() { + turn_off_flow_.reset(); + SetTurnOffFlowStatus(IDLE); +} + void EasyUnlockService::Initialize() { registrar_.Init(profile_->GetPrefs()); registrar_.Add( @@ -169,3 +273,28 @@ void EasyUnlockService::OnPrefsChanged() { screenlock_state_handler_.reset(); } } + +void EasyUnlockService::SetTurnOffFlowStatus(TurnOffFlowStatus status) { + turn_off_flow_status_ = status; + FOR_EACH_OBSERVER( + EasyUnlockServiceObserver, observers_, OnTurnOffOperationStatusChanged()); +} + +void EasyUnlockService::OnTurnOffFlowFinished(bool success) { + turn_off_flow_.reset(); + + if (!success) { + SetTurnOffFlowStatus(FAIL); + return; + } + + ClearRemoteDevices(); + SetTurnOffFlowStatus(IDLE); + + if (GetComponentLoader(profile_)->Exists(extension_misc::kEasyUnlockAppId)) { + extensions::ExtensionSystem* extension_system = + extensions::ExtensionSystem::Get(profile_); + extension_system->extension_service()->ReloadExtension( + extension_misc::kEasyUnlockAppId); + } +} diff --git a/chrome/browser/signin/easy_unlock_service.h b/chrome/browser/signin/easy_unlock_service.h index a8379f740349..996b4110c5df 100644 --- a/chrome/browser/signin/easy_unlock_service.h +++ b/chrome/browser/signin/easy_unlock_service.h @@ -6,19 +6,34 @@ #define CHROME_BROWSER_SIGNIN_EASY_UNLOCK_SERVICE_H_ #include "base/macros.h" +#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/observer_list.h" #include "base/prefs/pref_change_registrar.h" #include "components/keyed_service/core/keyed_service.h" +namespace base { +class DictionaryValue; +class ListValue; +} + namespace user_prefs { class PrefRegistrySyncable; } class EasyUnlockScreenlockStateHandler; +class EasyUnlockServiceObserver; +class EasyUnlockToggleFlow; class Profile; class EasyUnlockService : public KeyedService { public: + enum TurnOffFlowStatus { + IDLE, + PENDING, + FAIL, + }; + explicit EasyUnlockService(Profile* profile); virtual ~EasyUnlockService(); @@ -42,16 +57,44 @@ class EasyUnlockService : public KeyedService { // Unlock gets disabled. EasyUnlockScreenlockStateHandler* GetScreenlockStateHandler(); + // Gets/Sets/Clears the permit access for the local device. + const base::DictionaryValue* GetPermitAccess() const; + void SetPermitAccess(const base::DictionaryValue& permit); + void ClearPermitAccess(); + + // Gets/Sets/Clears the remote devices list. + const base::ListValue* GetRemoteDevices() const; + void SetRemoteDevices(const base::ListValue& devices); + void ClearRemoteDevices(); + + void RunTurnOffFlow(); + void ResetTurnOffFlow(); + + void AddObserver(EasyUnlockServiceObserver* observer); + void RemoveObserver(EasyUnlockServiceObserver* observer); + + TurnOffFlowStatus turn_off_flow_status() const { + return turn_off_flow_status_; + } + private: void Initialize(); void LoadApp(); void UnloadApp(); void OnPrefsChanged(); + void SetTurnOffFlowStatus(TurnOffFlowStatus status); + void OnTurnOffFlowFinished(bool success); + Profile* profile_; PrefChangeRegistrar registrar_; // Created lazily in |GetScreenlockStateHandler|. scoped_ptr screenlock_state_handler_; + + TurnOffFlowStatus turn_off_flow_status_; + scoped_ptr turn_off_flow_; + ObserverList observers_; + base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(EasyUnlockService); diff --git a/chrome/browser/signin/easy_unlock_service_observer.h b/chrome/browser/signin/easy_unlock_service_observer.h new file mode 100644 index 000000000000..f5569ff6b8d7 --- /dev/null +++ b/chrome/browser/signin/easy_unlock_service_observer.h @@ -0,0 +1,17 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SIGNIN_EASY_UNLOCK_SERVICE_OBSERVER_H_ +#define CHROME_BROWSER_SIGNIN_EASY_UNLOCK_SERVICE_OBSERVER_H_ + +class EasyUnlockServiceObserver { + public: + // Invoked when turn-off operation status changes. + virtual void OnTurnOffOperationStatusChanged() = 0; + + protected: + virtual ~EasyUnlockServiceObserver() {} +}; + +#endif // CHROME_BROWSER_SIGNIN_EASY_UNLOCK_SERVICE_OBSERVER_H_ diff --git a/chrome/browser/signin/easy_unlock_toggle_flow.cc b/chrome/browser/signin/easy_unlock_toggle_flow.cc new file mode 100644 index 000000000000..7655b2b8e164 --- /dev/null +++ b/chrome/browser/signin/easy_unlock_toggle_flow.cc @@ -0,0 +1,213 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/signin/easy_unlock_toggle_flow.h" + +#include + +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" +#include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h" +#include "chrome/common/extensions/extension_constants.h" +#include "components/signin/core/browser/profile_oauth2_token_service.h" +#include "components/signin/core/browser/signin_manager.h" +#include "extensions/browser/extension_system.h" +#include "google_apis/gaia/oauth2_api_call_flow.h" +#include "net/url_request/url_fetcher.h" + +namespace { + +const char kEasyUnlockToggleUrl[] = + "https://www.googleapis.com/cryptauth/v1/deviceSync/toggleeasyunlock"; + +std::vector GetScopes() { + std::vector scopes; + scopes.push_back("https://www.googleapis.com/auth/proximity_auth"); + scopes.push_back("https://www.googleapis.com/auth/cryptauth"); + return scopes; +} + +std::string GetEasyUnlockAppClientId(Profile * profile) { + extensions::ExtensionSystem* extension_system = + extensions::ExtensionSystem::Get(profile); + ExtensionService* extension_service = extension_system->extension_service(); + const extensions::Extension* easy_unlock_app = + extension_service->GetInstalledExtension( + extension_misc::kEasyUnlockAppId); + if (!easy_unlock_app) + return std::string(); + + const extensions::OAuth2Info& oauth2_info = + extensions::OAuth2Info::GetOAuth2Info(easy_unlock_app); + return oauth2_info.client_id; +} + +} // namespace + +class EasyUnlockToggleFlow::ToggleApiCall : public OAuth2ApiCallFlow { + public: + ToggleApiCall(EasyUnlockToggleFlow* flow, + net::URLRequestContextGetter* context, + const std::string& access_token, + const std::string& phone_public_key, + bool toggle_enable); + virtual ~ToggleApiCall(); + + // OAuth2ApiCallFlow + virtual GURL CreateApiCallUrl() OVERRIDE; + virtual std::string CreateApiCallBody() OVERRIDE; + virtual std::string CreateApiCallBodyContentType() OVERRIDE; + virtual void ProcessApiCallSuccess(const net::URLFetcher* source) OVERRIDE; + virtual void ProcessApiCallFailure(const net::URLFetcher* source) OVERRIDE; + virtual void ProcessNewAccessToken(const std::string& access_token) OVERRIDE; + virtual void ProcessMintAccessTokenFailure( + const GoogleServiceAuthError& error) OVERRIDE; + + private: + EasyUnlockToggleFlow* flow_; + const std::string phone_public_key_; + const bool toggle_enable_; + + DISALLOW_COPY_AND_ASSIGN(ToggleApiCall); +}; + +EasyUnlockToggleFlow::ToggleApiCall::ToggleApiCall( + EasyUnlockToggleFlow* flow, + net::URLRequestContextGetter* context, + const std::string& access_token, + const std::string& phone_public_key, + bool toggle_enable) + : OAuth2ApiCallFlow(context, + std::string(), + access_token, + GetScopes()), + flow_(flow), + phone_public_key_(phone_public_key), + toggle_enable_(toggle_enable) { +} + +EasyUnlockToggleFlow::ToggleApiCall::~ToggleApiCall() { +} + +GURL EasyUnlockToggleFlow::ToggleApiCall::CreateApiCallUrl() { + return GURL(kEasyUnlockToggleUrl); +} + +std::string EasyUnlockToggleFlow::ToggleApiCall::CreateApiCallBody() { + const char kBodyFormat[] = "{\"enable\":%s,\"publicKey\":\"%s\"}"; + return base::StringPrintf( + kBodyFormat, + toggle_enable_ ? "true" : "false", + phone_public_key_.c_str()); +} + +std::string +EasyUnlockToggleFlow::ToggleApiCall::CreateApiCallBodyContentType() { + return "application/json"; +} + +void EasyUnlockToggleFlow::ToggleApiCall::ProcessApiCallSuccess( + const net::URLFetcher* source) { + flow_->ReportToggleApiCallResult(true); +} + +void EasyUnlockToggleFlow::ToggleApiCall::ProcessApiCallFailure( + const net::URLFetcher* source) { + flow_->ReportToggleApiCallResult(false); +} + +void EasyUnlockToggleFlow::ToggleApiCall::ProcessNewAccessToken( + const std::string& access_token) { + NOTREACHED(); +} + +void EasyUnlockToggleFlow::ToggleApiCall::ProcessMintAccessTokenFailure( + const GoogleServiceAuthError& error) { + NOTREACHED(); +} + +EasyUnlockToggleFlow::EasyUnlockToggleFlow(Profile* profile, + const std::string& phone_public_key, + bool toggle_enable, + const ToggleFlowCallback& callback) + : OAuth2TokenService::Consumer("easy_unlock_toggle"), + profile_(profile), + phone_public_key_(phone_public_key), + toggle_enable_(toggle_enable), + callback_(callback) { +} + +EasyUnlockToggleFlow::~EasyUnlockToggleFlow() { +} + +void EasyUnlockToggleFlow::Start() { + ProfileOAuth2TokenService* token_service = + ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); + SigninManagerBase* signin_manager = + SigninManagerFactory::GetForProfile(profile_); + token_request_ = + token_service->StartRequest(signin_manager->GetAuthenticatedAccountId(), + OAuth2TokenService::ScopeSet(), + this); +} + +void EasyUnlockToggleFlow::OnGetTokenSuccess( + const OAuth2TokenService::Request* request, + const std::string& access_token, + const base::Time& expiration_time) { + DCHECK_EQ(token_request_.get(), request); + token_request_.reset(); + + mint_token_flow_.reset( + new OAuth2MintTokenFlow(profile_->GetRequestContext(), + this, + OAuth2MintTokenFlow::Parameters( + access_token, + extension_misc::kEasyUnlockAppId, + GetEasyUnlockAppClientId(profile_), + GetScopes(), + OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE))); + mint_token_flow_->Start(); +} + +void EasyUnlockToggleFlow::OnGetTokenFailure( + const OAuth2TokenService::Request* request, + const GoogleServiceAuthError& error) { + DCHECK_EQ(token_request_.get(), request); + token_request_.reset(); + + LOG(ERROR) << "Easy unlock toggle flow, failed to get access token," + << "error=" << error.state(); + callback_.Run(false); +} + +void EasyUnlockToggleFlow::OnMintTokenSuccess(const std::string& access_token, + int time_to_live) { + toggle_api_call_.reset(new ToggleApiCall(this, + profile_->GetRequestContext(), + access_token, + phone_public_key_, + toggle_enable_)); + toggle_api_call_->Start(); +} + +void EasyUnlockToggleFlow::OnMintTokenFailure( + const GoogleServiceAuthError& error) { + LOG(ERROR) << "Easy unlock toggle flow, failed to mint access token," + << "error=" << error.state(); + callback_.Run(false); +} + +void EasyUnlockToggleFlow::OnIssueAdviceSuccess( + const IssueAdviceInfo& issue_advice) { + NOTREACHED(); +} + +void EasyUnlockToggleFlow::ReportToggleApiCallResult(bool success) { + callback_.Run(success); +} diff --git a/chrome/browser/signin/easy_unlock_toggle_flow.h b/chrome/browser/signin/easy_unlock_toggle_flow.h new file mode 100644 index 000000000000..91ec965aadd4 --- /dev/null +++ b/chrome/browser/signin/easy_unlock_toggle_flow.h @@ -0,0 +1,69 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SIGNIN_EASY_UNLOCK_TOGGLE_FLOW_H_ +#define CHROME_BROWSER_SIGNIN_EASY_UNLOCK_TOGGLE_FLOW_H_ + +#include +#include + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "google_apis/gaia/google_service_auth_error.h" +#include "google_apis/gaia/oauth2_mint_token_flow.h" +#include "google_apis/gaia/oauth2_token_service.h" + +class Profile; + +class EasyUnlockToggleFlow : public OAuth2TokenService::Consumer, + public OAuth2MintTokenFlow::Delegate { + public: + // Callback to indicate whether the call succeeds or not. + typedef base::Callback ToggleFlowCallback; + + EasyUnlockToggleFlow(Profile* profile, + const std::string& phone_public_key, + bool toggle_enable, + const ToggleFlowCallback& callback); + virtual ~EasyUnlockToggleFlow(); + + void Start(); + + // OAuth2TokenService::Consumer + virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request, + const std::string& access_token, + const base::Time& expiration_time) OVERRIDE; + virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request, + const GoogleServiceAuthError& error) OVERRIDE; + + // OAuth2MintTokenFlow::Delegate + virtual void OnMintTokenSuccess(const std::string& access_token, + int time_to_live) OVERRIDE; + virtual void OnMintTokenFailure( + const GoogleServiceAuthError& error) OVERRIDE; + virtual void OnIssueAdviceSuccess( + const IssueAdviceInfo& issue_advice) OVERRIDE; + + private: + // Derived OAuth2ApiCallFlow class to make toggle api call after access token + // is available. + class ToggleApiCall; + + // Callbacks from ToggleApiCall + void ReportToggleApiCallResult(bool success); + + Profile* profile_; + const std::string phone_public_key_; + const bool toggle_enable_; + ToggleFlowCallback callback_; + + scoped_ptr token_request_; + scoped_ptr mint_token_flow_; + scoped_ptr toggle_api_call_; + + DISALLOW_COPY_AND_ASSIGN(EasyUnlockToggleFlow); +}; + +#endif // CHROME_BROWSER_SIGNIN_EASY_UNLOCK_TOGGLE_FLOW_H_ diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index d33ad338dc50..1863c7df00b1 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc @@ -250,20 +250,6 @@ void BrowserOptionsHandler::GetLocalizedValues(base::DictionaryValue* values) { { "easyUnlockSectionTitle", IDS_OPTIONS_EASY_UNLOCK_SECTION_TITLE }, { "easyUnlockSetupButton", IDS_OPTIONS_EASY_UNLOCK_SETUP_BUTTON }, { "easyUnlockSetupIntro", IDS_OPTIONS_EASY_UNLOCK_SETUP_INTRO }, - { "easyUnlockTurnOffButton", IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_BUTTON }, - { "easyUnlockTurnOffTitle", IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_TITLE }, - { "easyUnlockTurnOffDescription", - IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_DESCRIPTION }, - { "easyUnlockTurnOffOfflineTitle", - IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_OFFLINE_TITLE }, - { "easyUnlockTurnOffOfflineMessage", - IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_OFFLINE_MESSAGE }, - { "easyUnlockTurnOffErrorTitle", - IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_ERROR_TITLE }, - { "easyUnlockTurnOffErrorMessage", - IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_ERROR_MESSAGE }, - { "easyUnlockTurnOffRetryButton", - IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_RETRY_BUTTON }, { "extensionControlled", IDS_OPTIONS_TAB_EXTENSION_CONTROLLED }, { "extensionDisable", IDS_OPTIONS_TAB_EXTENSION_CONTROLLED_DISABLE }, { "fontSettingsCustomizeFontsButton", @@ -1838,8 +1824,9 @@ void BrowserOptionsHandler::SetupManagingSupervisedUsers() { void BrowserOptionsHandler::SetupEasyUnlock() { // TODO(xiyuan): Update when pairing data is really availble. - bool has_pairing = !Profile::FromWebUI(web_ui())->GetPrefs() - ->GetDictionary(prefs::kEasyUnlockPairing)->empty(); + const base::ListValue* devices = + EasyUnlockService::Get(Profile::FromWebUI(web_ui()))->GetRemoteDevices(); + bool has_pairing = devices && !devices->empty(); base::FundamentalValue has_pairing_value(has_pairing); web_ui()->CallJavascriptFunction( "BrowserOptions.updateEasyUnlock", diff --git a/chrome/browser/ui/webui/options/easy_unlock_handler.cc b/chrome/browser/ui/webui/options/easy_unlock_handler.cc new file mode 100644 index 000000000000..493a6d788f79 --- /dev/null +++ b/chrome/browser/ui/webui/options/easy_unlock_handler.cc @@ -0,0 +1,107 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/options/easy_unlock_handler.h" + +#include "base/bind.h" +#include "base/values.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/easy_unlock_service.h" +#include "content/public/browser/web_ui.h" +#include "grit/generated_resources.h" + +namespace options { + +EasyUnlockHandler::EasyUnlockHandler() { +} + +EasyUnlockHandler::~EasyUnlockHandler() { + EasyUnlockService::Get(Profile::FromWebUI(web_ui()))->RemoveObserver(this); +} + +void EasyUnlockHandler::GetLocalizedValues(base::DictionaryValue* values) { + static OptionsStringResource resources[] = { + {"easyUnlockTurnOffButton", IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_BUTTON}, + {"easyUnlockTurnOffTitle", IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_TITLE}, + {"easyUnlockTurnOffDescription", + IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_DESCRIPTION}, + {"easyUnlockTurnOffOfflineTitle", + IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_OFFLINE_TITLE}, + {"easyUnlockTurnOffOfflineMessage", + IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_OFFLINE_MESSAGE}, + {"easyUnlockTurnOffErrorTitle", + IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_ERROR_TITLE}, + {"easyUnlockTurnOffErrorMessage", + IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_ERROR_MESSAGE}, + {"easyUnlockTurnOffRetryButton", + IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_RETRY_BUTTON}, + }; + + RegisterStrings(values, resources, arraysize(resources)); +} + +void EasyUnlockHandler::InitializeHandler() { + EasyUnlockService::Get(Profile::FromWebUI(web_ui()))->AddObserver(this); +} + +void EasyUnlockHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback( + "easyUnlockGetTurnOffFlowStatus", + base::Bind(&EasyUnlockHandler::HandleGetTurnOffFlowStatus, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "easyUnlockRequestTurnOff", + base::Bind(&EasyUnlockHandler::HandleRequestTurnOff, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "easyUnlockTurnOffOverlayDismissed", + base::Bind(&EasyUnlockHandler::HandlePageDismissed, + base::Unretained(this))); +} + +void EasyUnlockHandler::OnTurnOffOperationStatusChanged() { + SendTurnOffOperationStatus(); +} + +void EasyUnlockHandler::SendTurnOffOperationStatus() { + EasyUnlockService::TurnOffFlowStatus status = + EasyUnlockService::Get(Profile::FromWebUI(web_ui())) + ->turn_off_flow_status(); + + // Translate status into JS UI state string. Note the translated string + // should match UIState defined in easy_unlock_turn_off_overlay.js. + std::string status_string; + switch (status) { + case EasyUnlockService::IDLE: + status_string = "idle"; + break; + case EasyUnlockService::PENDING: + status_string = "pending"; + break; + case EasyUnlockService::FAIL: + status_string = "server-error"; + break; + default: + LOG(ERROR) << "Unknown Easy unlock turn-off operation status: " << status; + status_string = "idle"; + break; + } + web_ui()->CallJavascriptFunction("EasyUnlockTurnOffOverlay.updateUIState", + base::StringValue(status_string)); +} + +void EasyUnlockHandler::HandleGetTurnOffFlowStatus( + const base::ListValue* args) { + SendTurnOffOperationStatus(); +} + +void EasyUnlockHandler::HandleRequestTurnOff(const base::ListValue* args) { + EasyUnlockService::Get(Profile::FromWebUI(web_ui()))->RunTurnOffFlow(); +} + +void EasyUnlockHandler::HandlePageDismissed(const base::ListValue* args) { + EasyUnlockService::Get(Profile::FromWebUI(web_ui()))->ResetTurnOffFlow(); +} + +} // namespace options diff --git a/chrome/browser/ui/webui/options/easy_unlock_handler.h b/chrome/browser/ui/webui/options/easy_unlock_handler.h new file mode 100644 index 000000000000..24173fa7df3e --- /dev/null +++ b/chrome/browser/ui/webui/options/easy_unlock_handler.h @@ -0,0 +1,43 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS_EASY_UNLOCK_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_OPTIONS_EASY_UNLOCK_HANDLER_H_ + +#include "base/macros.h" +#include "chrome/browser/signin/easy_unlock_service_observer.h" +#include "chrome/browser/ui/webui/options/options_ui.h" + +namespace options { + +class EasyUnlockHandler : public OptionsPageUIHandler, + public EasyUnlockServiceObserver { + public: + EasyUnlockHandler(); + virtual ~EasyUnlockHandler(); + + // OptionsPageUIHandler + virtual void InitializeHandler() OVERRIDE; + virtual void GetLocalizedValues(base::DictionaryValue* values) OVERRIDE; + + // WebUIMessageHandler + virtual void RegisterMessages() OVERRIDE; + + // EasyUnlockServiceObserver + virtual void OnTurnOffOperationStatusChanged() OVERRIDE; + + private: + void SendTurnOffOperationStatus(); + + // JS callbacks. + void HandleGetTurnOffFlowStatus(const base::ListValue* args); + void HandleRequestTurnOff(const base::ListValue* args); + void HandlePageDismissed(const base::ListValue* args); + + DISALLOW_COPY_AND_ASSIGN(EasyUnlockHandler); +}; + +} // namespace options + +#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS_EASY_UNLOCK_HANDLER_H_ diff --git a/chrome/browser/ui/webui/options/options_ui.cc b/chrome/browser/ui/webui/options/options_ui.cc index 14a49f305c59..4a703e269b13 100644 --- a/chrome/browser/ui/webui/options/options_ui.cc +++ b/chrome/browser/ui/webui/options/options_ui.cc @@ -30,6 +30,7 @@ #include "chrome/browser/ui/webui/options/cookies_view_handler.h" #include "chrome/browser/ui/webui/options/core_options_handler.h" #include "chrome/browser/ui/webui/options/create_profile_handler.h" +#include "chrome/browser/ui/webui/options/easy_unlock_handler.h" #include "chrome/browser/ui/webui/options/font_settings_handler.h" #include "chrome/browser/ui/webui/options/handler_options_handler.h" #include "chrome/browser/ui/webui/options/home_page_overlay_handler.h" @@ -273,6 +274,7 @@ OptionsUI::OptionsUI(content::WebUI* web_ui) AddOptionsPageUIHandler(localized_strings, new ContentSettingsHandler()); AddOptionsPageUIHandler(localized_strings, new CookiesViewHandler()); AddOptionsPageUIHandler(localized_strings, new CreateProfileHandler()); + AddOptionsPageUIHandler(localized_strings, new EasyUnlockHandler()); AddOptionsPageUIHandler(localized_strings, new FontSettingsHandler()); #if defined(ENABLE_GOOGLE_NOW) AddOptionsPageUIHandler(localized_strings, new GeolocationOptionsHandler()); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 83a4042f3616..0345d1b53fce 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1544,6 +1544,8 @@ 'browser/signin/easy_unlock_service.h', 'browser/signin/easy_unlock_service_factory.cc', 'browser/signin/easy_unlock_service_factory.h', + 'browser/signin/easy_unlock_toggle_flow.cc', + 'browser/signin/easy_unlock_toggle_flow.h', 'browser/speech/extension_api/tts_engine_extension_api.cc', 'browser/speech/extension_api/tts_engine_extension_api.h', 'browser/speech/extension_api/tts_engine_extension_observer.cc', diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 3db0a9835f43..5718eeeba2a6 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -1706,6 +1706,8 @@ 'browser/ui/webui/options/core_options_handler.h', 'browser/ui/webui/options/create_profile_handler.cc', 'browser/ui/webui/options/create_profile_handler.h', + 'browser/ui/webui/options/easy_unlock_handler.cc', + 'browser/ui/webui/options/easy_unlock_handler.h', 'browser/ui/webui/options/font_settings_handler.cc', 'browser/ui/webui/options/font_settings_handler.h', 'browser/ui/webui/options/font_settings_utils.h', diff --git a/chrome/common/extensions/api/easy_unlock_private.idl b/chrome/common/extensions/api/easy_unlock_private.idl index 32e6410d7b30..1648853257bf 100644 --- a/chrome/common/extensions/api/easy_unlock_private.idl +++ b/chrome/common/extensions/api/easy_unlock_private.idl @@ -44,6 +44,9 @@ AUTHENTICATED }; + // Type of a permit. All lower case to match permit.PermitRecord.Type. + enum PermitType {access, license}; + // Options that can be passed to |unwrapSecureMessage| method. dictionary UnwrapSecureMessageOptions { // The data associated with the message. For the message to be succesfully @@ -86,6 +89,39 @@ SignatureType? signType; }; + // A permit record contains the credentials used to request or grant + // authorization of a permit. + dictionary PermitRecord { + // ID of the permit, which identifies the service/application that these + // permit records are used in. + DOMString permitId; + + // An identifier for this record that should be unique among all other + // records of the same permit. + DOMString id; + + // Type of the record. + PermitType type; + + // Websafe base64 encoded payload data of the record. + DOMString data; + }; + + // Device information that can be authenticated for Easy unlock. + dictionary Device { + // The Bluetooth address of the device. + DOMString bluetoothAddress; + + // The name of the device. + DOMString? name; + + // The permit record of the device. + PermitRecord? permitRecord; + + // Websafe base64 encoded persistent symmetric key. + DOMString? psk; + }; + // Callback for crypto methods that return a single array buffer. callback DataCallback = void(optional ArrayBuffer data); @@ -99,6 +135,12 @@ callback KeyPairCallback = void(optional ArrayBuffer public_key, optional ArrayBuffer private_key); + // Callback for the getPermitAccess() method. + callback GetPermitAccessCallback = void(optional PermitRecord permitAccess); + + // Callback for the getRemoteDevices() method. + callback GetRemoteDevicesCallback = void(Device[] devices); + interface Functions { // Gets localized strings required to render the API. // @@ -175,5 +217,26 @@ // Updates the screenlock state to reflect the Easy Unlock app state. static void updateScreenlockState(State state, optional EmptyCallback callback); + + // Saves the permit record for the local device. + // |permitAccess|: The permit record to be saved. + // |callback|: Called to indicate success or failure. + static void setPermitAccess(PermitRecord permitAccess, + optional EmptyCallback callback); + + // Gets the permit record for the local device. + static void getPermitAccess(GetPermitAccessCallback callback); + + // Clears the permit record for the local device. + static void clearPermitAccess(optional EmptyCallback callback); + + // Saves the remote device list. + // |devices|: The list of remote devices to be saved. + // |callback|: Called to indicate success or failure. + static void setRemoteDevices(Device[] devices, + optional EmptyCallback callback); + + // Gets the remote device list. + static void getRemoteDevices(GetRemoteDevicesCallback callback); }; }; diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index f77176c5a1da..d7687ea45bab 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h @@ -936,6 +936,11 @@ enum HistogramValue { USBPRIVATE_GETDEVICEINFO, EASYUNLOCKPRIVATE_UPDATESCREENLOCKSTATE, CAST_CHANNEL_GETLOGS, + EASYUNLOCKPRIVATE_SETPERMITACCESS, + EASYUNLOCKPRIVATE_GETPERMITACCESS, + EASYUNLOCKPRIVATE_CLEARPERMITACCESS, + EASYUNLOCKPRIVATE_SETREMOTEDEVICES, + EASYUNLOCKPRIVATE_GETREMOTEDEVICES, // Last entry: Add new entries above and ensure to update // tools/metrics/histograms/histograms.xml. ENUM_BOUNDARY diff --git a/google_apis/gaia/oauth2_api_call_flow.cc b/google_apis/gaia/oauth2_api_call_flow.cc index 08312ebe5d39..07f32082817f 100644 --- a/google_apis/gaia/oauth2_api_call_flow.cc +++ b/google_apis/gaia/oauth2_api_call_flow.cc @@ -90,7 +90,8 @@ void OAuth2ApiCallFlow::EndApiCall(const net::URLFetcher* source) { return; } - if (source->GetResponseCode() != net::HTTP_OK) { + if (source->GetResponseCode() != net::HTTP_OK && + source->GetResponseCode() != net::HTTP_NO_CONTENT) { state_ = ERROR_STATE; ProcessApiCallFailure(source); return; @@ -125,6 +126,10 @@ void OAuth2ApiCallFlow::EndMintAccessToken( } } +std::string OAuth2ApiCallFlow::CreateApiCallBodyContentType() { + return "application/x-www-form-urlencoded"; +} + OAuth2AccessTokenFetcher* OAuth2ApiCallFlow::CreateAccessTokenFetcher() { return new OAuth2AccessTokenFetcherImpl(this, context_, refresh_token_); } @@ -166,7 +171,7 @@ URLFetcher* OAuth2ApiCallFlow::CreateURLFetcher() { result->SetAutomaticallyRetryOnNetworkChanges(3); if (!empty_body) - result->SetUploadData("application/x-www-form-urlencoded", body); + result->SetUploadData(CreateApiCallBodyContentType(), body); return result; } diff --git a/google_apis/gaia/oauth2_api_call_flow.h b/google_apis/gaia/oauth2_api_call_flow.h index b29bc8a13904..70c9b5131d5c 100644 --- a/google_apis/gaia/oauth2_api_call_flow.h +++ b/google_apis/gaia/oauth2_api_call_flow.h @@ -66,6 +66,7 @@ class OAuth2ApiCallFlow // Methods to help create HTTP request. virtual GURL CreateApiCallUrl() = 0; virtual std::string CreateApiCallBody() = 0; + virtual std::string CreateApiCallBodyContentType(); // Sub-classes can expose an appropriate observer interface by implementing // these template methods. diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 341772f66cb3..85fcfe1bb3bf 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -40788,6 +40788,11 @@ Therefore, the affected-histogram name has to have at least one dot in it. + + + + +