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