1 // Copyright 2014 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 "components/gcm_driver/fake_gcm_client.h"
6 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 
11 #include "base/bind.h"
12 #include "base/check.h"
13 #include "base/location.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/sys_byteorder.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/time/time.h"
20 #include "base/timer/timer.h"
21 #include "google_apis/gcm/base/encryptor.h"
22 #include "google_apis/gcm/engine/account_mapping.h"
23 #include "net/base/ip_endpoint.h"
24 
25 namespace gcm {
26 
27 // static
GenerateGCMRegistrationID(const std::vector<std::string> & sender_ids)28 std::string FakeGCMClient::GenerateGCMRegistrationID(
29     const std::vector<std::string>& sender_ids) {
30   // GCMService normalizes the sender IDs by making them sorted.
31   std::vector<std::string> normalized_sender_ids = sender_ids;
32   std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end());
33 
34   // Simulate the registration_id by concaternating all sender IDs.
35   // Set registration_id to empty to denote an error if sender_ids contains a
36   // hint.
37   std::string registration_id;
38   if (sender_ids.size() != 1 ||
39       sender_ids[0].find("error") == std::string::npos) {
40     for (size_t i = 0; i < normalized_sender_ids.size(); ++i) {
41       if (i > 0)
42         registration_id += ",";
43       registration_id += normalized_sender_ids[i];
44     }
45   }
46   return registration_id;
47 }
48 
49 // static
GenerateInstanceIDToken(const std::string & authorized_entity,const std::string & scope)50 std::string FakeGCMClient::GenerateInstanceIDToken(
51     const std::string& authorized_entity, const std::string& scope) {
52   if (authorized_entity.find("error") != std::string::npos)
53     return "";
54   std::string token(authorized_entity);
55   token += ",";
56   token += scope;
57   return token;
58 }
59 
FakeGCMClient(const scoped_refptr<base::SequencedTaskRunner> & ui_thread,const scoped_refptr<base::SequencedTaskRunner> & io_thread)60 FakeGCMClient::FakeGCMClient(
61     const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
62     const scoped_refptr<base::SequencedTaskRunner>& io_thread)
63     : delegate_(nullptr),
64       started_(false),
65       start_mode_(DELAYED_START),
66       start_mode_overridding_(RESPECT_START_MODE),
67       ui_thread_(ui_thread),
68       io_thread_(io_thread) {}
69 
~FakeGCMClient()70 FakeGCMClient::~FakeGCMClient() {
71 }
72 
Initialize(const ChromeBuildInfo & chrome_build_info,const base::FilePath & store_path,bool remove_account_mappings_with_email_key,const scoped_refptr<base::SequencedTaskRunner> & blocking_task_runner,scoped_refptr<base::SequencedTaskRunner> io_task_runner,base::RepeatingCallback<void (mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>)> get_socket_factory_callback,const scoped_refptr<network::SharedURLLoaderFactory> & url_loader_factory,network::NetworkConnectionTracker * network_connection_tracker,std::unique_ptr<Encryptor> encryptor,Delegate * delegate)73 void FakeGCMClient::Initialize(
74     const ChromeBuildInfo& chrome_build_info,
75     const base::FilePath& store_path,
76     bool remove_account_mappings_with_email_key,
77     const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
78     scoped_refptr<base::SequencedTaskRunner> io_task_runner,
79     base::RepeatingCallback<void(
80         mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>)>
81         get_socket_factory_callback,
82     const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory,
83     network::NetworkConnectionTracker* network_connection_tracker,
84     std::unique_ptr<Encryptor> encryptor,
85     Delegate* delegate) {
86   product_category_for_subtypes_ =
87       chrome_build_info.product_category_for_subtypes;
88   delegate_ = delegate;
89 }
90 
Start(StartMode start_mode)91 void FakeGCMClient::Start(StartMode start_mode) {
92   DCHECK(io_thread_->RunsTasksInCurrentSequence());
93 
94   if (started_)
95     return;
96 
97   if (start_mode == IMMEDIATE_START)
98     start_mode_ = IMMEDIATE_START;
99   if (start_mode_ == DELAYED_START ||
100       start_mode_overridding_ == FORCE_TO_ALWAYS_DELAY_START_GCM) {
101     return;
102   }
103 
104   DoStart();
105 }
106 
DoStart()107 void FakeGCMClient::DoStart() {
108   started_ = true;
109   base::ThreadTaskRunnerHandle::Get()->PostTask(
110       FROM_HERE,
111       base::BindOnce(&FakeGCMClient::Started, weak_ptr_factory_.GetWeakPtr()));
112 }
113 
Stop()114 void FakeGCMClient::Stop() {
115   DCHECK(io_thread_->RunsTasksInCurrentSequence());
116   started_ = false;
117   delegate_->OnDisconnected();
118 }
119 
Register(scoped_refptr<RegistrationInfo> registration_info)120 void FakeGCMClient::Register(
121     scoped_refptr<RegistrationInfo> registration_info) {
122   DCHECK(io_thread_->RunsTasksInCurrentSequence());
123 
124   std::string registration_id;
125 
126   GCMRegistrationInfo* gcm_registration_info =
127       GCMRegistrationInfo::FromRegistrationInfo(registration_info.get());
128   if (gcm_registration_info) {
129     registration_id = GenerateGCMRegistrationID(
130         gcm_registration_info->sender_ids);
131   }
132 
133   InstanceIDTokenInfo* instance_id_token_info =
134       InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get());
135   if (instance_id_token_info) {
136     registration_id = GenerateInstanceIDToken(
137         instance_id_token_info->authorized_entity,
138         instance_id_token_info->scope);
139   }
140 
141   base::ThreadTaskRunnerHandle::Get()->PostTask(
142       FROM_HERE, base::BindOnce(&FakeGCMClient::RegisterFinished,
143                                 weak_ptr_factory_.GetWeakPtr(),
144                                 std::move(registration_info), registration_id));
145 }
146 
ValidateRegistration(scoped_refptr<RegistrationInfo> registration_info,const std::string & registration_id)147 bool FakeGCMClient::ValidateRegistration(
148     scoped_refptr<RegistrationInfo> registration_info,
149     const std::string& registration_id) {
150   return true;
151 }
152 
Unregister(scoped_refptr<RegistrationInfo> registration_info)153 void FakeGCMClient::Unregister(
154     scoped_refptr<RegistrationInfo> registration_info) {
155   DCHECK(io_thread_->RunsTasksInCurrentSequence());
156 
157   base::ThreadTaskRunnerHandle::Get()->PostTask(
158       FROM_HERE,
159       base::BindOnce(&FakeGCMClient::UnregisterFinished,
160                      weak_ptr_factory_.GetWeakPtr(), registration_info));
161 }
162 
Send(const std::string & app_id,const std::string & receiver_id,const OutgoingMessage & message)163 void FakeGCMClient::Send(const std::string& app_id,
164                          const std::string& receiver_id,
165                          const OutgoingMessage& message) {
166   DCHECK(io_thread_->RunsTasksInCurrentSequence());
167 
168   base::ThreadTaskRunnerHandle::Get()->PostTask(
169       FROM_HERE,
170       base::BindOnce(&FakeGCMClient::SendFinished,
171                      weak_ptr_factory_.GetWeakPtr(), app_id, message));
172 }
173 
RecordDecryptionFailure(const std::string & app_id,GCMDecryptionResult result)174 void FakeGCMClient::RecordDecryptionFailure(const std::string& app_id,
175                                             GCMDecryptionResult result) {
176   recorder_.RecordDecryptionFailure(app_id, result);
177 }
178 
SetRecording(bool recording)179 void FakeGCMClient::SetRecording(bool recording) {
180   recorder_.set_is_recording(recording);
181 }
182 
ClearActivityLogs()183 void FakeGCMClient::ClearActivityLogs() {
184   recorder_.Clear();
185 }
186 
GetStatistics() const187 GCMClient::GCMStatistics FakeGCMClient::GetStatistics() const {
188   GCMClient::GCMStatistics statistics;
189   statistics.is_recording = recorder_.is_recording();
190 
191   recorder_.CollectActivities(&statistics.recorded_activities);
192   return statistics;
193 }
194 
SetAccountTokens(const std::vector<AccountTokenInfo> & account_tokens)195 void FakeGCMClient::SetAccountTokens(
196     const std::vector<AccountTokenInfo>& account_tokens) {
197 }
198 
UpdateAccountMapping(const AccountMapping & account_mapping)199 void FakeGCMClient::UpdateAccountMapping(
200     const AccountMapping& account_mapping) {
201 }
202 
RemoveAccountMapping(const CoreAccountId & account_id)203 void FakeGCMClient::RemoveAccountMapping(const CoreAccountId& account_id) {}
204 
SetLastTokenFetchTime(const base::Time & time)205 void FakeGCMClient::SetLastTokenFetchTime(const base::Time& time) {
206 }
207 
UpdateHeartbeatTimer(std::unique_ptr<base::RetainingOneShotTimer> timer)208 void FakeGCMClient::UpdateHeartbeatTimer(
209     std::unique_ptr<base::RetainingOneShotTimer> timer) {}
210 
AddInstanceIDData(const std::string & app_id,const std::string & instance_id,const std::string & extra_data)211 void FakeGCMClient::AddInstanceIDData(const std::string& app_id,
212                                       const std::string& instance_id,
213                                       const std::string& extra_data) {
214   instance_id_data_[app_id] = make_pair(instance_id, extra_data);
215 }
216 
RemoveInstanceIDData(const std::string & app_id)217 void FakeGCMClient::RemoveInstanceIDData(const std::string& app_id) {
218   instance_id_data_.erase(app_id);
219 }
220 
GetInstanceIDData(const std::string & app_id,std::string * instance_id,std::string * extra_data)221 void FakeGCMClient::GetInstanceIDData(const std::string& app_id,
222                                       std::string* instance_id,
223                                       std::string* extra_data) {
224   auto iter = instance_id_data_.find(app_id);
225   if (iter == instance_id_data_.end()) {
226     instance_id->clear();
227     extra_data->clear();
228     return;
229   }
230 
231   *instance_id = iter->second.first;
232   *extra_data = iter->second.second;
233 }
234 
AddHeartbeatInterval(const std::string & scope,int interval_ms)235 void FakeGCMClient::AddHeartbeatInterval(const std::string& scope,
236                                          int interval_ms) {
237 }
238 
RemoveHeartbeatInterval(const std::string & scope)239 void FakeGCMClient::RemoveHeartbeatInterval(const std::string& scope) {
240 }
241 
PerformDelayedStart()242 void FakeGCMClient::PerformDelayedStart() {
243   DCHECK(ui_thread_->RunsTasksInCurrentSequence());
244 
245   io_thread_->PostTask(
246       FROM_HERE,
247       base::BindOnce(&FakeGCMClient::DoStart, weak_ptr_factory_.GetWeakPtr()));
248 }
249 
ReceiveMessage(const std::string & app_id,const IncomingMessage & message)250 void FakeGCMClient::ReceiveMessage(const std::string& app_id,
251                                    const IncomingMessage& message) {
252   DCHECK(ui_thread_->RunsTasksInCurrentSequence());
253 
254   io_thread_->PostTask(
255       FROM_HERE,
256       base::BindOnce(&FakeGCMClient::MessageReceived,
257                      weak_ptr_factory_.GetWeakPtr(), app_id, message));
258 }
259 
DeleteMessages(const std::string & app_id)260 void FakeGCMClient::DeleteMessages(const std::string& app_id) {
261   DCHECK(ui_thread_->RunsTasksInCurrentSequence());
262 
263   io_thread_->PostTask(FROM_HERE,
264                        base::BindOnce(&FakeGCMClient::MessagesDeleted,
265                                       weak_ptr_factory_.GetWeakPtr(), app_id));
266 }
267 
Started()268 void FakeGCMClient::Started() {
269   delegate_->OnGCMReady(std::vector<AccountMapping>(), base::Time());
270   delegate_->OnConnected(net::IPEndPoint());
271 }
272 
RegisterFinished(scoped_refptr<RegistrationInfo> registration_info,const std::string & registrion_id)273 void FakeGCMClient::RegisterFinished(
274     scoped_refptr<RegistrationInfo> registration_info,
275     const std::string& registrion_id) {
276   delegate_->OnRegisterFinished(std::move(registration_info), registrion_id,
277                                 registrion_id.empty() ? SERVER_ERROR : SUCCESS);
278 }
279 
UnregisterFinished(scoped_refptr<RegistrationInfo> registration_info)280 void FakeGCMClient::UnregisterFinished(
281     scoped_refptr<RegistrationInfo> registration_info) {
282   delegate_->OnUnregisterFinished(std::move(registration_info),
283                                   GCMClient::SUCCESS);
284 }
285 
SendFinished(const std::string & app_id,const OutgoingMessage & message)286 void FakeGCMClient::SendFinished(const std::string& app_id,
287                                  const OutgoingMessage& message) {
288   delegate_->OnSendFinished(app_id, message.id, SUCCESS);
289 
290   // Simulate send error if message id contains a hint.
291   if (message.id.find("error") != std::string::npos) {
292     SendErrorDetails send_error_details;
293     send_error_details.message_id = message.id;
294     send_error_details.result = NETWORK_ERROR;
295     send_error_details.additional_data = message.data;
296     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
297         FROM_HERE,
298         base::BindOnce(&FakeGCMClient::MessageSendError,
299                        weak_ptr_factory_.GetWeakPtr(), app_id,
300                        send_error_details),
301         base::TimeDelta::FromMilliseconds(200));
302   } else if(message.id.find("ack") != std::string::npos) {
303     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
304         FROM_HERE,
305         base::BindOnce(&FakeGCMClient::SendAcknowledgement,
306                        weak_ptr_factory_.GetWeakPtr(), app_id, message.id),
307         base::TimeDelta::FromMilliseconds(200));
308   }
309 }
310 
MessageReceived(const std::string & app_id,const IncomingMessage & message)311 void FakeGCMClient::MessageReceived(const std::string& app_id,
312                                     const IncomingMessage& message) {
313   if (delegate_)
314     delegate_->OnMessageReceived(app_id, message);
315 }
316 
MessagesDeleted(const std::string & app_id)317 void FakeGCMClient::MessagesDeleted(const std::string& app_id) {
318   if (delegate_)
319     delegate_->OnMessagesDeleted(app_id);
320 }
321 
MessageSendError(const std::string & app_id,const GCMClient::SendErrorDetails & send_error_details)322 void FakeGCMClient::MessageSendError(
323     const std::string& app_id,
324     const GCMClient::SendErrorDetails& send_error_details) {
325   if (delegate_)
326     delegate_->OnMessageSendError(app_id, send_error_details);
327 }
328 
SendAcknowledgement(const std::string & app_id,const std::string & message_id)329 void FakeGCMClient::SendAcknowledgement(const std::string& app_id,
330                                         const std::string& message_id) {
331   if (delegate_)
332     delegate_->OnSendAcknowledged(app_id, message_id);
333 }
334 
335 }  // namespace gcm
336