DCHECK that ProfileSyncService is created on the UI thread.
[chromium-blink-merge.git] / remoting / protocol / pairing_registry.cc
blobedf085cd090ad331d3465fe135aa366f881cab74
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.
5 #include "remoting/protocol/pairing_registry.h"
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"
18 namespace remoting {
19 namespace protocol {
21 // How many bytes of random data to use for the shared secret.
22 const int kKeySize = 16;
24 const char PairingRegistry::kCreatedTimeKey[] = "createdTime";
25 const char PairingRegistry::kClientIdKey[] = "clientId";
26 const char PairingRegistry::kClientNameKey[] = "clientName";
27 const char PairingRegistry::kSharedSecretKey[] = "sharedSecret";
29 PairingRegistry::Pairing::Pairing() {
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) {
42 PairingRegistry::Pairing::~Pairing() {
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);
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);
71 LOG(ERROR) << "Failed to load pairing information: unexpected format.";
72 return Pairing();
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();
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_;
92 bool PairingRegistry::Pairing::is_valid() const {
93 // |shared_secret_| is optional. It will be empty on Windows because the
94 // privileged registry key can only be read in the elevated host process.
95 return !client_id_.empty();
98 PairingRegistry::PairingRegistry(
99 scoped_refptr<base::SingleThreadTaskRunner> delegate_task_runner,
100 scoped_ptr<Delegate> delegate)
101 : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()),
102 delegate_task_runner_(delegate_task_runner),
103 delegate_(delegate.Pass()) {
104 DCHECK(delegate_);
107 PairingRegistry::Pairing PairingRegistry::CreatePairing(
108 const std::string& client_name) {
109 DCHECK(caller_task_runner_->BelongsToCurrentThread());
111 Pairing result = Pairing::Create(client_name);
112 AddPairing(result);
113 return result;
116 void PairingRegistry::GetPairing(const std::string& client_id,
117 const GetPairingCallback& callback) {
118 DCHECK(caller_task_runner_->BelongsToCurrentThread());
120 GetPairingCallback wrapped_callback = base::Bind(
121 &PairingRegistry::InvokeGetPairingCallbackAndScheduleNext,
122 this, callback);
123 base::Closure request = base::Bind(
124 &PairingRegistry::DoLoad, this, client_id, wrapped_callback);
125 ServiceOrQueueRequest(request);
128 void PairingRegistry::GetAllPairings(
129 const GetAllPairingsCallback& callback) {
130 DCHECK(caller_task_runner_->BelongsToCurrentThread());
132 GetAllPairingsCallback wrapped_callback = base::Bind(
133 &PairingRegistry::InvokeGetAllPairingsCallbackAndScheduleNext,
134 this, callback);
135 GetAllPairingsCallback sanitize_callback = base::Bind(
136 &PairingRegistry::SanitizePairings,
137 this, wrapped_callback);
138 base::Closure request = base::Bind(
139 &PairingRegistry::DoLoadAll, this, sanitize_callback);
140 ServiceOrQueueRequest(request);
143 void PairingRegistry::DeletePairing(
144 const std::string& client_id, const DoneCallback& callback) {
145 DCHECK(caller_task_runner_->BelongsToCurrentThread());
147 DoneCallback wrapped_callback = base::Bind(
148 &PairingRegistry::InvokeDoneCallbackAndScheduleNext,
149 this, callback);
150 base::Closure request = base::Bind(
151 &PairingRegistry::DoDelete, this, client_id, wrapped_callback);
152 ServiceOrQueueRequest(request);
155 void PairingRegistry::ClearAllPairings(
156 const DoneCallback& callback) {
157 DCHECK(caller_task_runner_->BelongsToCurrentThread());
159 DoneCallback wrapped_callback = base::Bind(
160 &PairingRegistry::InvokeDoneCallbackAndScheduleNext,
161 this, callback);
162 base::Closure request = base::Bind(
163 &PairingRegistry::DoDeleteAll, this, wrapped_callback);
164 ServiceOrQueueRequest(request);
167 PairingRegistry::~PairingRegistry() {
170 void PairingRegistry::PostTask(
171 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
172 const tracked_objects::Location& from_here,
173 const base::Closure& task) {
174 task_runner->PostTask(from_here, task);
177 void PairingRegistry::AddPairing(const Pairing& pairing) {
178 DoneCallback wrapped_callback = base::Bind(
179 &PairingRegistry::InvokeDoneCallbackAndScheduleNext,
180 this, DoneCallback());
181 base::Closure request = base::Bind(
182 &PairingRegistry::DoSave, this, pairing, wrapped_callback);
183 ServiceOrQueueRequest(request);
186 void PairingRegistry::DoLoadAll(
187 const protocol::PairingRegistry::GetAllPairingsCallback& callback) {
188 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
190 scoped_ptr<base::ListValue> pairings = delegate_->LoadAll();
191 PostTask(caller_task_runner_, FROM_HERE, base::Bind(callback,
192 base::Passed(&pairings)));
195 void PairingRegistry::DoDeleteAll(
196 const protocol::PairingRegistry::DoneCallback& callback) {
197 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
199 bool success = delegate_->DeleteAll();
200 PostTask(caller_task_runner_, FROM_HERE, base::Bind(callback, success));
203 void PairingRegistry::DoLoad(
204 const std::string& client_id,
205 const protocol::PairingRegistry::GetPairingCallback& callback) {
206 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
208 Pairing pairing = delegate_->Load(client_id);
209 PostTask(caller_task_runner_, FROM_HERE, base::Bind(callback, pairing));
212 void PairingRegistry::DoSave(
213 const protocol::PairingRegistry::Pairing& pairing,
214 const protocol::PairingRegistry::DoneCallback& callback) {
215 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
217 bool success = delegate_->Save(pairing);
218 PostTask(caller_task_runner_, FROM_HERE, base::Bind(callback, success));
221 void PairingRegistry::DoDelete(
222 const std::string& client_id,
223 const protocol::PairingRegistry::DoneCallback& callback) {
224 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
226 bool success = delegate_->Delete(client_id);
227 PostTask(caller_task_runner_, FROM_HERE, base::Bind(callback, success));
230 void PairingRegistry::InvokeDoneCallbackAndScheduleNext(
231 const DoneCallback& callback, bool success) {
232 // CreatePairing doesn't have a callback, so the callback can be null.
233 if (!callback.is_null())
234 callback.Run(success);
236 pending_requests_.pop();
237 ServiceNextRequest();
240 void PairingRegistry::InvokeGetPairingCallbackAndScheduleNext(
241 const GetPairingCallback& callback, Pairing pairing) {
242 callback.Run(pairing);
243 pending_requests_.pop();
244 ServiceNextRequest();
247 void PairingRegistry::InvokeGetAllPairingsCallbackAndScheduleNext(
248 const GetAllPairingsCallback& callback,
249 scoped_ptr<base::ListValue> pairings) {
250 callback.Run(pairings.Pass());
251 pending_requests_.pop();
252 ServiceNextRequest();
255 void PairingRegistry::SanitizePairings(const GetAllPairingsCallback& callback,
256 scoped_ptr<base::ListValue> pairings) {
257 DCHECK(caller_task_runner_->BelongsToCurrentThread());
259 scoped_ptr<base::ListValue> sanitized_pairings(new base::ListValue());
260 for (size_t i = 0; i < pairings->GetSize(); ++i) {
261 base::DictionaryValue* pairing_json;
262 if (!pairings->GetDictionary(i, &pairing_json)) {
263 LOG(WARNING) << "A pairing entry is not a dictionary.";
264 continue;
267 // Parse the pairing data.
268 Pairing pairing = Pairing::CreateFromValue(*pairing_json);
269 if (!pairing.is_valid()) {
270 LOG(WARNING) << "Could not parse a pairing entry.";
271 continue;
274 // Clear the shared secrect and append the pairing data to the list.
275 Pairing sanitized_pairing(
276 pairing.created_time(),
277 pairing.client_name(),
278 pairing.client_id(),
279 "");
280 sanitized_pairings->Append(sanitized_pairing.ToValue().release());
283 callback.Run(sanitized_pairings.Pass());
286 void PairingRegistry::ServiceOrQueueRequest(const base::Closure& request) {
287 bool servicing_request = !pending_requests_.empty();
288 pending_requests_.push(request);
289 if (!servicing_request) {
290 ServiceNextRequest();
294 void PairingRegistry::ServiceNextRequest() {
295 if (pending_requests_.empty())
296 return;
298 PostTask(delegate_task_runner_, FROM_HERE, pending_requests_.front());
301 } // namespace protocol
302 } // namespace remoting