OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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/chromeos/extensions/quick_unlock_private/quick_unlock_p
rivate_api.h" |
| 6 |
| 7 #include "chrome/browser/chromeos/login/quick_unlock/pin_storage.h" |
| 8 #include "chrome/browser/chromeos/login/quick_unlock/pin_storage_factory.h" |
| 9 #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| 10 #include "chromeos/login/auth/extended_authenticator.h" |
| 11 #include "chromeos/login/auth/user_context.h" |
| 12 #include "extensions/browser/event_router.h" |
| 13 |
| 14 namespace extensions { |
| 15 |
| 16 namespace quick_unlock_private = api::quick_unlock_private; |
| 17 namespace SetModes = quick_unlock_private::SetModes; |
| 18 namespace GetActiveModes = quick_unlock_private::GetActiveModes; |
| 19 namespace GetAvailableModes = quick_unlock_private::GetAvailableModes; |
| 20 namespace OnActiveModesChanged = quick_unlock_private::OnActiveModesChanged; |
| 21 using QuickUnlockMode = quick_unlock_private::QuickUnlockMode; |
| 22 using QuickUnlockModeList = std::vector<QuickUnlockMode>; |
| 23 |
| 24 namespace { |
| 25 |
| 26 const char kModesAndCredentialsLengthMismatch[] = |
| 27 "|modes| and |credentials| must have the same number of elements"; |
| 28 const char kMultipleModesNotSupported[] = |
| 29 "At most one quick unlock mode can be active."; |
| 30 |
| 31 // Returns the active set of quick unlock modes. |
| 32 QuickUnlockModeList ComputeActiveModes(Profile* profile) { |
| 33 QuickUnlockModeList modes; |
| 34 |
| 35 chromeos::PinStorage* pin_storage = |
| 36 chromeos::PinStorageFactory::GetForProfile(profile); |
| 37 if (pin_storage->IsPinSet()) |
| 38 modes.push_back(quick_unlock_private::QUICK_UNLOCK_MODE_PIN); |
| 39 |
| 40 return modes; |
| 41 } |
| 42 |
| 43 // Returns true if |a| and |b| contain the same elements. The elements do not |
| 44 // need to be in the same order. |
| 45 bool AreModesEqual(const QuickUnlockModeList& a, const QuickUnlockModeList& b) { |
| 46 if (a.size() != b.size()) |
| 47 return false; |
| 48 |
| 49 // This is a slow comparison algorithm, but the number of entries in |a| and |
| 50 // |b| will always be very low (0-3 items) so it doesn't matter. |
| 51 for (size_t i = 0; i < a.size(); ++i) { |
| 52 if (std::find(b.begin(), b.end(), a[i]) == b.end()) |
| 53 return false; |
| 54 } |
| 55 |
| 56 return true; |
| 57 } |
| 58 |
| 59 } // namespace |
| 60 |
| 61 // quickUnlockPrivate.getAvailableModes |
| 62 |
| 63 QuickUnlockPrivateGetAvailableModesFunction:: |
| 64 QuickUnlockPrivateGetAvailableModesFunction() |
| 65 : chrome_details_(this) {} |
| 66 |
| 67 QuickUnlockPrivateGetAvailableModesFunction:: |
| 68 ~QuickUnlockPrivateGetAvailableModesFunction() {} |
| 69 |
| 70 ExtensionFunction::ResponseAction |
| 71 QuickUnlockPrivateGetAvailableModesFunction::Run() { |
| 72 // TODO(jdufault): Check for policy and do not return PIN if policy makes it |
| 73 // unavailable. See crbug.com/612271. |
| 74 const QuickUnlockModeList modes = { |
| 75 quick_unlock_private::QUICK_UNLOCK_MODE_PIN}; |
| 76 |
| 77 return RespondNow(ArgumentList(GetAvailableModes::Results::Create(modes))); |
| 78 } |
| 79 |
| 80 // quickUnlockPrivate.getActiveModes |
| 81 |
| 82 QuickUnlockPrivateGetActiveModesFunction:: |
| 83 QuickUnlockPrivateGetActiveModesFunction() |
| 84 : chrome_details_(this) {} |
| 85 |
| 86 QuickUnlockPrivateGetActiveModesFunction:: |
| 87 ~QuickUnlockPrivateGetActiveModesFunction() {} |
| 88 |
| 89 ExtensionFunction::ResponseAction |
| 90 QuickUnlockPrivateGetActiveModesFunction::Run() { |
| 91 const QuickUnlockModeList modes = |
| 92 ComputeActiveModes(chrome_details_.GetProfile()); |
| 93 return RespondNow(ArgumentList(GetActiveModes::Results::Create(modes))); |
| 94 } |
| 95 |
| 96 // quickUnlockPrivate.setModes |
| 97 |
| 98 QuickUnlockPrivateSetModesFunction::QuickUnlockPrivateSetModesFunction() |
| 99 : chrome_details_(this) {} |
| 100 |
| 101 QuickUnlockPrivateSetModesFunction::~QuickUnlockPrivateSetModesFunction() {} |
| 102 |
| 103 void QuickUnlockPrivateSetModesFunction::SetAuthenticatorAllocatorForTesting( |
| 104 const QuickUnlockPrivateSetModesFunction::AuthenticatorAllocator& |
| 105 allocator) { |
| 106 authenticator_allocator_ = allocator; |
| 107 } |
| 108 |
| 109 void QuickUnlockPrivateSetModesFunction::SetModesChangedEventHandlerForTesting( |
| 110 const ModesChangedEventHandler& handler) { |
| 111 modes_changed_handler_ = handler; |
| 112 } |
| 113 |
| 114 ExtensionFunction::ResponseAction QuickUnlockPrivateSetModesFunction::Run() { |
| 115 params_ = SetModes::Params::Create(*args_); |
| 116 EXTENSION_FUNCTION_VALIDATE(params_.get()); |
| 117 |
| 118 if (params_->modes.size() != params_->credentials.size()) |
| 119 return RespondNow(Error(kModesAndCredentialsLengthMismatch)); |
| 120 |
| 121 if (params_->modes.size() > 1) |
| 122 return RespondNow(Error(kMultipleModesNotSupported)); |
| 123 |
| 124 user_manager::User* user = chromeos::ProfileHelper::Get()->GetUserByProfile( |
| 125 chrome_details_.GetProfile()); |
| 126 chromeos::UserContext user_context(user->GetAccountId()); |
| 127 user_context.SetKey(chromeos::Key(params_->account_password)); |
| 128 |
| 129 // Lazily allocate the authenticator. We do this here, instead of in the ctor, |
| 130 // so that tests can install a fake. |
| 131 if (authenticator_allocator_.is_null()) |
| 132 extended_authenticator_ = chromeos::ExtendedAuthenticator::Create(this); |
| 133 else |
| 134 extended_authenticator_ = authenticator_allocator_.Run(this); |
| 135 |
| 136 // The extension function needs to stay alive while the authenticator is |
| 137 // running the password check. Add a ref before the authenticator starts, and |
| 138 // remove the ref after it invokes one of the OnAuth* callbacks. The PostTask |
| 139 // call applies ref management to the extended_authenticator_ instance and not |
| 140 // to the extension function instance, which is why the manual ref management |
| 141 // is needed. |
| 142 AddRef(); |
| 143 |
| 144 content::BrowserThread::PostTask( |
| 145 content::BrowserThread::UI, FROM_HERE, |
| 146 base::Bind(&chromeos::ExtendedAuthenticator::AuthenticateToCheck, |
| 147 extended_authenticator_.get(), user_context, base::Closure())); |
| 148 |
| 149 return RespondLater(); |
| 150 } |
| 151 |
| 152 void QuickUnlockPrivateSetModesFunction::OnAuthFailure( |
| 153 const chromeos::AuthFailure& error) { |
| 154 Respond(ArgumentList(SetModes::Results::Create(false))); |
| 155 Release(); // Balanced in Run(). |
| 156 } |
| 157 |
| 158 void QuickUnlockPrivateSetModesFunction::OnAuthSuccess( |
| 159 const chromeos::UserContext& user_context) { |
| 160 const QuickUnlockModeList initial_modes = |
| 161 ComputeActiveModes(chrome_details_.GetProfile()); |
| 162 ApplyModeChange(); |
| 163 const QuickUnlockModeList updated_modes = |
| 164 ComputeActiveModes(chrome_details_.GetProfile()); |
| 165 |
| 166 if (!AreModesEqual(initial_modes, updated_modes)) |
| 167 FireEvent(updated_modes); |
| 168 |
| 169 Respond(ArgumentList(SetModes::Results::Create(true))); |
| 170 Release(); // Balanced in Run(). |
| 171 } |
| 172 |
| 173 void QuickUnlockPrivateSetModesFunction::ApplyModeChange() { |
| 174 // This function is setup so it is easy to add another quick unlock mode while |
| 175 // following all of the invariants, which are: |
| 176 // |
| 177 // 1: If an unlock type is not specified, it should be deactivated. |
| 178 // 2: If a credential for an unlock type is empty, it should not be touched. |
| 179 // 3: Otherwise, the credential should be set to the new value. |
| 180 |
| 181 bool update_pin = true; |
| 182 std::string pin_credential; |
| 183 |
| 184 // Compute needed changes. |
| 185 for (size_t i = 0; i < params_->modes.size(); ++i) { |
| 186 const QuickUnlockMode mode = params_->modes[i]; |
| 187 const std::string& credential = params_->credentials[i]; |
| 188 |
| 189 if (mode == quick_unlock_private::QUICK_UNLOCK_MODE_PIN) { |
| 190 update_pin = !credential.empty(); |
| 191 pin_credential = credential; |
| 192 } |
| 193 } |
| 194 |
| 195 // Apply changes. |
| 196 if (update_pin) { |
| 197 Profile* profile = chrome_details_.GetProfile(); |
| 198 chromeos::PinStorage* pin_storage = |
| 199 chromeos::PinStorageFactory::GetForProfile(profile); |
| 200 |
| 201 if (pin_credential.empty()) |
| 202 pin_storage->RemovePin(); |
| 203 else |
| 204 pin_storage->SetPin(pin_credential); |
| 205 } |
| 206 } |
| 207 |
| 208 // Triggers a quickUnlockPrivate.onActiveModesChanged change event. |
| 209 void QuickUnlockPrivateSetModesFunction::FireEvent( |
| 210 const QuickUnlockModeList& modes) { |
| 211 // Allow unit tests to override how events are raised/handled. |
| 212 if (!modes_changed_handler_.is_null()) { |
| 213 modes_changed_handler_.Run(modes); |
| 214 return; |
| 215 } |
| 216 |
| 217 std::unique_ptr<base::ListValue> args = OnActiveModesChanged::Create(modes); |
| 218 std::unique_ptr<Event> event( |
| 219 new Event(events::QUICK_UNLOCK_PRIVATE_ON_ACTIVE_MODES_CHANGED, |
| 220 OnActiveModesChanged::kEventName, std::move(args))); |
| 221 EventRouter::Get(browser_context())->BroadcastEvent(std::move(event)); |
| 222 } |
| 223 |
| 224 } // namespace extensions |
OLD | NEW |