1 // Copyright 2013 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 "remoting/protocol/pairing_registry.h" 6 7 #include "base/base64.h" 8 #include "base/bind.h" 9 #include "base/guid.h" 10 #include "base/json/json_string_value_serializer.h" 11 #include "base/location.h" 12 #include "base/single_thread_task_runner.h" 13 #include "base/strings/string_number_conversions.h" 14 #include "base/thread_task_runner_handle.h" 15 #include "base/values.h" 16 #include "crypto/random.h" 17 18 namespace remoting { 19 namespace protocol { 20 21 // How many bytes of random data to use for the shared secret. 22 const int kKeySize = 16; 23 24 const char PairingRegistry::kCreatedTimeKey[] = "createdTime"; 25 const char PairingRegistry::kClientIdKey[] = "clientId"; 26 const char PairingRegistry::kClientNameKey[] = "clientName"; 27 const char PairingRegistry::kSharedSecretKey[] = "sharedSecret"; 28 29 PairingRegistry::Pairing::Pairing() { 30 } 31 32 PairingRegistry::Pairing::Pairing(const base::Time& created_time, 33 const std::string& client_name, 34 const std::string& client_id, 35 const std::string& shared_secret) 36 : created_time_(created_time), 37 client_name_(client_name), 38 client_id_(client_id), 39 shared_secret_(shared_secret) { 40 } 41 42 PairingRegistry::Pairing::~Pairing() { 43 } 44 45 PairingRegistry::Pairing PairingRegistry::Pairing::Create( 46 const std::string& client_name) { 47 base::Time created_time = base::Time::Now(); 48 std::string client_id = base::GenerateGUID(); 49 std::string shared_secret; 50 char buffer[kKeySize]; 51 crypto::RandBytes(buffer, arraysize(buffer)); 52 base::Base64Encode(base::StringPiece(buffer, arraysize(buffer)), 53 &shared_secret); 54 return Pairing(created_time, client_name, client_id, shared_secret); 55 } 56 57 PairingRegistry::Pairing PairingRegistry::Pairing::CreateFromValue( 58 const base::DictionaryValue& pairing) { 59 std::string client_name, client_id; 60 double created_time_value; 61 if (pairing.GetDouble(kCreatedTimeKey, &created_time_value) && 62 pairing.GetString(kClientNameKey, &client_name) && 63 pairing.GetString(kClientIdKey, &client_id)) { 64 // The shared secret is optional. 65 std::string shared_secret; 66 pairing.GetString(kSharedSecretKey, &shared_secret); 67 base::Time created_time = base::Time::FromJsTime(created_time_value); 68 return Pairing(created_time, client_name, client_id, shared_secret); 69 } 70 71 LOG(ERROR) << "Failed to load pairing information: unexpected format."; 72 return Pairing(); 73 } 74 75 scoped_ptr<base::DictionaryValue> PairingRegistry::Pairing::ToValue() const { 76 scoped_ptr<base::DictionaryValue> pairing(new base::DictionaryValue()); 77 pairing->SetDouble(kCreatedTimeKey, created_time().ToJsTime()); 78 pairing->SetString(kClientNameKey, client_name()); 79 pairing->SetString(kClientIdKey, client_id()); 80 if (!shared_secret().empty()) 81 pairing->SetString(kSharedSecretKey, shared_secret()); 82 return pairing.Pass(); 83 } 84 85 bool PairingRegistry::Pairing::operator==(const Pairing& other) const { 86 return created_time_ == other.created_time_ && 87 client_id_ == other.client_id_ && 88 client_name_ == other.client_name_ && 89 shared_secret_ == other.shared_secret_; 90 } 91 92 bool PairingRegistry::Pairing::is_valid() const { 93 return !client_id_.empty() && !shared_secret_.empty(); 94 } 95 96 PairingRegistry::PairingRegistry( 97 scoped_refptr<base::SingleThreadTaskRunner> delegate_task_runner, 98 scoped_ptr<Delegate> delegate) 99 : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), 100 delegate_task_runner_(delegate_task_runner), 101 delegate_(delegate.Pass()) { 102 DCHECK(delegate_); 103 } 104 105 PairingRegistry::Pairing PairingRegistry::CreatePairing( 106 const std::string& client_name) { 107 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 108 109 Pairing result = Pairing::Create(client_name); 110 AddPairing(result); 111 return result; 112 } 113 114 void PairingRegistry::GetPairing(const std::string& client_id, 115 const GetPairingCallback& callback) { 116 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 117 118 GetPairingCallback wrapped_callback = base::Bind( 119 &PairingRegistry::InvokeGetPairingCallbackAndScheduleNext, 120 this, callback); 121 base::Closure request = base::Bind( 122 &PairingRegistry::DoLoad, this, client_id, wrapped_callback); 123 ServiceOrQueueRequest(request); 124 } 125 126 void PairingRegistry::GetAllPairings( 127 const GetAllPairingsCallback& callback) { 128 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 129 130 GetAllPairingsCallback wrapped_callback = base::Bind( 131 &PairingRegistry::InvokeGetAllPairingsCallbackAndScheduleNext, 132 this, callback); 133 GetAllPairingsCallback sanitize_callback = base::Bind( 134 &PairingRegistry::SanitizePairings, 135 this, wrapped_callback); 136 base::Closure request = base::Bind( 137 &PairingRegistry::DoLoadAll, this, sanitize_callback); 138 ServiceOrQueueRequest(request); 139 } 140 141 void PairingRegistry::DeletePairing( 142 const std::string& client_id, const DoneCallback& callback) { 143 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 144 145 DoneCallback wrapped_callback = base::Bind( 146 &PairingRegistry::InvokeDoneCallbackAndScheduleNext, 147 this, callback); 148 base::Closure request = base::Bind( 149 &PairingRegistry::DoDelete, this, client_id, wrapped_callback); 150 ServiceOrQueueRequest(request); 151 } 152 153 void PairingRegistry::ClearAllPairings( 154 const DoneCallback& callback) { 155 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 156 157 DoneCallback wrapped_callback = base::Bind( 158 &PairingRegistry::InvokeDoneCallbackAndScheduleNext, 159 this, callback); 160 base::Closure request = base::Bind( 161 &PairingRegistry::DoDeleteAll, this, wrapped_callback); 162 ServiceOrQueueRequest(request); 163 } 164 165 PairingRegistry::~PairingRegistry() { 166 } 167 168 void PairingRegistry::PostTask( 169 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 170 const tracked_objects::Location& from_here, 171 const base::Closure& task) { 172 task_runner->PostTask(from_here, task); 173 } 174 175 void PairingRegistry::AddPairing(const Pairing& pairing) { 176 DoneCallback wrapped_callback = base::Bind( 177 &PairingRegistry::InvokeDoneCallbackAndScheduleNext, 178 this, DoneCallback()); 179 base::Closure request = base::Bind( 180 &PairingRegistry::DoSave, this, pairing, wrapped_callback); 181 ServiceOrQueueRequest(request); 182 } 183 184 void PairingRegistry::DoLoadAll( 185 const protocol::PairingRegistry::GetAllPairingsCallback& callback) { 186 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 187 188 scoped_ptr<base::ListValue> pairings = delegate_->LoadAll(); 189 PostTask(caller_task_runner_, FROM_HERE, base::Bind(callback, 190 base::Passed(&pairings))); 191 } 192 193 void PairingRegistry::DoDeleteAll( 194 const protocol::PairingRegistry::DoneCallback& callback) { 195 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 196 197 bool success = delegate_->DeleteAll(); 198 PostTask(caller_task_runner_, FROM_HERE, base::Bind(callback, success)); 199 } 200 201 void PairingRegistry::DoLoad( 202 const std::string& client_id, 203 const protocol::PairingRegistry::GetPairingCallback& callback) { 204 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 205 206 Pairing pairing = delegate_->Load(client_id); 207 PostTask(caller_task_runner_, FROM_HERE, base::Bind(callback, pairing)); 208 } 209 210 void PairingRegistry::DoSave( 211 const protocol::PairingRegistry::Pairing& pairing, 212 const protocol::PairingRegistry::DoneCallback& callback) { 213 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 214 215 bool success = delegate_->Save(pairing); 216 PostTask(caller_task_runner_, FROM_HERE, base::Bind(callback, success)); 217 } 218 219 void PairingRegistry::DoDelete( 220 const std::string& client_id, 221 const protocol::PairingRegistry::DoneCallback& callback) { 222 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 223 224 bool success = delegate_->Delete(client_id); 225 PostTask(caller_task_runner_, FROM_HERE, base::Bind(callback, success)); 226 } 227 228 void PairingRegistry::InvokeDoneCallbackAndScheduleNext( 229 const DoneCallback& callback, bool success) { 230 // CreatePairing doesn't have a callback, so the callback can be null. 231 if (!callback.is_null()) 232 callback.Run(success); 233 234 pending_requests_.pop(); 235 ServiceNextRequest(); 236 } 237 238 void PairingRegistry::InvokeGetPairingCallbackAndScheduleNext( 239 const GetPairingCallback& callback, Pairing pairing) { 240 callback.Run(pairing); 241 pending_requests_.pop(); 242 ServiceNextRequest(); 243 } 244 245 void PairingRegistry::InvokeGetAllPairingsCallbackAndScheduleNext( 246 const GetAllPairingsCallback& callback, 247 scoped_ptr<base::ListValue> pairings) { 248 callback.Run(pairings.Pass()); 249 pending_requests_.pop(); 250 ServiceNextRequest(); 251 } 252 253 void PairingRegistry::SanitizePairings(const GetAllPairingsCallback& callback, 254 scoped_ptr<base::ListValue> pairings) { 255 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 256 257 scoped_ptr<base::ListValue> sanitized_pairings(new base::ListValue()); 258 for (size_t i = 0; i < pairings->GetSize(); ++i) { 259 DictionaryValue* pairing_json; 260 if (!pairings->GetDictionary(i, &pairing_json)) { 261 LOG(WARNING) << "A pairing entry is not a dictionary."; 262 continue; 263 } 264 265 // Parse the pairing data. 266 Pairing pairing = Pairing::CreateFromValue(*pairing_json); 267 if (!pairing.is_valid()) { 268 LOG(WARNING) << "Could not parse a pairing entry."; 269 continue; 270 } 271 272 // Clear the shared secrect and append the pairing data to the list. 273 Pairing sanitized_pairing( 274 pairing.created_time(), 275 pairing.client_name(), 276 pairing.client_id(), 277 ""); 278 sanitized_pairings->Append(sanitized_pairing.ToValue().release()); 279 } 280 281 callback.Run(sanitized_pairings.Pass()); 282 } 283 284 void PairingRegistry::ServiceOrQueueRequest(const base::Closure& request) { 285 bool servicing_request = !pending_requests_.empty(); 286 pending_requests_.push(request); 287 if (!servicing_request) { 288 ServiceNextRequest(); 289 } 290 } 291 292 void PairingRegistry::ServiceNextRequest() { 293 if (pending_requests_.empty()) 294 return; 295 296 PostTask(delegate_task_runner_, FROM_HERE, pending_requests_.front()); 297 } 298 299 } // namespace protocol 300 } // namespace remoting 301