OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/protocol/pairing_registry.h" | 5 #include "remoting/protocol/pairing_registry.h" |
6 | 6 |
7 #include "base/base64.h" | 7 #include "base/base64.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/guid.h" | 9 #include "base/guid.h" |
10 #include "base/json/json_string_value_serializer.h" | 10 #include "base/json/json_string_value_serializer.h" |
(...skipping 18 matching lines...) Expand all Loading... |
29 PairingRegistry::Pairing::Pairing(const base::Time& created_time, | 29 PairingRegistry::Pairing::Pairing(const base::Time& created_time, |
30 const std::string& client_name, | 30 const std::string& client_name, |
31 const std::string& client_id, | 31 const std::string& client_id, |
32 const std::string& shared_secret) | 32 const std::string& shared_secret) |
33 : created_time_(created_time), | 33 : created_time_(created_time), |
34 client_name_(client_name), | 34 client_name_(client_name), |
35 client_id_(client_id), | 35 client_id_(client_id), |
36 shared_secret_(shared_secret) { | 36 shared_secret_(shared_secret) { |
37 } | 37 } |
38 | 38 |
| 39 PairingRegistry::Pairing::~Pairing() { |
| 40 } |
| 41 |
39 PairingRegistry::Pairing PairingRegistry::Pairing::Create( | 42 PairingRegistry::Pairing PairingRegistry::Pairing::Create( |
40 const std::string& client_name) { | 43 const std::string& client_name) { |
41 base::Time created_time = base::Time::Now(); | 44 base::Time created_time = base::Time::Now(); |
42 std::string client_id = base::GenerateGUID(); | 45 std::string client_id = base::GenerateGUID(); |
43 std::string shared_secret; | 46 std::string shared_secret; |
44 char buffer[kKeySize]; | 47 char buffer[kKeySize]; |
45 crypto::RandBytes(buffer, arraysize(buffer)); | 48 crypto::RandBytes(buffer, arraysize(buffer)); |
46 if (!base::Base64Encode(base::StringPiece(buffer, arraysize(buffer)), | 49 if (!base::Base64Encode(base::StringPiece(buffer, arraysize(buffer)), |
47 &shared_secret)) { | 50 &shared_secret)) { |
48 LOG(FATAL) << "Base64Encode failed."; | 51 LOG(FATAL) << "Base64Encode failed."; |
49 } | 52 } |
50 return Pairing(created_time, client_name, client_id, shared_secret); | 53 return Pairing(created_time, client_name, client_id, shared_secret); |
51 } | 54 } |
52 | 55 |
53 PairingRegistry::Pairing::~Pairing() { | 56 PairingRegistry::Pairing PairingRegistry::Pairing::CreateFromJson( |
| 57 const base::Value& pairing_json) { |
| 58 const base::DictionaryValue* pairing = NULL; |
| 59 if (!pairing_json.GetAsDictionary(&pairing)) { |
| 60 LOG(ERROR) << "Failed to load pairing information: not a dictionary."; |
| 61 return Pairing(); |
| 62 } |
| 63 |
| 64 std::string client_name, client_id, shared_secret; |
| 65 double created_time_value; |
| 66 if (pairing->GetDouble(kCreatedTimeKey, &created_time_value) && |
| 67 pairing->GetString(kClientNameKey, &client_name) && |
| 68 pairing->GetString(kClientIdKey, &client_id) && |
| 69 pairing->GetString(kSharedSecretKey, &shared_secret)) { |
| 70 base::Time created_time = base::Time::FromJsTime(created_time_value); |
| 71 return Pairing(created_time, client_name, client_id, shared_secret); |
| 72 } |
| 73 |
| 74 LOG(ERROR) << "Failed to load pairing information: unexpected format."; |
| 75 return Pairing(); |
| 76 } |
| 77 |
| 78 scoped_ptr<base::Value> PairingRegistry::Pairing::EncodeJson() const { |
| 79 scoped_ptr<base::DictionaryValue> pairing(new base::DictionaryValue()); |
| 80 pairing->SetDouble(kCreatedTimeKey, created_time().ToJsTime()); |
| 81 pairing->SetString(kClientNameKey, client_name()); |
| 82 pairing->SetString(kClientIdKey, client_id()); |
| 83 if (!shared_secret().empty()) |
| 84 pairing->SetString(kSharedSecretKey, shared_secret()); |
| 85 return pairing.PassAs<base::Value>(); |
54 } | 86 } |
55 | 87 |
56 bool PairingRegistry::Pairing::operator==(const Pairing& other) const { | 88 bool PairingRegistry::Pairing::operator==(const Pairing& other) const { |
57 return created_time_ == other.created_time_ && | 89 return created_time_ == other.created_time_ && |
58 client_id_ == other.client_id_ && | 90 client_id_ == other.client_id_ && |
59 client_name_ == other.client_name_ && | 91 client_name_ == other.client_name_ && |
60 shared_secret_ == other.shared_secret_; | 92 shared_secret_ == other.shared_secret_; |
61 } | 93 } |
62 | 94 |
63 bool PairingRegistry::Pairing::is_valid() const { | 95 bool PairingRegistry::Pairing::is_valid() const { |
(...skipping 15 matching lines...) Expand all Loading... |
79 AddPairing(result); | 111 AddPairing(result); |
80 return result; | 112 return result; |
81 } | 113 } |
82 | 114 |
83 void PairingRegistry::GetPairing(const std::string& client_id, | 115 void PairingRegistry::GetPairing(const std::string& client_id, |
84 const GetPairingCallback& callback) { | 116 const GetPairingCallback& callback) { |
85 DCHECK(CalledOnValidThread()); | 117 DCHECK(CalledOnValidThread()); |
86 GetPairingCallback wrapped_callback = base::Bind( | 118 GetPairingCallback wrapped_callback = base::Bind( |
87 &PairingRegistry::InvokeGetPairingCallbackAndScheduleNext, | 119 &PairingRegistry::InvokeGetPairingCallbackAndScheduleNext, |
88 this, callback); | 120 this, callback); |
89 LoadCallback load_callback = base::Bind( | |
90 &PairingRegistry::DoGetPairing, this, client_id, wrapped_callback); | |
91 // |Unretained| and |get| are both safe here because the delegate is owned | 121 // |Unretained| and |get| are both safe here because the delegate is owned |
92 // by the pairing registry and so is guaranteed to exist when the request | 122 // by the pairing registry and so is guaranteed to exist when the request |
93 // is serviced. | 123 // is serviced. |
94 base::Closure request = base::Bind( | 124 base::Closure request = base::Bind( |
95 &PairingRegistry::Delegate::Load, | 125 &PairingRegistry::Delegate::Load, |
96 base::Unretained(delegate_.get()), load_callback); | 126 base::Unretained(delegate_.get()), client_id, wrapped_callback); |
97 ServiceOrQueueRequest(request); | 127 ServiceOrQueueRequest(request); |
98 } | 128 } |
99 | 129 |
100 void PairingRegistry::GetAllPairings( | 130 void PairingRegistry::GetAllPairings( |
101 const GetAllPairingsCallback& callback) { | 131 const GetAllPairingsCallback& callback) { |
102 DCHECK(CalledOnValidThread()); | 132 DCHECK(CalledOnValidThread()); |
103 GetAllPairingsCallback wrapped_callback = base::Bind( | 133 GetAllPairingsCallback wrapped_callback = base::Bind( |
104 &PairingRegistry::InvokeGetAllPairingsCallbackAndScheduleNext, | 134 &PairingRegistry::InvokeGetAllPairingsCallbackAndScheduleNext, |
105 this, callback); | 135 this, callback); |
106 LoadCallback load_callback = base::Bind( | |
107 &PairingRegistry::SanitizePairings, this, wrapped_callback); | |
108 base::Closure request = base::Bind( | 136 base::Closure request = base::Bind( |
109 &PairingRegistry::Delegate::Load, | 137 &PairingRegistry::Delegate::LoadAll, |
110 base::Unretained(delegate_.get()), load_callback); | 138 base::Unretained(delegate_.get()), wrapped_callback); |
111 ServiceOrQueueRequest(request); | 139 ServiceOrQueueRequest(request); |
112 } | 140 } |
113 | 141 |
114 void PairingRegistry::DeletePairing( | 142 void PairingRegistry::DeletePairing( |
115 const std::string& client_id, const SaveCallback& callback) { | 143 const std::string& client_id, const DoneCallback& callback) { |
116 DCHECK(CalledOnValidThread()); | 144 DCHECK(CalledOnValidThread()); |
117 SaveCallback wrapped_callback = base::Bind( | 145 DoneCallback wrapped_callback = base::Bind( |
118 &PairingRegistry::InvokeSaveCallbackAndScheduleNext, | 146 &PairingRegistry::InvokeDoneCallbackAndScheduleNext, |
119 this, callback); | 147 this, callback); |
120 LoadCallback load_callback = base::Bind( | |
121 &PairingRegistry::DoDeletePairing, this, client_id, wrapped_callback); | |
122 base::Closure request = base::Bind( | 148 base::Closure request = base::Bind( |
123 &PairingRegistry::Delegate::Load, | 149 &PairingRegistry::Delegate::Delete, |
124 base::Unretained(delegate_.get()), load_callback); | 150 base::Unretained(delegate_.get()), client_id, wrapped_callback); |
125 ServiceOrQueueRequest(request); | 151 ServiceOrQueueRequest(request); |
126 } | 152 } |
127 | 153 |
128 void PairingRegistry::ClearAllPairings( | 154 void PairingRegistry::ClearAllPairings( |
129 const SaveCallback& callback) { | 155 const DoneCallback& callback) { |
130 DCHECK(CalledOnValidThread()); | 156 DCHECK(CalledOnValidThread()); |
131 SaveCallback wrapped_callback = base::Bind( | 157 DoneCallback wrapped_callback = base::Bind( |
132 &PairingRegistry::InvokeSaveCallbackAndScheduleNext, | 158 &PairingRegistry::InvokeDoneCallbackAndScheduleNext, |
133 this, callback); | 159 this, callback); |
134 base::Closure request = base::Bind( | 160 base::Closure request = base::Bind( |
135 &PairingRegistry::Delegate::Save, | 161 &PairingRegistry::Delegate::DeleteAll, |
136 base::Unretained(delegate_.get()), | 162 base::Unretained(delegate_.get()), wrapped_callback); |
137 EncodeJson(PairedClients()), | |
138 wrapped_callback); | |
139 ServiceOrQueueRequest(request); | 163 ServiceOrQueueRequest(request); |
140 } | 164 } |
141 | 165 |
142 void PairingRegistry::AddPairing(const Pairing& pairing) { | 166 void PairingRegistry::AddPairing(const Pairing& pairing) { |
143 SaveCallback callback = base::Bind( | 167 DoneCallback wrapped_callback = base::Bind( |
144 &PairingRegistry::InvokeSaveCallbackAndScheduleNext, | 168 &PairingRegistry::InvokeDoneCallbackAndScheduleNext, |
145 this, SaveCallback()); | 169 this, DoneCallback()); |
146 LoadCallback load_callback = base::Bind( | |
147 &PairingRegistry::MergePairingAndSave, this, pairing, callback); | |
148 base::Closure request = base::Bind( | 170 base::Closure request = base::Bind( |
149 &PairingRegistry::Delegate::Load, | 171 &PairingRegistry::Delegate::Save, |
150 base::Unretained(delegate_.get()), load_callback); | 172 base::Unretained(delegate_.get()), pairing, wrapped_callback); |
151 ServiceOrQueueRequest(request); | 173 ServiceOrQueueRequest(request); |
152 } | 174 } |
153 | 175 |
154 void PairingRegistry::MergePairingAndSave(const Pairing& pairing, | 176 void PairingRegistry::InvokeDoneCallbackAndScheduleNext( |
155 const SaveCallback& callback, | 177 const DoneCallback& callback, bool success) { |
156 const std::string& pairings_json) { | 178 // CreatePairing doesn't have a callback, so the callback can be null. |
157 DCHECK(CalledOnValidThread()); | 179 if (!callback.is_null()) |
158 PairedClients clients = DecodeJson(pairings_json); | 180 callback.Run(success); |
159 clients[pairing.client_id()] = pairing; | |
160 std::string new_pairings_json = EncodeJson(clients); | |
161 delegate_->Save(new_pairings_json, callback); | |
162 } | |
163 | 181 |
164 void PairingRegistry::DoGetPairing(const std::string& client_id, | |
165 const GetPairingCallback& callback, | |
166 const std::string& pairings_json) { | |
167 PairedClients clients = DecodeJson(pairings_json); | |
168 Pairing result = clients[client_id]; | |
169 callback.Run(result); | |
170 } | |
171 | |
172 void PairingRegistry::SanitizePairings(const GetAllPairingsCallback& callback, | |
173 const std::string& pairings_json) { | |
174 PairedClients clients = DecodeJson(pairings_json); | |
175 callback.Run(ConvertToListValue(clients, false)); | |
176 } | |
177 | |
178 void PairingRegistry::DoDeletePairing(const std::string& client_id, | |
179 const SaveCallback& callback, | |
180 const std::string& pairings_json) { | |
181 PairedClients clients = DecodeJson(pairings_json); | |
182 clients.erase(client_id); | |
183 std::string new_pairings_json = EncodeJson(clients); | |
184 delegate_->Save(new_pairings_json, callback); | |
185 } | |
186 | |
187 void PairingRegistry::InvokeLoadCallbackAndScheduleNext( | |
188 const LoadCallback& callback, const std::string& pairings_json) { | |
189 callback.Run(pairings_json); | |
190 pending_requests_.pop(); | 182 pending_requests_.pop(); |
191 ServiceNextRequest(); | 183 ServiceNextRequest(); |
192 } | 184 } |
193 | |
194 void PairingRegistry::InvokeSaveCallbackAndScheduleNext( | |
195 const SaveCallback& callback, bool success) { | |
196 // CreatePairing doesn't have a callback, so the callback can be null. | |
197 if (!callback.is_null()) { | |
198 callback.Run(success); | |
199 } | |
200 pending_requests_.pop(); | |
201 ServiceNextRequest(); | |
202 } | |
203 | 185 |
204 void PairingRegistry::InvokeGetPairingCallbackAndScheduleNext( | 186 void PairingRegistry::InvokeGetPairingCallbackAndScheduleNext( |
205 const GetPairingCallback& callback, Pairing pairing) { | 187 const GetPairingCallback& callback, Pairing pairing) { |
206 callback.Run(pairing); | 188 callback.Run(pairing); |
207 pending_requests_.pop(); | 189 pending_requests_.pop(); |
208 ServiceNextRequest(); | 190 ServiceNextRequest(); |
209 } | 191 } |
210 | 192 |
211 void PairingRegistry::InvokeGetAllPairingsCallbackAndScheduleNext( | 193 void PairingRegistry::InvokeGetAllPairingsCallbackAndScheduleNext( |
212 const GetAllPairingsCallback& callback, | 194 const GetAllPairingsCallback& callback, |
213 scoped_ptr<base::ListValue> pairings) { | 195 scoped_ptr<base::ListValue> pairings) { |
214 callback.Run(pairings.Pass()); | 196 callback.Run(pairings.Pass()); |
215 pending_requests_.pop(); | 197 pending_requests_.pop(); |
216 ServiceNextRequest(); | 198 ServiceNextRequest(); |
217 } | 199 } |
218 | 200 |
219 // static | |
220 PairingRegistry::PairedClients PairingRegistry::DecodeJson( | |
221 const std::string& pairings_json) { | |
222 PairedClients result; | |
223 | |
224 if (pairings_json.empty()) { | |
225 return result; | |
226 } | |
227 | |
228 JSONStringValueSerializer registry(pairings_json); | |
229 int error_code; | |
230 std::string error_message; | |
231 scoped_ptr<base::Value> root( | |
232 registry.Deserialize(&error_code, &error_message)); | |
233 if (!root) { | |
234 LOG(ERROR) << "Failed to load paired clients: " << error_message | |
235 << " (" << error_code << ")."; | |
236 return result; | |
237 } | |
238 | |
239 base::ListValue* root_list = NULL; | |
240 if (!root->GetAsList(&root_list)) { | |
241 LOG(ERROR) << "Failed to load paired clients: root node is not a list."; | |
242 return result; | |
243 } | |
244 | |
245 for (size_t i = 0; i < root_list->GetSize(); ++i) { | |
246 base::DictionaryValue* pairing = NULL; | |
247 std::string client_name, client_id, shared_secret; | |
248 double created_time_value; | |
249 if (root_list->GetDictionary(i, &pairing) && | |
250 pairing->GetDouble(kCreatedTimeKey, &created_time_value) && | |
251 pairing->GetString(kClientNameKey, &client_name) && | |
252 pairing->GetString(kClientIdKey, &client_id) && | |
253 pairing->GetString(kSharedSecretKey, &shared_secret)) { | |
254 base::Time created_time = base::Time::FromJsTime(created_time_value); | |
255 result[client_id] = Pairing( | |
256 created_time, client_name, client_id, shared_secret); | |
257 } else { | |
258 LOG(ERROR) << "Paired client " << i << " has unexpected format."; | |
259 } | |
260 } | |
261 | |
262 return result; | |
263 } | |
264 | |
265 void PairingRegistry::ServiceOrQueueRequest(const base::Closure& request) { | 201 void PairingRegistry::ServiceOrQueueRequest(const base::Closure& request) { |
266 bool servicing_request = !pending_requests_.empty(); | 202 bool servicing_request = !pending_requests_.empty(); |
267 pending_requests_.push(request); | 203 pending_requests_.push(request); |
268 if (!servicing_request) { | 204 if (!servicing_request) { |
269 ServiceNextRequest(); | 205 ServiceNextRequest(); |
270 } | 206 } |
271 } | 207 } |
272 | 208 |
273 void PairingRegistry::ServiceNextRequest() { | 209 void PairingRegistry::ServiceNextRequest() { |
274 if (pending_requests_.empty()) { | 210 if (pending_requests_.empty()) |
275 return; | 211 return; |
276 } | 212 |
277 base::Closure request = pending_requests_.front(); | 213 base::Closure request = pending_requests_.front(); |
278 request.Run(); | 214 request.Run(); |
279 } | 215 } |
280 | 216 |
281 // static | |
282 std::string PairingRegistry::EncodeJson(const PairedClients& clients) { | |
283 scoped_ptr<base::ListValue> root = ConvertToListValue(clients, true); | |
284 std::string result; | |
285 JSONStringValueSerializer serializer(&result); | |
286 serializer.Serialize(*root); | |
287 | |
288 return result; | |
289 } | |
290 | |
291 // static | |
292 scoped_ptr<base::ListValue> PairingRegistry::ConvertToListValue( | |
293 const PairedClients& clients, | |
294 bool include_shared_secrets) { | |
295 scoped_ptr<base::ListValue> root(new base::ListValue()); | |
296 for (PairedClients::const_iterator i = clients.begin(); | |
297 i != clients.end(); ++i) { | |
298 base::DictionaryValue* pairing = new base::DictionaryValue(); | |
299 pairing->SetDouble(kCreatedTimeKey, i->second.created_time().ToJsTime()); | |
300 pairing->SetString(kClientNameKey, i->second.client_name()); | |
301 pairing->SetString(kClientIdKey, i->second.client_id()); | |
302 if (include_shared_secrets) { | |
303 pairing->SetString(kSharedSecretKey, i->second.shared_secret()); | |
304 } | |
305 root->Append(pairing); | |
306 } | |
307 return root.Pass(); | |
308 } | |
309 | |
310 } // namespace protocol | 217 } // namespace protocol |
311 } // namespace remoting | 218 } // namespace remoting |
OLD | NEW |