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/gcm_driver.h"
6 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 
11 #include "base/bind.h"
12 #include "base/files/file_path.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "components/gcm_driver/crypto/gcm_decryption_result.h"
16 #include "components/gcm_driver/crypto/gcm_encryption_result.h"
17 #include "components/gcm_driver/gcm_app_handler.h"
18 
19 namespace gcm {
20 
21 InstanceIDHandler::InstanceIDHandler() = default;
22 
23 InstanceIDHandler::~InstanceIDHandler() = default;
24 
DeleteAllTokensForApp(const std::string & app_id,DeleteTokenCallback callback)25 void InstanceIDHandler::DeleteAllTokensForApp(const std::string& app_id,
26                                               DeleteTokenCallback callback) {
27   DeleteToken(app_id, "*", "*", std::move(callback));
28 }
29 
GCMDriver(const base::FilePath & store_path,const scoped_refptr<base::SequencedTaskRunner> & blocking_task_runner)30 GCMDriver::GCMDriver(
31     const base::FilePath& store_path,
32     const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner) {
33   // The |blocking_task_runner| can be nullptr for tests that do not need the
34   // encryption capabilities of the GCMDriver class.
35   if (blocking_task_runner)
36     encryption_provider_.Init(store_path, blocking_task_runner);
37 }
38 
39 GCMDriver::~GCMDriver() = default;
40 
Register(const std::string & app_id,const std::vector<std::string> & sender_ids,RegisterCallback callback)41 void GCMDriver::Register(const std::string& app_id,
42                          const std::vector<std::string>& sender_ids,
43                          RegisterCallback callback) {
44   DCHECK(!app_id.empty());
45   DCHECK(!sender_ids.empty() && sender_ids.size() <= kMaxSenders);
46   DCHECK(!callback.is_null());
47 
48   GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
49   if (result != GCMClient::SUCCESS) {
50     std::move(callback).Run(std::string(), result);
51     return;
52   }
53 
54   // If previous register operation is still in progress, bail out.
55   if (register_callbacks_.find(app_id) != register_callbacks_.end()) {
56     std::move(callback).Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING);
57     return;
58   }
59 
60   // Normalize the sender IDs by making them sorted.
61   std::vector<std::string> normalized_sender_ids = sender_ids;
62   std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end());
63 
64   register_callbacks_[app_id] = std::move(callback);
65 
66   // If previous unregister operation is still in progress, wait until it
67   // finishes. We don't want to throw ASYNC_OPERATION_PENDING when the user
68   // uninstalls an app (ungistering) and then reinstalls the app again
69   // (registering).
70   auto unregister_iter = unregister_callbacks_.find(app_id);
71   if (unregister_iter != unregister_callbacks_.end()) {
72     // Replace the original unregister callback with an intermediate callback
73     // that will invoke the original unregister callback and trigger the pending
74     // registration after the unregistration finishes.
75     // Note that some parameters to RegisterAfterUnregister are specified here
76     // when the callback is created (base::Bind supports the partial binding
77     // of parameters).
78     unregister_iter->second = base::BindOnce(
79         &GCMDriver::RegisterAfterUnregister, weak_ptr_factory_.GetWeakPtr(),
80         app_id, normalized_sender_ids, std::move(unregister_iter->second));
81     return;
82   }
83 
84   RegisterImpl(app_id, normalized_sender_ids);
85 }
86 
Unregister(const std::string & app_id,UnregisterCallback callback)87 void GCMDriver::Unregister(const std::string& app_id,
88                            UnregisterCallback callback) {
89   UnregisterInternal(app_id, nullptr /* sender_id */, std::move(callback));
90 }
91 
UnregisterWithSenderId(const std::string & app_id,const std::string & sender_id,UnregisterCallback callback)92 void GCMDriver::UnregisterWithSenderId(const std::string& app_id,
93                                        const std::string& sender_id,
94                                        UnregisterCallback callback) {
95   DCHECK(!sender_id.empty());
96   UnregisterInternal(app_id, &sender_id, std::move(callback));
97 }
98 
UnregisterInternal(const std::string & app_id,const std::string * sender_id,UnregisterCallback callback)99 void GCMDriver::UnregisterInternal(const std::string& app_id,
100                                    const std::string* sender_id,
101                                    UnregisterCallback callback) {
102   DCHECK(!app_id.empty());
103   DCHECK(!callback.is_null());
104 
105   GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
106   if (result != GCMClient::SUCCESS) {
107     std::move(callback).Run(result);
108     return;
109   }
110 
111   // If previous un/register operation is still in progress, bail out.
112   if (register_callbacks_.find(app_id) != register_callbacks_.end() ||
113       unregister_callbacks_.find(app_id) != unregister_callbacks_.end()) {
114     std::move(callback).Run(GCMClient::ASYNC_OPERATION_PENDING);
115     return;
116   }
117 
118   unregister_callbacks_[app_id] = std::move(callback);
119 
120   if (sender_id)
121     UnregisterWithSenderIdImpl(app_id, *sender_id);
122   else
123     UnregisterImpl(app_id);
124 }
125 
Send(const std::string & app_id,const std::string & receiver_id,const OutgoingMessage & message,SendCallback callback)126 void GCMDriver::Send(const std::string& app_id,
127                      const std::string& receiver_id,
128                      const OutgoingMessage& message,
129                      SendCallback callback) {
130   DCHECK(!app_id.empty());
131   DCHECK(!receiver_id.empty());
132   DCHECK(!callback.is_null());
133 
134   GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
135   if (result != GCMClient::SUCCESS) {
136     std::move(callback).Run(std::string(), result);
137     return;
138   }
139 
140   // If the message with send ID is still in progress, bail out.
141   std::pair<std::string, std::string> key(app_id, message.id);
142   if (send_callbacks_.find(key) != send_callbacks_.end()) {
143     std::move(callback).Run(message.id, GCMClient::INVALID_PARAMETER);
144     return;
145   }
146 
147   send_callbacks_[key] = std::move(callback);
148 
149   SendImpl(app_id, receiver_id, message);
150 }
151 
GetEncryptionInfo(const std::string & app_id,GetEncryptionInfoCallback callback)152 void GCMDriver::GetEncryptionInfo(const std::string& app_id,
153                                   GetEncryptionInfoCallback callback) {
154   encryption_provider_.GetEncryptionInfo(app_id, "" /* authorized_entity */,
155                                          std::move(callback));
156 }
157 
UnregisterWithSenderIdImpl(const std::string & app_id,const std::string & sender_id)158 void GCMDriver::UnregisterWithSenderIdImpl(const std::string& app_id,
159                                            const std::string& sender_id) {
160   NOTREACHED();
161 }
162 
RegisterFinished(const std::string & app_id,const std::string & registration_id,GCMClient::Result result)163 void GCMDriver::RegisterFinished(const std::string& app_id,
164                                  const std::string& registration_id,
165                                  GCMClient::Result result) {
166   auto callback_iter = register_callbacks_.find(app_id);
167   if (callback_iter == register_callbacks_.end()) {
168     // The callback could have been removed when the app is uninstalled.
169     return;
170   }
171 
172   RegisterCallback callback = std::move(callback_iter->second);
173   register_callbacks_.erase(callback_iter);
174   std::move(callback).Run(registration_id, result);
175 }
176 
RemoveEncryptionInfoAfterUnregister(const std::string & app_id,GCMClient::Result result)177 void GCMDriver::RemoveEncryptionInfoAfterUnregister(const std::string& app_id,
178                                                     GCMClient::Result result) {
179   encryption_provider_.RemoveEncryptionInfo(
180       app_id, "" /* authorized_entity */,
181       base::BindOnce(&GCMDriver::UnregisterFinished,
182                      weak_ptr_factory_.GetWeakPtr(), app_id, result));
183 }
184 
UnregisterFinished(const std::string & app_id,GCMClient::Result result)185 void GCMDriver::UnregisterFinished(const std::string& app_id,
186                                    GCMClient::Result result) {
187   auto callback_iter = unregister_callbacks_.find(app_id);
188   if (callback_iter == unregister_callbacks_.end())
189     return;
190 
191   UnregisterCallback callback = std::move(callback_iter->second);
192   unregister_callbacks_.erase(callback_iter);
193   std::move(callback).Run(result);
194 }
195 
SendFinished(const std::string & app_id,const std::string & message_id,GCMClient::Result result)196 void GCMDriver::SendFinished(const std::string& app_id,
197                              const std::string& message_id,
198                              GCMClient::Result result) {
199   auto callback_iter = send_callbacks_.find(
200       std::pair<std::string, std::string>(app_id, message_id));
201   if (callback_iter == send_callbacks_.end()) {
202     // The callback could have been removed when the app is uninstalled.
203     return;
204   }
205 
206   SendCallback callback = std::move(callback_iter->second);
207   send_callbacks_.erase(callback_iter);
208   std::move(callback).Run(message_id, result);
209 }
210 
Shutdown()211 void GCMDriver::Shutdown() {
212   for (GCMAppHandlerMap::const_iterator iter = app_handlers_.begin();
213        iter != app_handlers_.end(); ++iter) {
214     DVLOG(1) << "Calling ShutdownHandler for: " << iter->first;
215     iter->second->ShutdownHandler();
216   }
217   app_handlers_.clear();
218 }
219 
AddAppHandler(const std::string & app_id,GCMAppHandler * handler)220 void GCMDriver::AddAppHandler(const std::string& app_id,
221                               GCMAppHandler* handler) {
222   DCHECK(!app_id.empty());
223   DCHECK(handler);
224   DCHECK_EQ(app_handlers_.count(app_id), 0u);
225   app_handlers_[app_id] = handler;
226   DVLOG(1) << "App handler added for: " << app_id;
227 }
228 
RemoveAppHandler(const std::string & app_id)229 void GCMDriver::RemoveAppHandler(const std::string& app_id) {
230   DCHECK(!app_id.empty());
231   app_handlers_.erase(app_id);
232   DVLOG(1) << "App handler removed for: " << app_id;
233 }
234 
GetAppHandler(const std::string & app_id)235 GCMAppHandler* GCMDriver::GetAppHandler(const std::string& app_id) {
236   // Look for exact match.
237   GCMAppHandlerMap::const_iterator iter = app_handlers_.find(app_id);
238   if (iter != app_handlers_.end())
239     return iter->second;
240 
241   // Ask the handlers whether they know how to handle it.
242   for (iter = app_handlers_.begin(); iter != app_handlers_.end(); ++iter) {
243     if (iter->second->CanHandle(app_id))
244       return iter->second;
245   }
246 
247   return nullptr;
248 }
249 
GetEncryptionProviderInternal()250 GCMEncryptionProvider* GCMDriver::GetEncryptionProviderInternal() {
251   return &encryption_provider_;
252 }
253 
HasRegisterCallback(const std::string & app_id)254 bool GCMDriver::HasRegisterCallback(const std::string& app_id) {
255   return register_callbacks_.find(app_id) != register_callbacks_.end();
256 }
257 
ClearCallbacks()258 void GCMDriver::ClearCallbacks() {
259   register_callbacks_.clear();
260   unregister_callbacks_.clear();
261   send_callbacks_.clear();
262 }
263 
DispatchMessage(const std::string & app_id,const IncomingMessage & message)264 void GCMDriver::DispatchMessage(const std::string& app_id,
265                                 const IncomingMessage& message) {
266   encryption_provider_.DecryptMessage(
267       app_id, message,
268       base::BindOnce(&GCMDriver::DispatchMessageInternal,
269                      weak_ptr_factory_.GetWeakPtr(), app_id));
270 }
271 
DispatchMessageInternal(const std::string & app_id,GCMDecryptionResult result,IncomingMessage message)272 void GCMDriver::DispatchMessageInternal(const std::string& app_id,
273                                         GCMDecryptionResult result,
274                                         IncomingMessage message) {
275   UMA_HISTOGRAM_ENUMERATION("GCM.Crypto.DecryptMessageResult", result,
276                             GCMDecryptionResult::ENUM_SIZE);
277 
278   switch (result) {
279     case GCMDecryptionResult::UNENCRYPTED:
280     case GCMDecryptionResult::DECRYPTED_DRAFT_03:
281     case GCMDecryptionResult::DECRYPTED_DRAFT_08: {
282       GCMAppHandler* handler = GetAppHandler(app_id);
283       UMA_HISTOGRAM_BOOLEAN("GCM.DeliveredToAppHandler", !!handler);
284 
285       if (handler)
286         handler->OnMessage(app_id, message);
287 
288       // TODO(peter/harkness): Surface unavailable app handlers on
289       // chrome://gcm-internals and send a delivery receipt.
290       return;
291     }
292     case GCMDecryptionResult::INVALID_ENCRYPTION_HEADER:
293     case GCMDecryptionResult::INVALID_CRYPTO_KEY_HEADER:
294     case GCMDecryptionResult::NO_KEYS:
295     case GCMDecryptionResult::INVALID_SHARED_SECRET:
296     case GCMDecryptionResult::INVALID_PAYLOAD:
297     case GCMDecryptionResult::INVALID_BINARY_HEADER_PAYLOAD_LENGTH:
298     case GCMDecryptionResult::INVALID_BINARY_HEADER_RECORD_SIZE:
299     case GCMDecryptionResult::INVALID_BINARY_HEADER_PUBLIC_KEY_LENGTH:
300     case GCMDecryptionResult::INVALID_BINARY_HEADER_PUBLIC_KEY_FORMAT: {
301       RecordDecryptionFailure(app_id, result);
302       GCMAppHandler* handler = GetAppHandler(app_id);
303       if (handler) {
304         handler->OnMessageDecryptionFailed(
305             app_id, message.message_id,
306             ToGCMDecryptionResultDetailsString(result));
307       }
308       return;
309     }
310     case GCMDecryptionResult::ENUM_SIZE:
311       break;  // deliberate fall-through
312   }
313 
314   NOTREACHED();
315 }
316 
RegisterAfterUnregister(const std::string & app_id,const std::vector<std::string> & normalized_sender_ids,UnregisterCallback unregister_callback,GCMClient::Result result)317 void GCMDriver::RegisterAfterUnregister(
318     const std::string& app_id,
319     const std::vector<std::string>& normalized_sender_ids,
320     UnregisterCallback unregister_callback,
321     GCMClient::Result result) {
322   // Invoke the original unregister callback.
323   std::move(unregister_callback).Run(result);
324 
325   // Trigger the pending registration.
326   DCHECK(register_callbacks_.find(app_id) != register_callbacks_.end());
327   RegisterImpl(app_id, normalized_sender_ids);
328 }
329 
EncryptMessage(const std::string & app_id,const std::string & authorized_entity,const std::string & p256dh,const std::string & auth_secret,const std::string & message,EncryptMessageCallback callback)330 void GCMDriver::EncryptMessage(const std::string& app_id,
331                                const std::string& authorized_entity,
332                                const std::string& p256dh,
333                                const std::string& auth_secret,
334                                const std::string& message,
335                                EncryptMessageCallback callback) {
336   encryption_provider_.EncryptMessage(
337       app_id, authorized_entity, p256dh, auth_secret, message,
338       base::BindOnce(&GCMDriver::OnMessageEncrypted,
339                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
340 }
341 
OnMessageEncrypted(EncryptMessageCallback callback,GCMEncryptionResult result,std::string message)342 void GCMDriver::OnMessageEncrypted(EncryptMessageCallback callback,
343                                    GCMEncryptionResult result,
344                                    std::string message) {
345   UMA_HISTOGRAM_ENUMERATION("GCM.Crypto.EncryptMessageResult", result,
346                             GCMEncryptionResult::ENUM_SIZE);
347   std::move(callback).Run(result, std::move(message));
348 }
349 
DecryptMessage(const std::string & app_id,const std::string & authorized_entity,const std::string & message,DecryptMessageCallback callback)350 void GCMDriver::DecryptMessage(const std::string& app_id,
351                                const std::string& authorized_entity,
352                                const std::string& message,
353                                DecryptMessageCallback callback) {
354   IncomingMessage incoming_message;
355   incoming_message.sender_id = authorized_entity;
356   incoming_message.raw_data = message;
357   incoming_message.data[GCMEncryptionProvider::kContentEncodingProperty] =
358       GCMEncryptionProvider::kContentCodingAes128Gcm;
359   encryption_provider_.DecryptMessage(
360       app_id, incoming_message,
361       base::BindOnce(&GCMDriver::OnMessageDecrypted,
362                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
363 }
364 
OnMessageDecrypted(DecryptMessageCallback callback,GCMDecryptionResult result,IncomingMessage message)365 void GCMDriver::OnMessageDecrypted(DecryptMessageCallback callback,
366                                    GCMDecryptionResult result,
367                                    IncomingMessage message) {
368   UMA_HISTOGRAM_ENUMERATION("GCM.Crypto.DecryptMessageResult", result,
369                             GCMDecryptionResult::ENUM_SIZE);
370   std::move(callback).Run(result, std::move(message.raw_data));
371 }
372 
373 }  // namespace gcm
374