1 // Copyright 2014 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/easy_unlock/easy_unlock_key_manager.h" 6 7 #include "base/bind.h" 8 #include "base/logging.h" 9 #include "base/stl_util.h" 10 #include "base/strings/stringprintf.h" 11 #include "base/values.h" 12 13 namespace chromeos { 14 15 namespace { 16 17 const char kKeyBluetoothAddress[] = "bluetoothAddress"; 18 const char kKeyPermitRecord[] = "permitRecord"; 19 const char kKeyPermitId[] = "permitRecord.id"; 20 const char kKeyPermitPermitId[] = "permitRecord.permitId"; 21 const char kKeyPermitData[] = "permitRecord.data"; 22 const char kKeyPermitType[] = "permitRecord.type"; 23 const char kKeyPsk[] = "psk"; 24 25 const char kKeyLabelPrefix[] = "easy-unlock-"; 26 27 const char kPermitPermitIdFormat[] = "permit://google.com/easyunlock/v1/%s"; 28 const char kPermitTypeLicence[] = "licence"; 29 30 } // namespace 31 32 EasyUnlockKeyManager::EasyUnlockKeyManager() 33 : operation_id_(0), 34 weak_ptr_factory_(this) { 35 } 36 37 EasyUnlockKeyManager::~EasyUnlockKeyManager() { 38 STLDeleteContainerPairSecondPointers(get_keys_ops_.begin(), 39 get_keys_ops_.end()); 40 } 41 42 void EasyUnlockKeyManager::RefreshKeys(const UserContext& user_context, 43 const base::ListValue& remote_devices, 44 const RefreshKeysCallback& callback) { 45 // Must have the secret. 46 DCHECK(!user_context.GetKey()->GetSecret().empty()); 47 48 EasyUnlockDeviceKeyDataList devices; 49 if (!RemoteDeviceListToDeviceDataList(remote_devices, &devices)) 50 devices.clear(); 51 52 // Only one pending request. 53 DCHECK(!HasPendingOperations()); 54 create_keys_op_.reset(new EasyUnlockCreateKeysOperation( 55 user_context, 56 devices, 57 base::Bind(&EasyUnlockKeyManager::OnKeysCreated, 58 weak_ptr_factory_.GetWeakPtr(), 59 devices.size(), 60 callback))); 61 create_keys_op_->Start(); 62 } 63 64 void EasyUnlockKeyManager::RemoveKeys(const UserContext& user_context, 65 size_t start_index, 66 const RemoveKeysCallback& callback) { 67 // Must have the secret. 68 DCHECK(!user_context.GetKey()->GetSecret().empty()); 69 // Only one pending request. 70 DCHECK(!HasPendingOperations()); 71 72 remove_keys_op_.reset( 73 new EasyUnlockRemoveKeysOperation( 74 user_context, 75 start_index, 76 base::Bind(&EasyUnlockKeyManager::OnKeysRemoved, 77 weak_ptr_factory_.GetWeakPtr(), 78 callback))); 79 remove_keys_op_->Start(); 80 } 81 82 void EasyUnlockKeyManager::GetDeviceDataList( 83 const UserContext& user_context, 84 const GetDeviceDataListCallback& callback) { 85 // Defer the get operation if there is pending write operations. 86 if (create_keys_op_ || remove_keys_op_) { 87 pending_ops_.push_back(base::Bind(&EasyUnlockKeyManager::GetDeviceDataList, 88 weak_ptr_factory_.GetWeakPtr(), 89 user_context, 90 callback)); 91 return; 92 } 93 94 const int op_id = GetNextOperationId(); 95 scoped_ptr<EasyUnlockGetKeysOperation> op(new EasyUnlockGetKeysOperation( 96 user_context, 97 base::Bind(&EasyUnlockKeyManager::OnKeysFetched, 98 weak_ptr_factory_.GetWeakPtr(), 99 op_id, 100 callback))); 101 op->Start(); 102 get_keys_ops_[op_id] = op.release(); 103 } 104 105 // static 106 void EasyUnlockKeyManager::DeviceDataToRemoteDeviceDictionary( 107 const std::string& user_id, 108 const EasyUnlockDeviceKeyData& data, 109 base::DictionaryValue* dict) { 110 dict->SetString(kKeyBluetoothAddress, data.bluetooth_address); 111 dict->SetString(kKeyPsk, data.psk); 112 scoped_ptr<base::DictionaryValue> permit_record(new base::DictionaryValue); 113 dict->Set(kKeyPermitRecord, permit_record.release()); 114 dict->SetString(kKeyPermitId, data.public_key); 115 dict->SetString(kKeyPermitData, data.public_key); 116 dict->SetString(kKeyPermitType, kPermitTypeLicence); 117 dict->SetString(kKeyPermitPermitId, 118 base::StringPrintf(kPermitPermitIdFormat, 119 user_id.c_str())); 120 } 121 122 // static 123 bool EasyUnlockKeyManager::RemoteDeviceDictionaryToDeviceData( 124 const base::DictionaryValue& dict, 125 EasyUnlockDeviceKeyData* data) { 126 std::string bluetooth_address; 127 std::string public_key; 128 std::string psk; 129 130 if (!dict.GetString(kKeyBluetoothAddress, &bluetooth_address) || 131 !dict.GetString(kKeyPermitId, &public_key) || 132 !dict.GetString(kKeyPsk, &psk)) { 133 return false; 134 } 135 136 data->bluetooth_address.swap(bluetooth_address); 137 data->public_key.swap(public_key); 138 data->psk.swap(psk); 139 return true; 140 } 141 142 // static 143 void EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList( 144 const std::string& user_id, 145 const EasyUnlockDeviceKeyDataList& data_list, 146 base::ListValue* device_list) { 147 device_list->Clear(); 148 for (size_t i = 0; i < data_list.size(); ++i) { 149 scoped_ptr<base::DictionaryValue> device_dict(new base::DictionaryValue); 150 DeviceDataToRemoteDeviceDictionary( 151 user_id, data_list[i], device_dict.get()); 152 device_list->Append(device_dict.release()); 153 } 154 } 155 156 // static 157 bool EasyUnlockKeyManager::RemoteDeviceListToDeviceDataList( 158 const base::ListValue& device_list, 159 EasyUnlockDeviceKeyDataList* data_list) { 160 EasyUnlockDeviceKeyDataList parsed_devices; 161 for (base::ListValue::const_iterator it = device_list.begin(); 162 it != device_list.end(); 163 ++it) { 164 const base::DictionaryValue* dict; 165 if (!(*it)->GetAsDictionary(&dict) || !dict) 166 return false; 167 168 EasyUnlockDeviceKeyData data; 169 if (!RemoteDeviceDictionaryToDeviceData(*dict, &data)) 170 return false; 171 172 parsed_devices.push_back(data); 173 } 174 175 data_list->swap(parsed_devices); 176 return true; 177 } 178 179 // static 180 std::string EasyUnlockKeyManager::GetKeyLabel(size_t key_index) { 181 return base::StringPrintf("%s%zu", kKeyLabelPrefix, key_index); 182 } 183 184 bool EasyUnlockKeyManager::HasPendingOperations() const { 185 return create_keys_op_ || remove_keys_op_ || !get_keys_ops_.empty(); 186 } 187 188 int EasyUnlockKeyManager::GetNextOperationId() { 189 return ++operation_id_; 190 } 191 192 void EasyUnlockKeyManager::RunNextPendingOp() { 193 if (pending_ops_.empty()) 194 return; 195 196 pending_ops_.front().Run(); 197 pending_ops_.pop_front(); 198 } 199 200 void EasyUnlockKeyManager::OnKeysCreated( 201 size_t remove_start_index, 202 const RefreshKeysCallback& callback, 203 bool create_success) { 204 scoped_ptr<EasyUnlockCreateKeysOperation> op = create_keys_op_.Pass(); 205 if (!callback.is_null()) 206 callback.Run(create_success); 207 208 // Remove extra existing keys. 209 RemoveKeys(op->user_context(), remove_start_index, RemoveKeysCallback()); 210 } 211 212 void EasyUnlockKeyManager::OnKeysRemoved(const RemoveKeysCallback& callback, 213 bool remove_success) { 214 scoped_ptr<EasyUnlockRemoveKeysOperation> op = remove_keys_op_.Pass(); 215 if (!callback.is_null()) 216 callback.Run(remove_success); 217 218 if (!HasPendingOperations()) 219 RunNextPendingOp(); 220 } 221 222 void EasyUnlockKeyManager::OnKeysFetched( 223 int op_id, 224 const GetDeviceDataListCallback& callback, 225 bool fetch_success, 226 const EasyUnlockDeviceKeyDataList& fetched_data) { 227 std::map<int, EasyUnlockGetKeysOperation*>::iterator it = 228 get_keys_ops_.find(op_id); 229 scoped_ptr<EasyUnlockGetKeysOperation> op; 230 if (it != get_keys_ops_.end()) { 231 op.reset(it->second); 232 get_keys_ops_.erase(it); 233 } else { 234 NOTREACHED(); 235 } 236 237 if (!callback.is_null()) 238 callback.Run(fetch_success, fetched_data); 239 240 if (!HasPendingOperations()) 241 RunNextPendingOp(); 242 } 243 244 } // namespace chromeos 245