1 // Copyright (c) 2011 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/login/signed_settings_helper.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/lazy_instance.h" 11 #include "base/logging.h" 12 #include "base/memory/ref_counted.h" 13 #include "chrome/browser/chromeos/login/signed_settings.h" 14 #include "chrome/browser/policy/proto/device_management_backend.pb.h" 15 #include "content/browser/browser_thread.h" 16 17 namespace chromeos { 18 19 namespace { 20 21 class OpContext { 22 public: 23 class Delegate { 24 public: 25 virtual void OnOpCreated(OpContext* context) = 0; 26 virtual void OnOpStarted(OpContext* context) = 0; 27 virtual void OnOpCompleted(OpContext* context) = 0; 28 }; 29 30 virtual ~OpContext() {} 31 32 // Creates and execute op. 33 void Execute() { 34 CreateOp(); 35 CHECK(op_.get()); 36 if (delegate_) 37 delegate_->OnOpCreated(this); 38 39 // Note that the context could be released when op_->Execute() returns. 40 // So keep a local copy of delegate and executing flag to use after 41 // the call. 42 Delegate* delegate = delegate_; 43 executing_ = true; 44 op_->Execute(); 45 if (delegate) 46 delegate->OnOpStarted(this); 47 } 48 49 // Cancels the callback. 50 void CancelCallback() { 51 callback_ = NULL; 52 } 53 54 // Cancels the callback and cancels the op if it is not executing. 55 void Cancel() { 56 CancelCallback(); 57 58 if (!executing_) 59 OnOpCompleted(); 60 } 61 62 // Accessors. 63 SignedSettings* op() const { 64 return op_.get(); 65 } 66 67 SignedSettingsHelper::Callback* callback() const { 68 return callback_; 69 } 70 71 void set_delegate(Delegate* delegate) { 72 delegate_ = delegate; 73 } 74 75 protected: 76 OpContext(SignedSettingsHelper::Callback* callback, 77 Delegate* delegate) 78 : executing_(false), 79 delegate_(delegate), 80 callback_(callback) { 81 } 82 83 // Creates the op to execute. 84 virtual void CreateOp() = 0; 85 86 // Callback on op completion. 87 virtual void OnOpCompleted() { 88 if (delegate_) 89 delegate_->OnOpCompleted(this); 90 91 delete this; 92 } 93 94 bool executing_; 95 Delegate* delegate_; 96 97 scoped_refptr<SignedSettings> op_; 98 SignedSettingsHelper::Callback* callback_; 99 }; 100 101 class WhitelistOpContext : public SignedSettings::Delegate<bool>, 102 public OpContext { 103 public: 104 enum Type { 105 CHECK, 106 ADD, 107 REMOVE, 108 }; 109 110 WhitelistOpContext(Type type, 111 const std::string& email, 112 SignedSettingsHelper::Callback* callback, 113 OpContext::Delegate* delegate) 114 : OpContext(callback, delegate), 115 type_(type), 116 email_(email) { 117 } 118 119 // chromeos::SignedSettings::Delegate implementation 120 virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, 121 bool value) OVERRIDE { 122 if (callback_) { 123 switch (type_) { 124 case CHECK: 125 callback_->OnCheckWhitelistCompleted(code, email_); 126 break; 127 case ADD: 128 callback_->OnWhitelistCompleted(code, email_); 129 break; 130 case REMOVE: 131 callback_->OnUnwhitelistCompleted(code, email_); 132 break; 133 default: 134 LOG(ERROR) << "Unknown WhitelistOpContext type " << type_; 135 break; 136 } 137 } 138 OnOpCompleted(); 139 } 140 141 protected: 142 // OpContext implemenetation 143 virtual void CreateOp() OVERRIDE { 144 switch (type_) { 145 case CHECK: 146 op_ = SignedSettings::CreateCheckWhitelistOp(email_, this); 147 break; 148 case ADD: 149 op_ = SignedSettings::CreateWhitelistOp(email_, true, this); 150 break; 151 case REMOVE: 152 op_ = SignedSettings::CreateWhitelistOp(email_, false, this); 153 break; 154 default: 155 LOG(ERROR) << "Unknown WhitelistOpContext type " << type_; 156 break; 157 } 158 } 159 160 private: 161 Type type_; 162 std::string email_; 163 164 DISALLOW_COPY_AND_ASSIGN(WhitelistOpContext); 165 }; 166 167 class StorePropertyOpContext : public SignedSettings::Delegate<bool>, 168 public OpContext { 169 public: 170 StorePropertyOpContext(const std::string& name, 171 const std::string& value, 172 SignedSettingsHelper::Callback* callback, 173 OpContext::Delegate* delegate) 174 : OpContext(callback, delegate), 175 name_(name), 176 value_(value) { 177 } 178 179 // chromeos::SignedSettings::Delegate implementation 180 virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, 181 bool unused) OVERRIDE { 182 VLOG(2) << "OnSettingsOpCompleted, code = " << code; 183 if (callback_) 184 callback_->OnStorePropertyCompleted(code, name_, value_); 185 OnOpCompleted(); 186 } 187 188 protected: 189 // OpContext implemenetation 190 virtual void CreateOp() OVERRIDE { 191 op_ = SignedSettings::CreateStorePropertyOp(name_, value_, this); 192 } 193 194 private: 195 std::string name_; 196 std::string value_; 197 198 DISALLOW_COPY_AND_ASSIGN(StorePropertyOpContext); 199 }; 200 201 class RetrievePropertyOpContext 202 : public SignedSettings::Delegate<std::string>, 203 public OpContext { 204 public: 205 RetrievePropertyOpContext(const std::string& name, 206 SignedSettingsHelper::Callback* callback, 207 OpContext::Delegate* delegate) 208 : OpContext(callback, delegate), 209 name_(name) { 210 } 211 212 // chromeos::SignedSettings::Delegate implementation 213 virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, 214 std::string value) OVERRIDE { 215 if (callback_) 216 callback_->OnRetrievePropertyCompleted(code, name_, value); 217 218 OnOpCompleted(); 219 } 220 221 protected: 222 // OpContext implemenetation 223 virtual void CreateOp() OVERRIDE { 224 op_ = SignedSettings::CreateRetrievePropertyOp(name_, this); 225 } 226 227 private: 228 std::string name_; 229 230 DISALLOW_COPY_AND_ASSIGN(RetrievePropertyOpContext); 231 }; 232 233 class StorePolicyOpContext : public SignedSettings::Delegate<bool>, 234 public OpContext { 235 public: 236 StorePolicyOpContext(const em::PolicyFetchResponse& policy, 237 SignedSettingsHelper::Callback* callback, 238 OpContext::Delegate* delegate) 239 : OpContext(callback, delegate), 240 policy_(policy) { 241 } 242 243 // chromeos::SignedSettings::Delegate implementation 244 virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, 245 bool unused) OVERRIDE { 246 VLOG(2) << "OnSettingsOpCompleted, code = " << code; 247 if (callback_) 248 callback_->OnStorePolicyCompleted(code); 249 OnOpCompleted(); 250 } 251 252 protected: 253 // OpContext implementation 254 virtual void CreateOp() OVERRIDE { 255 op_ = SignedSettings::CreateStorePolicyOp(&policy_, this); 256 } 257 258 private: 259 em::PolicyFetchResponse policy_; 260 DISALLOW_COPY_AND_ASSIGN(StorePolicyOpContext); 261 }; 262 263 class RetrievePolicyOpContext 264 : public SignedSettings::Delegate<const em::PolicyFetchResponse&>, 265 public OpContext { 266 public: 267 RetrievePolicyOpContext(SignedSettingsHelper::Callback* callback, 268 OpContext::Delegate* delegate) 269 : OpContext(callback, delegate) { 270 } 271 272 // chromeos::SignedSettings::Delegate implementation 273 virtual void OnSettingsOpCompleted( 274 SignedSettings::ReturnCode code, 275 const em::PolicyFetchResponse& policy) OVERRIDE { 276 if (callback_) 277 callback_->OnRetrievePolicyCompleted(code, policy); 278 OnOpCompleted(); 279 } 280 281 protected: 282 // OpContext implementation 283 virtual void CreateOp() OVERRIDE { 284 op_ = SignedSettings::CreateRetrievePolicyOp(this); 285 } 286 287 private: 288 DISALLOW_COPY_AND_ASSIGN(RetrievePolicyOpContext); 289 }; 290 291 } // namespace 292 293 294 class SignedSettingsHelperImpl : public SignedSettingsHelper, 295 public OpContext::Delegate { 296 public: 297 // SignedSettingsHelper implementation 298 virtual void StartCheckWhitelistOp(const std::string& email, 299 Callback* callback) OVERRIDE; 300 virtual void StartWhitelistOp(const std::string& email, 301 bool add_to_whitelist, 302 Callback* callback) OVERRIDE; 303 virtual void StartStorePropertyOp(const std::string& name, 304 const std::string& value, 305 Callback* callback) OVERRIDE; 306 virtual void StartRetrieveProperty(const std::string& name, 307 Callback* callback) OVERRIDE; 308 virtual void StartStorePolicyOp(const em::PolicyFetchResponse& policy, 309 Callback* callback) OVERRIDE; 310 virtual void StartRetrievePolicyOp(Callback* callback) OVERRIDE; 311 virtual void CancelCallback(Callback* callback) OVERRIDE; 312 313 // OpContext::Delegate implementation 314 virtual void OnOpCreated(OpContext* context); 315 virtual void OnOpStarted(OpContext* context); 316 virtual void OnOpCompleted(OpContext* context); 317 318 private: 319 SignedSettingsHelperImpl(); 320 ~SignedSettingsHelperImpl(); 321 322 void AddOpContext(OpContext* context); 323 void ClearAll(); 324 325 std::vector<OpContext*> pending_contexts_; 326 327 friend struct base::DefaultLazyInstanceTraits<SignedSettingsHelperImpl>; 328 DISALLOW_COPY_AND_ASSIGN(SignedSettingsHelperImpl); 329 }; 330 331 static base::LazyInstance<SignedSettingsHelperImpl> 332 g_signed_settings_helper_impl(base::LINKER_INITIALIZED); 333 334 SignedSettingsHelperImpl::SignedSettingsHelperImpl() { 335 } 336 337 SignedSettingsHelperImpl::~SignedSettingsHelperImpl() { 338 if (!pending_contexts_.empty()) { 339 LOG(WARNING) << "SignedSettingsHelperImpl shutdown with pending ops, " 340 << "changes will be lost."; 341 ClearAll(); 342 } 343 } 344 345 void SignedSettingsHelperImpl::StartCheckWhitelistOp( 346 const std::string&email, 347 SignedSettingsHelper::Callback* callback) { 348 AddOpContext(new WhitelistOpContext( 349 WhitelistOpContext::CHECK, 350 email, 351 callback, 352 this)); 353 } 354 355 void SignedSettingsHelperImpl::StartWhitelistOp( 356 const std::string&email, 357 bool add_to_whitelist, 358 SignedSettingsHelper::Callback* callback) { 359 AddOpContext(new WhitelistOpContext( 360 add_to_whitelist ? WhitelistOpContext::ADD : WhitelistOpContext::REMOVE, 361 email, 362 callback, 363 this)); 364 } 365 366 void SignedSettingsHelperImpl::StartStorePropertyOp( 367 const std::string& name, 368 const std::string& value, 369 SignedSettingsHelper::Callback* callback) { 370 AddOpContext(new StorePropertyOpContext( 371 name, 372 value, 373 callback, 374 this)); 375 } 376 377 void SignedSettingsHelperImpl::StartRetrieveProperty( 378 const std::string& name, 379 SignedSettingsHelper::Callback* callback) { 380 AddOpContext(new RetrievePropertyOpContext( 381 name, 382 callback, 383 this)); 384 } 385 386 void SignedSettingsHelperImpl::StartStorePolicyOp( 387 const em::PolicyFetchResponse& policy, 388 SignedSettingsHelper::Callback* callback) { 389 AddOpContext(new StorePolicyOpContext(policy, callback, this)); 390 } 391 392 void SignedSettingsHelperImpl::StartRetrievePolicyOp( 393 SignedSettingsHelper::Callback* callback) { 394 AddOpContext(new RetrievePolicyOpContext(callback, this)); 395 } 396 397 void SignedSettingsHelperImpl::CancelCallback( 398 SignedSettingsHelper::Callback* callback) { 399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 400 401 for (size_t i = 0; i < pending_contexts_.size(); ++i) { 402 if (pending_contexts_[i]->callback() == callback) { 403 pending_contexts_[i]->CancelCallback(); 404 } 405 } 406 } 407 408 void SignedSettingsHelperImpl::AddOpContext(OpContext* context) { 409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 410 CHECK(context); 411 412 pending_contexts_.push_back(context); 413 if (pending_contexts_.size() == 1) 414 context->Execute(); 415 } 416 417 void SignedSettingsHelperImpl::ClearAll() { 418 for (size_t i = 0; i < pending_contexts_.size(); ++i) { 419 pending_contexts_[i]->set_delegate(NULL); 420 pending_contexts_[i]->Cancel(); 421 } 422 pending_contexts_.clear(); 423 } 424 425 void SignedSettingsHelperImpl::OnOpCreated(OpContext* context) { 426 if (test_delegate_) 427 test_delegate_->OnOpCreated(context->op()); 428 } 429 430 void SignedSettingsHelperImpl::OnOpStarted(OpContext* context) { 431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 432 433 if (test_delegate_) 434 test_delegate_->OnOpStarted(context->op()); 435 } 436 437 void SignedSettingsHelperImpl::OnOpCompleted(OpContext* context) { 438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 439 DCHECK(pending_contexts_.front() == context); 440 441 pending_contexts_.erase(pending_contexts_.begin()); 442 if (!pending_contexts_.empty()) 443 pending_contexts_.front()->Execute(); 444 445 if (test_delegate_) 446 test_delegate_->OnOpCompleted(context->op()); 447 } 448 449 SignedSettingsHelper* SignedSettingsHelper::Get() { 450 return g_signed_settings_helper_impl.Pointer(); 451 } 452 453 } // namespace chromeos 454