blob: 35960120e381a807721bd19a092eef9eab55866f [file] [log] [blame]
[email protected]df84c532014-04-25 15:36:541// 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
[email protected]8d41e5a2014-05-28 03:18:495#include "components/gcm_driver/gcm_driver.h"
[email protected]df84c532014-04-25 15:36:546
avi26062922015-12-26 00:14:187#include <stddef.h>
8
[email protected]c27c10792014-06-05 15:27:239#include <algorithm>
10
jianli753282a32015-01-09 02:07:4011#include "base/bind.h"
peterbfa736e2015-07-28 16:19:5512#include "base/files/file_path.h"
[email protected]df84c532014-04-25 15:36:5413#include "base/logging.h"
peter266a2aa42016-02-19 18:51:3914#include "base/metrics/histogram_macros.h"
Peter Beverlooa376e98c2017-06-27 15:55:3715#include "components/gcm_driver/crypto/gcm_decryption_result.h"
Alex Chau67605b92019-06-05 10:48:2916#include "components/gcm_driver/crypto/gcm_encryption_result.h"
[email protected]446f73c22014-05-14 20:47:1817#include "components/gcm_driver/gcm_app_handler.h"
[email protected]df84c532014-04-25 15:36:5418
19namespace gcm {
20
Rayan Kanso9e5adf212019-05-09 16:07:5321InstanceIDHandler::InstanceIDHandler() = default;
jianli10018b2d2015-05-11 21:14:1322
Rayan Kanso9e5adf212019-05-09 16:07:5323InstanceIDHandler::~InstanceIDHandler() = default;
jianli10018b2d2015-05-11 21:14:1324
danakjb534bf72019-05-02 17:10:1425void InstanceIDHandler::DeleteAllTokensForApp(const std::string& app_id,
26 DeleteTokenCallback callback) {
27 DeleteToken(app_id, "*", "*", std::move(callback));
jianlic5f6bd92015-05-28 02:23:4528}
29
peterbfa736e2015-07-28 16:19:5530GCMDriver::GCMDriver(
31 const base::FilePath& store_path,
Alex Chauda2073d62020-01-29 11:26:0832 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner) {
Alex Chaua76a6e32019-06-26 16:20:0133 // The |blocking_task_runner| can be nullptr for tests that do not need the
peterbfa736e2015-07-28 16:19:5534 // encryption capabilities of the GCMDriver class.
35 if (blocking_task_runner)
36 encryption_provider_.Init(store_path, blocking_task_runner);
[email protected]9d7e5c02014-05-21 03:09:0337}
38
Rayan Kanso9e5adf212019-05-09 16:07:5339GCMDriver::~GCMDriver() = default;
[email protected]9d7e5c02014-05-21 03:09:0340
[email protected]c27c10792014-06-05 15:27:2341void GCMDriver::Register(const std::string& app_id,
42 const std::vector<std::string>& sender_ids,
danakjb534bf72019-05-02 17:10:1443 RegisterCallback callback) {
[email protected]c27c10792014-06-05 15:27:2344 DCHECK(!app_id.empty());
jianli7a0c9b62015-05-26 23:24:4745 DCHECK(!sender_ids.empty() && sender_ids.size() <= kMaxSenders);
[email protected]c27c10792014-06-05 15:27:2346 DCHECK(!callback.is_null());
47
jianlif3e52af42015-01-21 23:18:4748 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
[email protected]c27c10792014-06-05 15:27:2349 if (result != GCMClient::SUCCESS) {
danakjb534bf72019-05-02 17:10:1450 std::move(callback).Run(std::string(), result);
[email protected]c27c10792014-06-05 15:27:2351 return;
52 }
53
jianlif17b85a2014-10-29 21:42:3054 // If previous register operation is still in progress, bail out.
55 if (register_callbacks_.find(app_id) != register_callbacks_.end()) {
danakjb534bf72019-05-02 17:10:1456 std::move(callback).Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING);
[email protected]c27c10792014-06-05 15:27:2357 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
danakjb534bf72019-05-02 17:10:1464 register_callbacks_[app_id] = std::move(callback);
[email protected]c27c10792014-06-05 15:27:2365
jianlif17b85a2014-10-29 21:42:3066 // 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).
jdoerrie3feb1852018-10-05 12:16:4470 auto unregister_iter = unregister_callbacks_.find(app_id);
jianlif17b85a2014-10-29 21:42:3071 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).
danakjb534bf72019-05-02 17:10:1478 unregister_iter->second = base::BindOnce(
79 &GCMDriver::RegisterAfterUnregister, weak_ptr_factory_.GetWeakPtr(),
80 app_id, normalized_sender_ids, std::move(unregister_iter->second));
jianlif17b85a2014-10-29 21:42:3081 return;
82 }
83
[email protected]c27c10792014-06-05 15:27:2384 RegisterImpl(app_id, normalized_sender_ids);
85}
86
87void GCMDriver::Unregister(const std::string& app_id,
danakjb534bf72019-05-02 17:10:1488 UnregisterCallback callback) {
89 UnregisterInternal(app_id, nullptr /* sender_id */, std::move(callback));
johnme07b355a2015-02-19 17:00:5190}
91
danakjb534bf72019-05-02 17:10:1492void GCMDriver::UnregisterWithSenderId(const std::string& app_id,
93 const std::string& sender_id,
94 UnregisterCallback callback) {
johnme07b355a2015-02-19 17:00:5195 DCHECK(!sender_id.empty());
danakjb534bf72019-05-02 17:10:1496 UnregisterInternal(app_id, &sender_id, std::move(callback));
johnme07b355a2015-02-19 17:00:5197}
98
99void GCMDriver::UnregisterInternal(const std::string& app_id,
100 const std::string* sender_id,
danakjb534bf72019-05-02 17:10:14101 UnregisterCallback callback) {
[email protected]c27c10792014-06-05 15:27:23102 DCHECK(!app_id.empty());
103 DCHECK(!callback.is_null());
104
jianlif3e52af42015-01-21 23:18:47105 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
[email protected]c27c10792014-06-05 15:27:23106 if (result != GCMClient::SUCCESS) {
danakjb534bf72019-05-02 17:10:14107 std::move(callback).Run(result);
[email protected]c27c10792014-06-05 15:27:23108 return;
109 }
110
111 // If previous un/register operation is still in progress, bail out.
jianlif17b85a2014-10-29 21:42:30112 if (register_callbacks_.find(app_id) != register_callbacks_.end() ||
113 unregister_callbacks_.find(app_id) != unregister_callbacks_.end()) {
danakjb534bf72019-05-02 17:10:14114 std::move(callback).Run(GCMClient::ASYNC_OPERATION_PENDING);
[email protected]c27c10792014-06-05 15:27:23115 return;
116 }
117
danakjb534bf72019-05-02 17:10:14118 unregister_callbacks_[app_id] = std::move(callback);
[email protected]c27c10792014-06-05 15:27:23119
johnme07b355a2015-02-19 17:00:51120 if (sender_id)
121 UnregisterWithSenderIdImpl(app_id, *sender_id);
122 else
123 UnregisterImpl(app_id);
[email protected]c27c10792014-06-05 15:27:23124}
125
126void GCMDriver::Send(const std::string& app_id,
127 const std::string& receiver_id,
mvanouwerkerkf8633deb2015-07-13 11:04:06128 const OutgoingMessage& message,
Reilly Grantaa7bc2f2020-01-31 11:49:29129 SendCallback callback) {
[email protected]c27c10792014-06-05 15:27:23130 DCHECK(!app_id.empty());
131 DCHECK(!receiver_id.empty());
132 DCHECK(!callback.is_null());
133
jianlif3e52af42015-01-21 23:18:47134 GCMClient::Result result = EnsureStarted(GCMClient::IMMEDIATE_START);
[email protected]c27c10792014-06-05 15:27:23135 if (result != GCMClient::SUCCESS) {
Reilly Grantaa7bc2f2020-01-31 11:49:29136 std::move(callback).Run(std::string(), result);
[email protected]c27c10792014-06-05 15:27:23137 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()) {
Reilly Grantaa7bc2f2020-01-31 11:49:29143 std::move(callback).Run(message.id, GCMClient::INVALID_PARAMETER);
[email protected]c27c10792014-06-05 15:27:23144 return;
145 }
146
Reilly Grantaa7bc2f2020-01-31 11:49:29147 send_callbacks_[key] = std::move(callback);
[email protected]c27c10792014-06-05 15:27:23148
149 SendImpl(app_id, receiver_id, message);
150}
151
Peter Beverloo9635b662019-07-10 19:05:18152void GCMDriver::GetEncryptionInfo(const std::string& app_id,
153 GetEncryptionInfoCallback callback) {
johnme36ae5802016-05-10 15:46:24154 encryption_provider_.GetEncryptionInfo(app_id, "" /* authorized_entity */,
Peter Beverloo9635b662019-07-10 19:05:18155 std::move(callback));
peterbfa736e2015-07-28 16:19:55156}
157
johnme07b355a2015-02-19 17:00:51158void GCMDriver::UnregisterWithSenderIdImpl(const std::string& app_id,
159 const std::string& sender_id) {
160 NOTREACHED();
161}
162
[email protected]c27c10792014-06-05 15:27:23163void GCMDriver::RegisterFinished(const std::string& app_id,
164 const std::string& registration_id,
165 GCMClient::Result result) {
jdoerrie3feb1852018-10-05 12:16:44166 auto callback_iter = register_callbacks_.find(app_id);
[email protected]c27c10792014-06-05 15:27:23167 if (callback_iter == register_callbacks_.end()) {
168 // The callback could have been removed when the app is uninstalled.
169 return;
170 }
171
danakjb534bf72019-05-02 17:10:14172 RegisterCallback callback = std::move(callback_iter->second);
[email protected]c27c10792014-06-05 15:27:23173 register_callbacks_.erase(callback_iter);
danakjb534bf72019-05-02 17:10:14174 std::move(callback).Run(registration_id, result);
[email protected]c27c10792014-06-05 15:27:23175}
176
petera4795ae832016-02-17 11:35:27177void GCMDriver::RemoveEncryptionInfoAfterUnregister(const std::string& app_id,
178 GCMClient::Result result) {
179 encryption_provider_.RemoveEncryptionInfo(
johnme36ae5802016-05-10 15:46:24180 app_id, "" /* authorized_entity */,
Reilly Grantaa7bc2f2020-01-31 11:49:29181 base::BindOnce(&GCMDriver::UnregisterFinished,
182 weak_ptr_factory_.GetWeakPtr(), app_id, result));
petera4795ae832016-02-17 11:35:27183}
184
[email protected]c27c10792014-06-05 15:27:23185void GCMDriver::UnregisterFinished(const std::string& app_id,
186 GCMClient::Result result) {
jdoerrie3feb1852018-10-05 12:16:44187 auto callback_iter = unregister_callbacks_.find(app_id);
[email protected]c27c10792014-06-05 15:27:23188 if (callback_iter == unregister_callbacks_.end())
189 return;
190
danakjb534bf72019-05-02 17:10:14191 UnregisterCallback callback = std::move(callback_iter->second);
[email protected]c27c10792014-06-05 15:27:23192 unregister_callbacks_.erase(callback_iter);
danakjb534bf72019-05-02 17:10:14193 std::move(callback).Run(result);
[email protected]c27c10792014-06-05 15:27:23194}
195
196void GCMDriver::SendFinished(const std::string& app_id,
197 const std::string& message_id,
198 GCMClient::Result result) {
jdoerrie3feb1852018-10-05 12:16:44199 auto callback_iter = send_callbacks_.find(
200 std::pair<std::string, std::string>(app_id, message_id));
[email protected]c27c10792014-06-05 15:27:23201 if (callback_iter == send_callbacks_.end()) {
202 // The callback could have been removed when the app is uninstalled.
203 return;
204 }
205
Reilly Grantaa7bc2f2020-01-31 11:49:29206 SendCallback callback = std::move(callback_iter->second);
[email protected]c27c10792014-06-05 15:27:23207 send_callbacks_.erase(callback_iter);
Reilly Grantaa7bc2f2020-01-31 11:49:29208 std::move(callback).Run(message_id, result);
[email protected]c27c10792014-06-05 15:27:23209}
210
[email protected]9d7e5c02014-05-21 03:09:03211void GCMDriver::Shutdown() {
[email protected]df84c532014-04-25 15:36:54212 for (GCMAppHandlerMap::const_iterator iter = app_handlers_.begin();
213 iter != app_handlers_.end(); ++iter) {
fgorski83afd872014-10-16 01:11:52214 DVLOG(1) << "Calling ShutdownHandler for: " << iter->first;
[email protected]df84c532014-04-25 15:36:54215 iter->second->ShutdownHandler();
216 }
217 app_handlers_.clear();
[email protected]df84c532014-04-25 15:36:54218}
219
[email protected]530f2162014-05-15 01:05:04220void GCMDriver::AddAppHandler(const std::string& app_id,
221 GCMAppHandler* handler) {
[email protected]df84c532014-04-25 15:36:54222 DCHECK(!app_id.empty());
223 DCHECK(handler);
[email protected]b7176262014-06-18 15:26:29224 DCHECK_EQ(app_handlers_.count(app_id), 0u);
[email protected]df84c532014-04-25 15:36:54225 app_handlers_[app_id] = handler;
fgorski83afd872014-10-16 01:11:52226 DVLOG(1) << "App handler added for: " << app_id;
[email protected]df84c532014-04-25 15:36:54227}
228
[email protected]530f2162014-05-15 01:05:04229void GCMDriver::RemoveAppHandler(const std::string& app_id) {
[email protected]df84c532014-04-25 15:36:54230 DCHECK(!app_id.empty());
[email protected]df84c532014-04-25 15:36:54231 app_handlers_.erase(app_id);
fgorski83afd872014-10-16 01:11:52232 DVLOG(1) << "App handler removed for: " << app_id;
[email protected]df84c532014-04-25 15:36:54233}
234
[email protected]530f2162014-05-15 01:05:04235GCMAppHandler* GCMDriver::GetAppHandler(const std::string& app_id) {
[email protected]b7176262014-06-18 15:26:29236 // Look for exact match.
[email protected]21b77652014-05-31 01:21:09237 GCMAppHandlerMap::const_iterator iter = app_handlers_.find(app_id);
[email protected]b7176262014-06-18 15:26:29238 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
peterbef2a022017-02-23 14:41:15247 return nullptr;
[email protected]df84c532014-04-25 15:36:54248}
249
johnmea00cc8ae2016-06-02 13:58:04250GCMEncryptionProvider* GCMDriver::GetEncryptionProviderInternal() {
251 return &encryption_provider_;
252}
253
[email protected]c27c10792014-06-05 15:27:23254bool GCMDriver::HasRegisterCallback(const std::string& app_id) {
255 return register_callbacks_.find(app_id) != register_callbacks_.end();
256}
257
258void GCMDriver::ClearCallbacks() {
259 register_callbacks_.clear();
260 unregister_callbacks_.clear();
261 send_callbacks_.clear();
262}
263
peteradd31f62015-10-09 10:18:52264void GCMDriver::DispatchMessage(const std::string& app_id,
265 const IncomingMessage& message) {
peter266a2aa42016-02-19 18:51:39266 encryption_provider_.DecryptMessage(
Alex Chauda2073d62020-01-29 11:26:08267 app_id, message,
268 base::BindOnce(&GCMDriver::DispatchMessageInternal,
269 weak_ptr_factory_.GetWeakPtr(), app_id));
peter266a2aa42016-02-19 18:51:39270}
271
Peter Beverlooa376e98c2017-06-27 15:55:37272void GCMDriver::DispatchMessageInternal(const std::string& app_id,
273 GCMDecryptionResult result,
Alex Chauda2073d62020-01-29 11:26:08274 IncomingMessage message) {
peter266a2aa42016-02-19 18:51:39275 UMA_HISTOGRAM_ENUMERATION("GCM.Crypto.DecryptMessageResult", result,
Peter Beverlooa376e98c2017-06-27 15:55:37276 GCMDecryptionResult::ENUM_SIZE);
peter266a2aa42016-02-19 18:51:39277
278 switch (result) {
Peter Beverlooa376e98c2017-06-27 15:55:37279 case GCMDecryptionResult::UNENCRYPTED:
280 case GCMDecryptionResult::DECRYPTED_DRAFT_03:
281 case GCMDecryptionResult::DECRYPTED_DRAFT_08: {
peterbef2a022017-02-23 14:41:15282 GCMAppHandler* handler = GetAppHandler(app_id);
Peter Beverloof6403f32019-09-05 12:33:10283 UMA_HISTOGRAM_BOOLEAN("GCM.DeliveredToAppHandler", !!handler);
284
peterbef2a022017-02-23 14:41:15285 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.
peter266a2aa42016-02-19 18:51:39290 return;
peterbef2a022017-02-23 14:41:15291 }
Peter Beverlooa376e98c2017-06-27 15:55:37292 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:
Peter Beverlooe5eef71732017-06-27 15:51:29297 case GCMDecryptionResult::INVALID_BINARY_HEADER_PAYLOAD_LENGTH:
298 case GCMDecryptionResult::INVALID_BINARY_HEADER_RECORD_SIZE:
299 case GCMDecryptionResult::INVALID_BINARY_HEADER_PUBLIC_KEY_LENGTH:
Rayan Kanso9e5adf212019-05-09 16:07:53300 case GCMDecryptionResult::INVALID_BINARY_HEADER_PUBLIC_KEY_FORMAT: {
peter266a2aa42016-02-19 18:51:39301 RecordDecryptionFailure(app_id, result);
Rayan Kanso9e5adf212019-05-09 16:07:53302 GCMAppHandler* handler = GetAppHandler(app_id);
303 if (handler) {
304 handler->OnMessageDecryptionFailed(
Rayan Kanso7bde07992019-05-09 17:59:22305 app_id, message.message_id,
306 ToGCMDecryptionResultDetailsString(result));
Rayan Kanso9e5adf212019-05-09 16:07:53307 }
peter266a2aa42016-02-19 18:51:39308 return;
Rayan Kanso9e5adf212019-05-09 16:07:53309 }
Peter Beverlooa376e98c2017-06-27 15:55:37310 case GCMDecryptionResult::ENUM_SIZE:
311 break; // deliberate fall-through
peteradd31f62015-10-09 10:18:52312 }
313
peter266a2aa42016-02-19 18:51:39314 NOTREACHED();
peteradd31f62015-10-09 10:18:52315}
316
jianlif17b85a2014-10-29 21:42:30317void GCMDriver::RegisterAfterUnregister(
318 const std::string& app_id,
319 const std::vector<std::string>& normalized_sender_ids,
danakjb534bf72019-05-02 17:10:14320 UnregisterCallback unregister_callback,
jianlif17b85a2014-10-29 21:42:30321 GCMClient::Result result) {
322 // Invoke the original unregister callback.
danakjb534bf72019-05-02 17:10:14323 std::move(unregister_callback).Run(result);
jianlif17b85a2014-10-29 21:42:30324
325 // Trigger the pending registration.
326 DCHECK(register_callbacks_.find(app_id) != register_callbacks_.end());
327 RegisterImpl(app_id, normalized_sender_ids);
[email protected]c27c10792014-06-05 15:27:23328}
329
Alex Chauda2073d62020-01-29 11:26:08330void 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) {
Alex Chau67605b92019-06-05 10:48:29336 encryption_provider_.EncryptMessage(
Alex Chauda2073d62020-01-29 11:26:08337 app_id, authorized_entity, p256dh, auth_secret, message,
Alex Chaua76a6e32019-06-26 16:20:01338 base::BindOnce(&GCMDriver::OnMessageEncrypted,
Alex Chauda2073d62020-01-29 11:26:08339 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
Alex Chau67605b92019-06-05 10:48:29340}
341
Alex Chauda2073d62020-01-29 11:26:08342void GCMDriver::OnMessageEncrypted(EncryptMessageCallback callback,
Alex Chau67605b92019-06-05 10:48:29343 GCMEncryptionResult result,
Alex Chauda2073d62020-01-29 11:26:08344 std::string message) {
Alex Chau67605b92019-06-05 10:48:29345 UMA_HISTOGRAM_ENUMERATION("GCM.Crypto.EncryptMessageResult", result,
346 GCMEncryptionResult::ENUM_SIZE);
Alex Chauda2073d62020-01-29 11:26:08347 std::move(callback).Run(result, std::move(message));
348}
Alex Chau67605b92019-06-05 10:48:29349
Alex Chauda2073d62020-01-29 11:26:08350void 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}
Alex Chau67605b92019-06-05 10:48:29364
Alex Chauda2073d62020-01-29 11:26:08365void 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));
Alex Chau67605b92019-06-05 10:48:29371}
372
[email protected]df84c532014-04-25 15:36:54373} // namespace gcm