pairing_registry.cc 10 KB

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