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 "chrome/browser/push_messaging/push_messaging_service_impl.h"
6
7 #include <map>
8 #include <sstream>
9 #include <vector>
10
11 #include "base/barrier_closure.h"
12 #include "base/base64url.h"
13 #include "base/bind.h"
14 #include "base/callback_helpers.h"
15 #include "base/command_line.h"
16 #include "base/feature_list.h"
17 #include "base/logging.h"
18 #include "base/metrics/histogram_macros.h"
19 #include "base/strings/string_util.h"
20 #include "base/threading/thread_task_runner_handle.h"
21 #include "base/time/time.h"
22 #include "build/build_config.h"
23 #include "chrome/browser/browser_process.h"
24 #include "chrome/browser/chrome_notification_types.h"
25 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
26 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
27 #include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h"
28 #include "chrome/browser/permissions/abusive_origin_permission_revocation_request.h"
29 #include "chrome/browser/permissions/permission_manager_factory.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
32 #include "chrome/browser/push_messaging/push_messaging_constants.h"
33 #include "chrome/browser/push_messaging/push_messaging_features.h"
34 #include "chrome/browser/push_messaging/push_messaging_service_factory.h"
35 #include "chrome/browser/push_messaging/push_messaging_utils.h"
36 #include "chrome/browser/ui/chrome_pages.h"
37 #include "chrome/common/buildflags.h"
38 #include "chrome/common/chrome_features.h"
39 #include "chrome/common/chrome_switches.h"
40 #include "chrome/common/pref_names.h"
41 #include "chrome/grit/generated_resources.h"
42 #include "components/content_settings/core/browser/host_content_settings_map.h"
43 #include "components/gcm_driver/gcm_driver.h"
44 #include "components/gcm_driver/gcm_profile_service.h"
45 #include "components/gcm_driver/instance_id/instance_id.h"
46 #include "components/gcm_driver/instance_id/instance_id_driver.h"
47 #include "components/gcm_driver/instance_id/instance_id_profile_service.h"
48 #include "components/permissions/permission_manager.h"
49 #include "components/permissions/permission_result.h"
50 #include "components/pref_registry/pref_registry_syncable.h"
51 #include "components/prefs/pref_service.h"
52 #include "content/public/browser/browser_context.h"
53 #include "content/public/browser/devtools_background_services_context.h"
54 #include "content/public/browser/notification_service.h"
55 #include "content/public/browser/render_frame_host.h"
56 #include "content/public/browser/service_worker_context.h"
57 #include "content/public/browser/storage_partition.h"
58 #include "content/public/browser/web_contents.h"
59 #include "content/public/common/child_process_host.h"
60 #include "content/public/common/content_features.h"
61 #include "content/public/common/content_switches.h"
62 #include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
63 #include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom.h"
64 #include "ui/base/l10n/l10n_util.h"
65
66 #if BUILDFLAG(ENABLE_BACKGROUND_MODE)
67 #include "chrome/browser/background/background_mode_manager.h"
68 #include "components/keep_alive_registry/keep_alive_types.h"
69 #include "components/keep_alive_registry/scoped_keep_alive.h"
70 #endif
71
72 #if defined(OS_ANDROID)
73 #include "base/android/jni_android.h"
74 #include "chrome/android/chrome_jni_headers/PushMessagingServiceObserver_jni.h"
75 #endif
76
77 using instance_id::InstanceID;
78
79 namespace {
80
81 // Scope passed to getToken to obtain GCM registration tokens.
82 // Must match Java GoogleCloudMessaging.INSTANCE_ID_SCOPE.
83 const char kGCMScope[] = "GCM";
84
85 const int kMaxRegistrations = 1000000;
86
87 // Chrome does not yet support silent push messages, and requires websites to
88 // indicate that they will only send user-visible messages.
89 const char kSilentPushUnsupportedMessage[] =
90 "Chrome currently only supports the Push API for subscriptions that will "
91 "result in user-visible messages. You can indicate this by calling "
92 "pushManager.subscribe({userVisibleOnly: true}) instead. See "
93 "https://goo.gl/yqv4Q4 for more details.";
94
95 // Message displayed in the console (as an error) when a GCM Sender ID is used
96 // to create a subscription, which is unsupported. The subscription request will
97 // have been blocked, and an exception will be thrown as well.
98 const char kSenderIdRegistrationDisallowedMessage[] =
99 "The provided application server key is not a VAPID key. Only VAPID keys "
100 "are supported. For more information check https://crbug.com/979235.";
101
102 // Message displayed in the console (as a warning) when a GCM Sender ID is used
103 // to create a subscription, which will soon be unsupported.
104 const char kSenderIdRegistrationDeprecatedMessage[] =
105 "The provided application server key is not a VAPID key. Only VAPID keys "
106 "will be supported in the future. For more information check "
107 "https://crbug.com/979235.";
108
RecordDeliveryStatus(blink::mojom::PushEventStatus status)109 void RecordDeliveryStatus(blink::mojom::PushEventStatus status) {
110 UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus", status);
111 }
112
RecordPushSubcriptionChangeStatus(blink::mojom::PushEventStatus status)113 void RecordPushSubcriptionChangeStatus(blink::mojom::PushEventStatus status) {
114 UMA_HISTOGRAM_ENUMERATION("PushMessaging.PushSubscriptionChangeStatus",
115 status);
116 }
RecordUnsubscribeReason(blink::mojom::PushUnregistrationReason reason)117 void RecordUnsubscribeReason(blink::mojom::PushUnregistrationReason reason) {
118 UMA_HISTOGRAM_ENUMERATION("PushMessaging.UnregistrationReason", reason);
119 }
120
RecordUnsubscribeGCMResult(gcm::GCMClient::Result result)121 void RecordUnsubscribeGCMResult(gcm::GCMClient::Result result) {
122 UMA_HISTOGRAM_ENUMERATION("PushMessaging.UnregistrationGCMResult", result);
123 }
124
RecordUnsubscribeIIDResult(InstanceID::Result result)125 void RecordUnsubscribeIIDResult(InstanceID::Result result) {
126 UMA_HISTOGRAM_ENUMERATION("PushMessaging.UnregistrationIIDResult", result);
127 }
128
ToPermissionStatus(ContentSetting content_setting)129 blink::mojom::PermissionStatus ToPermissionStatus(
130 ContentSetting content_setting) {
131 switch (content_setting) {
132 case CONTENT_SETTING_ALLOW:
133 return blink::mojom::PermissionStatus::GRANTED;
134 case CONTENT_SETTING_BLOCK:
135 return blink::mojom::PermissionStatus::DENIED;
136 case CONTENT_SETTING_ASK:
137 return blink::mojom::PermissionStatus::ASK;
138 default:
139 break;
140 }
141 NOTREACHED();
142 return blink::mojom::PermissionStatus::DENIED;
143 }
144
UnregisterCallbackToClosure(base::OnceClosure closure,blink::mojom::PushUnregistrationStatus status)145 void UnregisterCallbackToClosure(
146 base::OnceClosure closure,
147 blink::mojom::PushUnregistrationStatus status) {
148 DCHECK(closure);
149 std::move(closure).Run();
150 }
151
LogMessageReceivedEventToDevTools(content::DevToolsBackgroundServicesContext * devtools_context,const PushMessagingAppIdentifier & app_identifier,const std::string & message_id,bool was_encrypted,const std::string & error_message,const std::string & payload)152 void LogMessageReceivedEventToDevTools(
153 content::DevToolsBackgroundServicesContext* devtools_context,
154 const PushMessagingAppIdentifier& app_identifier,
155 const std::string& message_id,
156 bool was_encrypted,
157 const std::string& error_message,
158 const std::string& payload) {
159 if (!devtools_context)
160 return;
161
162 std::map<std::string, std::string> event_metadata = {
163 {"Success", error_message.empty() ? "Yes" : "No"},
164 {"Was Encrypted", was_encrypted ? "Yes" : "No"}};
165
166 if (!error_message.empty())
167 event_metadata["Error Reason"] = error_message;
168 else if (was_encrypted)
169 event_metadata["Payload"] = payload;
170
171 devtools_context->LogBackgroundServiceEvent(
172 app_identifier.service_worker_registration_id(),
173 url::Origin::Create(app_identifier.origin()),
174 content::DevToolsBackgroundService::kPushMessaging,
175 "Push message received" /* event_name */, message_id, event_metadata);
176 }
177
GetMainFrameForRenderFrameHost(content::RenderFrameHost * render_frame_host)178 content::RenderFrameHost* GetMainFrameForRenderFrameHost(
179 content::RenderFrameHost* render_frame_host) {
180 content::WebContents* web_contents =
181 content::WebContents::FromRenderFrameHost(render_frame_host);
182
183 return web_contents ? web_contents->GetMainFrame() : nullptr;
184 }
185
PendingMessage(std::string app_id,gcm::IncomingMessage message)186 PendingMessage::PendingMessage(std::string app_id, gcm::IncomingMessage message)
187 : app_id(std::move(app_id)), message(std::move(message)) {}
188 PendingMessage::PendingMessage(PendingMessage&& other) = default;
189 PendingMessage& PendingMessage::operator=(PendingMessage&& other) = default;
190 PendingMessage::~PendingMessage() = default;
191
192 } // namespace
193
194 // static
InitializeForProfile(Profile * profile)195 void PushMessagingServiceImpl::InitializeForProfile(Profile* profile) {
196 // TODO(johnme): Consider whether push should be enabled in incognito.
197 if (!profile || profile->IsOffTheRecord())
198 return;
199
200 int count = PushMessagingAppIdentifier::GetCount(profile);
201 if (count <= 0)
202 return;
203
204 PushMessagingServiceImpl* push_service =
205 PushMessagingServiceFactory::GetForProfile(profile);
206 if (push_service) {
207 push_service->IncreasePushSubscriptionCount(count, false /* is_pending */);
208 push_service->RemoveExpiredSubscriptions();
209 }
210 }
211
RemoveExpiredSubscriptions()212 void PushMessagingServiceImpl::RemoveExpiredSubscriptions() {
213 if (!base::FeatureList::IsEnabled(
214 features::kPushSubscriptionWithExpirationTime)) {
215 return;
216 }
217
218 base::RepeatingClosure barrier_closure = base::BarrierClosure(
219 PushMessagingAppIdentifier::GetCount(profile_),
220 remove_expired_subscriptions_callback_for_testing_.is_null()
221 ? base::DoNothing()
222 : std::move(remove_expired_subscriptions_callback_for_testing_));
223
224 for (const auto& identifier : PushMessagingAppIdentifier::GetAll(profile_)) {
225 if (!identifier.IsExpired()) {
226 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, barrier_closure);
227 continue;
228 }
229 content::BrowserThread::PostBestEffortTask(
230 FROM_HERE, base::ThreadTaskRunnerHandle::Get(),
231 base::BindOnce(
232 &PushMessagingServiceImpl::UnexpectedChange,
233 weak_factory_.GetWeakPtr(), identifier,
234 blink::mojom::PushUnregistrationReason::SUBSCRIPTION_EXPIRED,
235 barrier_closure));
236 }
237 }
238
UnexpectedChange(PushMessagingAppIdentifier identifier,blink::mojom::PushUnregistrationReason reason,base::OnceClosure completed_closure)239 void PushMessagingServiceImpl::UnexpectedChange(
240 PushMessagingAppIdentifier identifier,
241 blink::mojom::PushUnregistrationReason reason,
242 base::OnceClosure completed_closure) {
243 auto unsubscribe_closure =
244 base::BindOnce(&PushMessagingServiceImpl::UnexpectedUnsubscribe,
245 weak_factory_.GetWeakPtr(), identifier, reason,
246 base::BindOnce(&UnregisterCallbackToClosure,
247 std::move(completed_closure)));
248 if (base::FeatureList::IsEnabled(features::kPushSubscriptionChangeEvent)) {
249 // Find old subscription and fire a `pushsubscriptionchange` event
250 GetPushSubscriptionFromAppIdentifier(
251 identifier,
252 base::BindOnce(&PushMessagingServiceImpl::FirePushSubscriptionChange,
253 weak_factory_.GetWeakPtr(), identifier,
254 std::move(unsubscribe_closure),
255 nullptr /* new_subscription */));
256 } else {
257 std::move(unsubscribe_closure).Run();
258 }
259 }
260
PushMessagingServiceImpl(Profile * profile)261 PushMessagingServiceImpl::PushMessagingServiceImpl(Profile* profile)
262 : profile_(profile),
263 push_subscription_count_(0),
264 pending_push_subscription_count_(0),
265 notification_manager_(profile) {
266 DCHECK(profile);
267 HostContentSettingsMapFactory::GetForProfile(profile_)->AddObserver(this);
268
269 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
270 content::NotificationService::AllSources());
271 refresh_observer_.Add(&refresher_);
272 }
273
274 PushMessagingServiceImpl::~PushMessagingServiceImpl() = default;
275
IncreasePushSubscriptionCount(int add,bool is_pending)276 void PushMessagingServiceImpl::IncreasePushSubscriptionCount(int add,
277 bool is_pending) {
278 DCHECK_GT(add, 0);
279 if (push_subscription_count_ + pending_push_subscription_count_ == 0)
280 GetGCMDriver()->AddAppHandler(kPushMessagingAppIdentifierPrefix, this);
281
282 if (is_pending)
283 pending_push_subscription_count_ += add;
284 else
285 push_subscription_count_ += add;
286 }
287
DecreasePushSubscriptionCount(int subtract,bool was_pending)288 void PushMessagingServiceImpl::DecreasePushSubscriptionCount(int subtract,
289 bool was_pending) {
290 DCHECK_GT(subtract, 0);
291 if (was_pending) {
292 pending_push_subscription_count_ -= subtract;
293 DCHECK_GE(pending_push_subscription_count_, 0);
294 } else {
295 push_subscription_count_ -= subtract;
296 DCHECK_GE(push_subscription_count_, 0);
297 }
298
299 if (push_subscription_count_ + pending_push_subscription_count_ == 0)
300 GetGCMDriver()->RemoveAppHandler(kPushMessagingAppIdentifierPrefix);
301 }
302
CanHandle(const std::string & app_id) const303 bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const {
304 return base::StartsWith(app_id, kPushMessagingAppIdentifierPrefix,
305 base::CompareCase::INSENSITIVE_ASCII);
306 }
307
ShutdownHandler()308 void PushMessagingServiceImpl::ShutdownHandler() {
309 // Shutdown() should come before and it removes us from the list of app
310 // handlers of gcm::GCMDriver so this shouldn't ever been called.
311 NOTREACHED();
312 }
313
OnStoreReset()314 void PushMessagingServiceImpl::OnStoreReset() {
315 // Delete all cached subscriptions, since they are now invalid.
316 for (const auto& identifier : PushMessagingAppIdentifier::GetAll(profile_)) {
317 RecordUnsubscribeReason(
318 blink::mojom::PushUnregistrationReason::GCM_STORE_RESET);
319 // Clear all the subscriptions in parallel, to reduce risk that shutdown
320 // occurs before we finish clearing them.
321 ClearPushSubscriptionId(profile_, identifier.origin(),
322 identifier.service_worker_registration_id(),
323 base::DoNothing());
324 // TODO(johnme): Fire pushsubscriptionchange/pushsubscriptionlost SW event.
325 }
326 PushMessagingAppIdentifier::DeleteAllFromPrefs(profile_);
327 }
328
329 // OnMessage methods -----------------------------------------------------------
330
OnMessage(const std::string & app_id,const gcm::IncomingMessage & message)331 void PushMessagingServiceImpl::OnMessage(const std::string& app_id,
332 const gcm::IncomingMessage& message) {
333 // We won't have time to process and act on the message.
334 // TODO(peter) This should be checked at the level of the GCMDriver, so that
335 // the message is not consumed. See https://crbug.com/612815
336 if (g_browser_process->IsShuttingDown() || shutdown_started_)
337 return;
338
339 in_flight_message_deliveries_.insert(app_id);
340
341 #if BUILDFLAG(ENABLE_BACKGROUND_MODE)
342 if (g_browser_process->background_mode_manager()) {
343 UMA_HISTOGRAM_BOOLEAN("PushMessaging.ReceivedMessageInBackground",
344 g_browser_process->background_mode_manager()
345 ->IsBackgroundWithoutWindows());
346 }
347
348 if (!in_flight_keep_alive_) {
349 in_flight_keep_alive_ = std::make_unique<ScopedKeepAlive>(
350 KeepAliveOrigin::IN_FLIGHT_PUSH_MESSAGE,
351 KeepAliveRestartOption::DISABLED);
352 }
353 #endif
354
355 refresher_.GotMessageFrom(app_id);
356
357 PushMessagingAppIdentifier app_identifier =
358 PushMessagingAppIdentifier::FindByAppId(profile_, app_id);
359 // Drop message and unregister if app_id was unknown (maybe recently deleted).
360 if (app_identifier.is_null()) {
361 base::Optional<PushMessagingAppIdentifier> refresh_identifier =
362 refresher_.FindActiveAppIdentifier(app_id);
363 if (!refresh_identifier) {
364 DeliverMessageCallback(app_id, GURL::EmptyGURL(),
365 -1 /* kInvalidServiceWorkerRegistrationId */,
366 message, message_handled_callback(),
367 blink::mojom::PushEventStatus::UNKNOWN_APP_ID);
368 return;
369 }
370 app_identifier = std::move(*refresh_identifier);
371 }
372
373 LogMessageReceivedEventToDevTools(
374 GetDevToolsContext(app_identifier.origin()), app_identifier,
375 message.message_id,
376 /* was_encrypted= */ message.decrypted, std::string() /* error_message */,
377 message.decrypted ? message.raw_data : std::string());
378
379 if (IsPermissionSet(app_identifier.origin())) {
380 messages_pending_permission_check_.emplace(app_id, message);
381 // Start abusive origin verification only if no other verification is in
382 // progress.
383 if (!abusive_origin_revocation_request_)
384 CheckOriginForAbuseAndDispatchNextMessage();
385 } else {
386 // Drop message and unregister if origin has lost push permission.
387 DeliverMessageCallback(app_id, app_identifier.origin(),
388 app_identifier.service_worker_registration_id(),
389 message, message_handled_callback(),
390 blink::mojom::PushEventStatus::PERMISSION_DENIED);
391 }
392 }
393
CheckOriginForAbuseAndDispatchNextMessage()394 void PushMessagingServiceImpl::CheckOriginForAbuseAndDispatchNextMessage() {
395 if (messages_pending_permission_check_.empty())
396 return;
397
398 const std::string app_id =
399 std::move(messages_pending_permission_check_.front().app_id);
400 const gcm::IncomingMessage message =
401 std::move(messages_pending_permission_check_.front().message);
402 messages_pending_permission_check_.pop();
403
404 PushMessagingAppIdentifier app_identifier =
405 PushMessagingAppIdentifier::FindByAppId(profile_, app_id);
406
407 if (app_identifier.is_null()) {
408 CheckOriginForAbuseAndDispatchNextMessage();
409 return;
410 }
411
412 DCHECK(!abusive_origin_revocation_request_)
413 << "Create one Abusive Origin Revocation instance per request.";
414 abusive_origin_revocation_request_ =
415 std::make_unique<AbusiveOriginPermissionRevocationRequest>(
416 profile_, app_identifier.origin(),
417 base::BindOnce(&PushMessagingServiceImpl::OnCheckedOriginForAbuse,
418 weak_factory_.GetWeakPtr(), app_id, message));
419 }
420
OnCheckedOriginForAbuse(const std::string & app_id,const gcm::IncomingMessage & message,AbusiveOriginPermissionRevocationRequest::Outcome outcome)421 void PushMessagingServiceImpl::OnCheckedOriginForAbuse(
422 const std::string& app_id,
423 const gcm::IncomingMessage& message,
424 AbusiveOriginPermissionRevocationRequest::Outcome outcome) {
425 abusive_origin_revocation_request_.reset();
426
427 PushMessagingAppIdentifier app_identifier =
428 PushMessagingAppIdentifier::FindByAppId(profile_, app_id);
429
430 if (app_identifier.is_null()) {
431 CheckOriginForAbuseAndDispatchNextMessage();
432 return;
433 }
434
435 const GURL& origin = app_identifier.origin();
436 int64_t service_worker_registration_id =
437 app_identifier.service_worker_registration_id();
438
439 // It is possible that Notifications permission has been revoked by an user
440 // during abusive origin verification.
441 if (outcome == AbusiveOriginPermissionRevocationRequest::Outcome::
442 PERMISSION_NOT_REVOKED &&
443 IsPermissionSet(origin)) {
444 // The payload of a push message can be valid with content, valid with empty
445 // content, or null.
446 base::Optional<std::string> payload;
447 if (message.decrypted)
448 payload = message.raw_data;
449
450 // Dispatch the message to the appropriate Service Worker.
451 content::BrowserContext::DeliverPushMessage(
452 profile_, origin, service_worker_registration_id, message.message_id,
453 payload,
454 base::BindOnce(&PushMessagingServiceImpl::DeliverMessageCallback,
455 weak_factory_.GetWeakPtr(), app_id, origin,
456 service_worker_registration_id, message,
457 message_handled_callback()));
458
459 // Inform tests observing message dispatching about the event.
460 if (!message_dispatched_callback_for_testing_.is_null()) {
461 message_dispatched_callback_for_testing_.Run(
462 app_id, origin, service_worker_registration_id, std::move(payload));
463 }
464 } else {
465 // Drop message and unregister if origin has lost push permission.
466 DeliverMessageCallback(
467 app_id, app_identifier.origin(), service_worker_registration_id,
468 message, message_handled_callback(),
469 outcome == AbusiveOriginPermissionRevocationRequest::Outcome::
470 PERMISSION_NOT_REVOKED
471 ? blink::mojom::PushEventStatus::PERMISSION_DENIED
472 : blink::mojom::PushEventStatus::PERMISSION_REVOKED_ABUSIVE);
473 }
474
475 // Verify the next message in the queue.
476 CheckOriginForAbuseAndDispatchNextMessage();
477 }
478
DeliverMessageCallback(const std::string & app_id,const GURL & requesting_origin,int64_t service_worker_registration_id,const gcm::IncomingMessage & message,base::OnceClosure message_handled_closure,blink::mojom::PushEventStatus status)479 void PushMessagingServiceImpl::DeliverMessageCallback(
480 const std::string& app_id,
481 const GURL& requesting_origin,
482 int64_t service_worker_registration_id,
483 const gcm::IncomingMessage& message,
484 base::OnceClosure message_handled_closure,
485 blink::mojom::PushEventStatus status) {
486 DCHECK_GE(in_flight_message_deliveries_.count(app_id), 1u);
487
488 // Note: It's important that |message_handled_closure| is run or passed to
489 // another function before this function returns.
490
491 RecordDeliveryStatus(status);
492
493 // A reason to automatically unsubscribe. UNKNOWN means do not unsubscribe.
494 blink::mojom::PushUnregistrationReason unsubscribe_reason =
495 blink::mojom::PushUnregistrationReason::UNKNOWN;
496
497 // TODO(mvanouwerkerk): Show a warning in the developer console of the
498 // Service Worker corresponding to app_id (and/or on an internals page).
499 // See https://crbug.com/508516 for options.
500 switch (status) {
501 // Call EnforceUserVisibleOnlyRequirements if the message was delivered to
502 // the Service Worker JavaScript, even if the website's event handler failed
503 // (to prevent sites deliberately failing in order to avoid having to show
504 // notifications).
505 case blink::mojom::PushEventStatus::SUCCESS:
506 case blink::mojom::PushEventStatus::EVENT_WAITUNTIL_REJECTED:
507 case blink::mojom::PushEventStatus::TIMEOUT:
508 // Only enforce the user visible requirements if this is currently running
509 // as the delivery callback for the last in-flight message, and silent
510 // push has not been enabled through a command line flag.
511 if (in_flight_message_deliveries_.count(app_id) == 1 &&
512 !base::CommandLine::ForCurrentProcess()->HasSwitch(
513 switches::kAllowSilentPush)) {
514 notification_manager_.EnforceUserVisibleOnlyRequirements(
515 requesting_origin, service_worker_registration_id,
516 base::BindOnce(&PushMessagingServiceImpl::DidHandleMessage,
517 weak_factory_.GetWeakPtr(), app_id,
518 message.message_id,
519 std::move(message_handled_closure)));
520 }
521 break;
522 case blink::mojom::PushEventStatus::SERVICE_WORKER_ERROR:
523 // Do nothing, and hope the error is transient.
524 break;
525 case blink::mojom::PushEventStatus::UNKNOWN_APP_ID:
526 unsubscribe_reason =
527 blink::mojom::PushUnregistrationReason::DELIVERY_UNKNOWN_APP_ID;
528 break;
529 case blink::mojom::PushEventStatus::PERMISSION_DENIED:
530 unsubscribe_reason =
531 blink::mojom::PushUnregistrationReason::DELIVERY_PERMISSION_DENIED;
532 break;
533 case blink::mojom::PushEventStatus::NO_SERVICE_WORKER:
534 unsubscribe_reason =
535 blink::mojom::PushUnregistrationReason::DELIVERY_NO_SERVICE_WORKER;
536 break;
537 case blink::mojom::PushEventStatus::PERMISSION_REVOKED_ABUSIVE:
538 unsubscribe_reason =
539 blink::mojom::PushUnregistrationReason::PERMISSION_REVOKED_ABUSIVE;
540 break;
541 }
542
543 // If |message_handled_closure| was not yet used, make a |completion_closure|
544 // which should run by default at the end of this function, unless it is
545 // explicitly passed to another function or disabled.
546 base::ScopedClosureRunner completion_closure_runner(
547 message_handled_closure
548 ? base::BindOnce(&PushMessagingServiceImpl::DidHandleMessage,
549 weak_factory_.GetWeakPtr(), app_id,
550 message.message_id,
551 std::move(message_handled_closure),
552 false /* did_show_generic_notification */)
553 : base::DoNothing());
554
555 if (unsubscribe_reason != blink::mojom::PushUnregistrationReason::UNKNOWN) {
556 PushMessagingAppIdentifier app_identifier =
557 PushMessagingAppIdentifier::FindByAppId(profile_, app_id);
558 UnsubscribeInternal(
559 unsubscribe_reason,
560 app_identifier.is_null() ? GURL::EmptyGURL() : app_identifier.origin(),
561 app_identifier.is_null()
562 ? -1 /* kInvalidServiceWorkerRegistrationId */
563 : app_identifier.service_worker_registration_id(),
564 app_id, message.sender_id,
565 base::BindOnce(&UnregisterCallbackToClosure,
566 completion_closure_runner.Release()));
567
568 if (app_identifier.is_null())
569 return;
570
571 if (auto* devtools_context = GetDevToolsContext(app_identifier.origin())) {
572 std::stringstream ss;
573 ss << unsubscribe_reason;
574 devtools_context->LogBackgroundServiceEvent(
575 app_identifier.service_worker_registration_id(),
576 url::Origin::Create(app_identifier.origin()),
577 content::DevToolsBackgroundService::kPushMessaging,
578 "Unsubscribed due to error" /* event_name */, message.message_id,
579 {{"Reason", ss.str()}});
580 }
581 }
582 }
583
DidHandleMessage(const std::string & app_id,const std::string & push_message_id,base::OnceClosure message_handled_closure,bool did_show_generic_notification)584 void PushMessagingServiceImpl::DidHandleMessage(
585 const std::string& app_id,
586 const std::string& push_message_id,
587 base::OnceClosure message_handled_closure,
588 bool did_show_generic_notification) {
589 auto in_flight_iterator = in_flight_message_deliveries_.find(app_id);
590 DCHECK(in_flight_iterator != in_flight_message_deliveries_.end());
591
592 // Remove a single in-flight delivery for |app_id|. This has to be done using
593 // an iterator rather than by value, as the latter removes all entries.
594 in_flight_message_deliveries_.erase(in_flight_iterator);
595
596 #if BUILDFLAG(ENABLE_BACKGROUND_MODE)
597 // Reset before running callbacks below, so tests can verify keep-alive reset.
598 if (in_flight_message_deliveries_.empty())
599 in_flight_keep_alive_.reset();
600 #endif
601
602 std::move(message_handled_closure).Run();
603
604 #if defined(OS_ANDROID)
605 chrome::android::Java_PushMessagingServiceObserver_onMessageHandled(
606 base::android::AttachCurrentThread());
607 #endif
608
609 PushMessagingAppIdentifier app_identifier =
610 PushMessagingAppIdentifier::FindByAppId(profile_, app_id);
611
612 if (app_identifier.is_null() || !did_show_generic_notification)
613 return;
614
615 if (auto* devtools_context = GetDevToolsContext(app_identifier.origin())) {
616 devtools_context->LogBackgroundServiceEvent(
617 app_identifier.service_worker_registration_id(),
618 url::Origin::Create(app_identifier.origin()),
619 content::DevToolsBackgroundService::kPushMessaging,
620 "Generic notification shown" /* event_name */, push_message_id,
621 {} /* event_metadata */);
622 }
623 }
624
SetMessageCallbackForTesting(const base::Closure & callback)625 void PushMessagingServiceImpl::SetMessageCallbackForTesting(
626 const base::Closure& callback) {
627 message_callback_for_testing_ = callback;
628 }
629
630 // Other gcm::GCMAppHandler methods --------------------------------------------
631
OnMessagesDeleted(const std::string & app_id)632 void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) {
633 // TODO(mvanouwerkerk): Consider firing an event on the Service Worker
634 // corresponding to |app_id| to inform the app about deleted messages.
635 }
636
OnSendError(const std::string & app_id,const gcm::GCMClient::SendErrorDetails & send_error_details)637 void PushMessagingServiceImpl::OnSendError(
638 const std::string& app_id,
639 const gcm::GCMClient::SendErrorDetails& send_error_details) {
640 NOTREACHED() << "The Push API shouldn't have sent messages upstream";
641 }
642
OnSendAcknowledged(const std::string & app_id,const std::string & message_id)643 void PushMessagingServiceImpl::OnSendAcknowledged(
644 const std::string& app_id,
645 const std::string& message_id) {
646 NOTREACHED() << "The Push API shouldn't have sent messages upstream";
647 }
648
OnMessageDecryptionFailed(const std::string & app_id,const std::string & message_id,const std::string & error_message)649 void PushMessagingServiceImpl::OnMessageDecryptionFailed(
650 const std::string& app_id,
651 const std::string& message_id,
652 const std::string& error_message) {
653 PushMessagingAppIdentifier app_identifier =
654 PushMessagingAppIdentifier::FindByAppId(profile_, app_id);
655
656 if (app_identifier.is_null())
657 return;
658
659 LogMessageReceivedEventToDevTools(
660 GetDevToolsContext(app_identifier.origin()), app_identifier, message_id,
661 /* was_encrypted= */ true, error_message, "" /* payload */);
662 }
663
664 // Subscribe and GetPermissionStatus methods -----------------------------------
665
SubscribeFromDocument(const GURL & requesting_origin,int64_t service_worker_registration_id,int render_process_id,int render_frame_id,blink::mojom::PushSubscriptionOptionsPtr options,bool user_gesture,RegisterCallback callback)666 void PushMessagingServiceImpl::SubscribeFromDocument(
667 const GURL& requesting_origin,
668 int64_t service_worker_registration_id,
669 int render_process_id,
670 int render_frame_id,
671 blink::mojom::PushSubscriptionOptionsPtr options,
672 bool user_gesture,
673 RegisterCallback callback) {
674 PushMessagingAppIdentifier app_identifier =
675 PushMessagingAppIdentifier::FindByServiceWorker(
676 profile_, requesting_origin, service_worker_registration_id);
677
678 // If there is no existing app identifier for the given Service Worker,
679 // generate a new one. This will create a new subscription on the server.
680 if (app_identifier.is_null()) {
681 app_identifier = PushMessagingAppIdentifier::Generate(
682 requesting_origin, service_worker_registration_id);
683 }
684
685 if (push_subscription_count_ + pending_push_subscription_count_ >=
686 kMaxRegistrations) {
687 SubscribeEndWithError(std::move(callback),
688 blink::mojom::PushRegistrationStatus::LIMIT_REACHED);
689 return;
690 }
691
692 content::RenderFrameHost* render_frame_host =
693 content::RenderFrameHost::FromID(render_process_id, render_frame_id);
694
695 if (!render_frame_host) {
696 // It is possible for `render_frame_host` to be nullptr here due to a race
697 // (crbug.com/1057981).
698 SubscribeEndWithError(
699 std::move(callback),
700 blink::mojom::PushRegistrationStatus::RENDERER_SHUTDOWN);
701 return;
702 }
703
704 if (!options->user_visible_only) {
705 content::RenderFrameHost* main_frame =
706 GetMainFrameForRenderFrameHost(render_frame_host);
707
708 if (main_frame) {
709 main_frame->AddMessageToConsole(blink::mojom::ConsoleMessageLevel::kError,
710 kSilentPushUnsupportedMessage);
711 }
712
713 SubscribeEndWithError(
714 std::move(callback),
715 blink::mojom::PushRegistrationStatus::PERMISSION_DENIED);
716 return;
717 }
718
719 // Push does not allow permission requests from iframes.
720 PermissionManagerFactory::GetForProfile(profile_)->RequestPermission(
721 ContentSettingsType::NOTIFICATIONS, render_frame_host, requesting_origin,
722 user_gesture,
723 base::BindOnce(&PushMessagingServiceImpl::DoSubscribe,
724 weak_factory_.GetWeakPtr(), std::move(app_identifier),
725 std::move(options), std::move(callback), render_process_id,
726 render_frame_id));
727 }
728
SubscribeFromWorker(const GURL & requesting_origin,int64_t service_worker_registration_id,blink::mojom::PushSubscriptionOptionsPtr options,RegisterCallback register_callback)729 void PushMessagingServiceImpl::SubscribeFromWorker(
730 const GURL& requesting_origin,
731 int64_t service_worker_registration_id,
732 blink::mojom::PushSubscriptionOptionsPtr options,
733 RegisterCallback register_callback) {
734 PushMessagingAppIdentifier app_identifier =
735 PushMessagingAppIdentifier::FindByServiceWorker(
736 profile_, requesting_origin, service_worker_registration_id);
737
738 // If there is no existing app identifier for the given Service Worker,
739 // generate a new one. This will create a new subscription on the server.
740 if (app_identifier.is_null()) {
741 app_identifier = PushMessagingAppIdentifier::Generate(
742 requesting_origin, service_worker_registration_id);
743 }
744
745 if (push_subscription_count_ + pending_push_subscription_count_ >=
746 kMaxRegistrations) {
747 SubscribeEndWithError(std::move(register_callback),
748 blink::mojom::PushRegistrationStatus::LIMIT_REACHED);
749 return;
750 }
751
752 if (!IsPermissionSet(requesting_origin, options->user_visible_only)) {
753 SubscribeEndWithError(
754 std::move(register_callback),
755 blink::mojom::PushRegistrationStatus::PERMISSION_DENIED);
756 return;
757 }
758
759 DoSubscribe(std::move(app_identifier), std::move(options),
760 std::move(register_callback),
761 /* render_process_id= */ -1, /* render_frame_id= */ -1,
762 CONTENT_SETTING_ALLOW);
763 }
764
GetPermissionStatus(const GURL & origin,bool user_visible)765 blink::mojom::PermissionStatus PushMessagingServiceImpl::GetPermissionStatus(
766 const GURL& origin,
767 bool user_visible) {
768 if (!user_visible)
769 return blink::mojom::PermissionStatus::DENIED;
770
771 // Because the Push API is tied to Service Workers, many usages of the API
772 // won't have an embedding origin at all. Only consider the requesting
773 // |origin| when checking whether permission to use the API has been granted.
774 return ToPermissionStatus(
775 PermissionManagerFactory::GetForProfile(profile_)
776 ->GetPermissionStatus(ContentSettingsType::NOTIFICATIONS, origin,
777 origin)
778 .content_setting);
779 }
780
SupportNonVisibleMessages()781 bool PushMessagingServiceImpl::SupportNonVisibleMessages() {
782 return false;
783 }
784
DoSubscribe(PushMessagingAppIdentifier app_identifier,blink::mojom::PushSubscriptionOptionsPtr options,RegisterCallback register_callback,int render_process_id,int render_frame_id,ContentSetting content_setting)785 void PushMessagingServiceImpl::DoSubscribe(
786 PushMessagingAppIdentifier app_identifier,
787 blink::mojom::PushSubscriptionOptionsPtr options,
788 RegisterCallback register_callback,
789 int render_process_id,
790 int render_frame_id,
791 ContentSetting content_setting) {
792 if (content_setting != CONTENT_SETTING_ALLOW) {
793 SubscribeEndWithError(
794 std::move(register_callback),
795 blink::mojom::PushRegistrationStatus::PERMISSION_DENIED);
796 return;
797 }
798
799 std::string application_server_key_string(
800 options->application_server_key.begin(),
801 options->application_server_key.end());
802
803 // TODO(peter): Move this check to the renderer process & Mojo message
804 // validation once the flag is always enabled, and remove the
805 // |render_process_id| and |render_frame_id| parameters from this method.
806 if (!push_messaging::IsVapidKey(application_server_key_string)) {
807 content::RenderFrameHost* render_frame_host =
808 content::RenderFrameHost::FromID(render_process_id, render_frame_id);
809 content::RenderFrameHost* main_frame =
810 GetMainFrameForRenderFrameHost(render_frame_host);
811
812 if (base::FeatureList::IsEnabled(
813 features::kPushMessagingDisallowSenderIDs)) {
814 if (main_frame) {
815 main_frame->AddMessageToConsole(
816 blink::mojom::ConsoleMessageLevel::kError,
817 kSenderIdRegistrationDisallowedMessage);
818 }
819 SubscribeEndWithError(
820 std::move(register_callback),
821 blink::mojom::PushRegistrationStatus::UNSUPPORTED_GCM_SENDER_ID);
822 return;
823 } else if (main_frame) {
824 main_frame->AddMessageToConsole(
825 blink::mojom::ConsoleMessageLevel::kWarning,
826 kSenderIdRegistrationDeprecatedMessage);
827 }
828 }
829
830 IncreasePushSubscriptionCount(1, true /* is_pending */);
831
832 // Set time to live for GCM registration
833 base::TimeDelta ttl = base::TimeDelta();
834
835 if (base::FeatureList::IsEnabled(
836 features::kPushSubscriptionWithExpirationTime)) {
837 app_identifier.set_expiration_time(
838 base::Time::Now() + kPushSubscriptionExpirationPeriodTimeDelta);
839 DCHECK(app_identifier.expiration_time());
840 ttl = kPushSubscriptionExpirationPeriodTimeDelta;
841 }
842
843 GetInstanceIDDriver()
844 ->GetInstanceID(app_identifier.app_id())
845 ->GetToken(
846 push_messaging::NormalizeSenderInfo(application_server_key_string),
847 kGCMScope, ttl, std::map<std::string, std::string>() /* options */,
848 {} /* flags */,
849 base::BindOnce(&PushMessagingServiceImpl::DidSubscribe,
850 weak_factory_.GetWeakPtr(), app_identifier,
851 application_server_key_string,
852 std::move(register_callback)));
853 }
854
SubscribeEnd(RegisterCallback callback,const std::string & subscription_id,const GURL & endpoint,const base::Optional<base::Time> & expiration_time,const std::vector<uint8_t> & p256dh,const std::vector<uint8_t> & auth,blink::mojom::PushRegistrationStatus status)855 void PushMessagingServiceImpl::SubscribeEnd(
856 RegisterCallback callback,
857 const std::string& subscription_id,
858 const GURL& endpoint,
859 const base::Optional<base::Time>& expiration_time,
860 const std::vector<uint8_t>& p256dh,
861 const std::vector<uint8_t>& auth,
862 blink::mojom::PushRegistrationStatus status) {
863 std::move(callback).Run(subscription_id, endpoint, expiration_time, p256dh,
864 auth, status);
865 }
866
SubscribeEndWithError(RegisterCallback callback,blink::mojom::PushRegistrationStatus status)867 void PushMessagingServiceImpl::SubscribeEndWithError(
868 RegisterCallback callback,
869 blink::mojom::PushRegistrationStatus status) {
870 SubscribeEnd(std::move(callback), std::string() /* subscription_id */,
871 GURL::EmptyGURL() /* endpoint */,
872 base::nullopt /* expiration_time */,
873 std::vector<uint8_t>() /* p256dh */,
874 std::vector<uint8_t>() /* auth */, status);
875 }
876
DidSubscribe(const PushMessagingAppIdentifier & app_identifier,const std::string & sender_id,RegisterCallback callback,const std::string & subscription_id,InstanceID::Result result)877 void PushMessagingServiceImpl::DidSubscribe(
878 const PushMessagingAppIdentifier& app_identifier,
879 const std::string& sender_id,
880 RegisterCallback callback,
881 const std::string& subscription_id,
882 InstanceID::Result result) {
883 DecreasePushSubscriptionCount(1, true /* was_pending */);
884
885 blink::mojom::PushRegistrationStatus status =
886 blink::mojom::PushRegistrationStatus::SERVICE_ERROR;
887
888 switch (result) {
889 case InstanceID::SUCCESS: {
890 const GURL endpoint = push_messaging::CreateEndpoint(subscription_id);
891
892 // Make sure that this subscription has associated encryption keys prior
893 // to returning it to the developer - they'll need this information in
894 // order to send payloads to the user.
895 GetEncryptionInfoForAppId(
896 app_identifier.app_id(), sender_id,
897 base::BindOnce(
898 &PushMessagingServiceImpl::DidSubscribeWithEncryptionInfo,
899 weak_factory_.GetWeakPtr(), app_identifier, std::move(callback),
900 subscription_id, endpoint));
901 return;
902 }
903 case InstanceID::INVALID_PARAMETER:
904 case InstanceID::DISABLED:
905 case InstanceID::ASYNC_OPERATION_PENDING:
906 case InstanceID::SERVER_ERROR:
907 case InstanceID::UNKNOWN_ERROR:
908 DLOG(ERROR) << "Push messaging subscription failed; InstanceID::Result = "
909 << result;
910 status = blink::mojom::PushRegistrationStatus::SERVICE_ERROR;
911 break;
912 case InstanceID::NETWORK_ERROR:
913 status = blink::mojom::PushRegistrationStatus::NETWORK_ERROR;
914 break;
915 }
916
917 SubscribeEndWithError(std::move(callback), status);
918 }
919
DidSubscribeWithEncryptionInfo(const PushMessagingAppIdentifier & app_identifier,RegisterCallback callback,const std::string & subscription_id,const GURL & endpoint,std::string p256dh,std::string auth_secret)920 void PushMessagingServiceImpl::DidSubscribeWithEncryptionInfo(
921 const PushMessagingAppIdentifier& app_identifier,
922 RegisterCallback callback,
923 const std::string& subscription_id,
924 const GURL& endpoint,
925 std::string p256dh,
926 std::string auth_secret) {
927 if (p256dh.empty()) {
928 SubscribeEndWithError(
929 std::move(callback),
930 blink::mojom::PushRegistrationStatus::PUBLIC_KEY_UNAVAILABLE);
931 return;
932 }
933
934 app_identifier.PersistToPrefs(profile_);
935
936 IncreasePushSubscriptionCount(1, false /* is_pending */);
937
938 SubscribeEnd(std::move(callback), subscription_id, endpoint,
939 app_identifier.expiration_time(),
940 std::vector<uint8_t>(p256dh.begin(), p256dh.end()),
941 std::vector<uint8_t>(auth_secret.begin(), auth_secret.end()),
942 blink::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE);
943 }
944
945 // GetSubscriptionInfo methods -------------------------------------------------
946
GetSubscriptionInfo(const GURL & origin,int64_t service_worker_registration_id,const std::string & sender_id,const std::string & subscription_id,SubscriptionInfoCallback callback)947 void PushMessagingServiceImpl::GetSubscriptionInfo(
948 const GURL& origin,
949 int64_t service_worker_registration_id,
950 const std::string& sender_id,
951 const std::string& subscription_id,
952 SubscriptionInfoCallback callback) {
953 PushMessagingAppIdentifier app_identifier =
954 PushMessagingAppIdentifier::FindByServiceWorker(
955 profile_, origin, service_worker_registration_id);
956
957 if (app_identifier.is_null()) {
958 std::move(callback).Run(
959 false /* is_valid */, GURL::EmptyGURL() /*endpoint*/,
960 base::nullopt /* expiration_time */,
961 std::vector<uint8_t>() /* p256dh */, std::vector<uint8_t>() /* auth */);
962 return;
963 }
964
965 const GURL endpoint = push_messaging::CreateEndpoint(subscription_id);
966 const std::string& app_id = app_identifier.app_id();
967 base::Optional<base::Time> expiration_time = app_identifier.expiration_time();
968
969 base::OnceCallback<void(bool)> validate_cb =
970 base::BindOnce(&PushMessagingServiceImpl::DidValidateSubscription,
971 weak_factory_.GetWeakPtr(), app_id, sender_id, endpoint,
972 expiration_time, std::move(callback));
973
974 if (PushMessagingAppIdentifier::UseInstanceID(app_id)) {
975 GetInstanceIDDriver()->GetInstanceID(app_id)->ValidateToken(
976 push_messaging::NormalizeSenderInfo(sender_id), kGCMScope,
977 subscription_id, std::move(validate_cb));
978 } else {
979 GetGCMDriver()->ValidateRegistration(
980 app_id, {push_messaging::NormalizeSenderInfo(sender_id)},
981 subscription_id, std::move(validate_cb));
982 }
983 }
984
DidValidateSubscription(const std::string & app_id,const std::string & sender_id,const GURL & endpoint,const base::Optional<base::Time> & expiration_time,SubscriptionInfoCallback callback,bool is_valid)985 void PushMessagingServiceImpl::DidValidateSubscription(
986 const std::string& app_id,
987 const std::string& sender_id,
988 const GURL& endpoint,
989 const base::Optional<base::Time>& expiration_time,
990 SubscriptionInfoCallback callback,
991 bool is_valid) {
992 if (!is_valid) {
993 std::move(callback).Run(
994 false /* is_valid */, GURL::EmptyGURL() /* endpoint */,
995 base::nullopt /* expiration_time */,
996 std::vector<uint8_t>() /* p256dh */, std::vector<uint8_t>() /* auth */);
997 return;
998 }
999
1000 GetEncryptionInfoForAppId(
1001 app_id, sender_id,
1002 base::BindOnce(&PushMessagingServiceImpl::DidGetEncryptionInfo,
1003 weak_factory_.GetWeakPtr(), endpoint, expiration_time,
1004 std::move(callback)));
1005 }
1006
DidGetEncryptionInfo(const GURL & endpoint,const base::Optional<base::Time> & expiration_time,SubscriptionInfoCallback callback,std::string p256dh,std::string auth_secret) const1007 void PushMessagingServiceImpl::DidGetEncryptionInfo(
1008 const GURL& endpoint,
1009 const base::Optional<base::Time>& expiration_time,
1010 SubscriptionInfoCallback callback,
1011 std::string p256dh,
1012 std::string auth_secret) const {
1013 // I/O errors might prevent the GCM Driver from retrieving a key-pair.
1014 bool is_valid = !p256dh.empty();
1015 std::move(callback).Run(
1016 is_valid, endpoint, expiration_time,
1017 std::vector<uint8_t>(p256dh.begin(), p256dh.end()),
1018 std::vector<uint8_t>(auth_secret.begin(), auth_secret.end()));
1019 }
1020
1021 // Unsubscribe methods ---------------------------------------------------------
1022
Unsubscribe(blink::mojom::PushUnregistrationReason reason,const GURL & requesting_origin,int64_t service_worker_registration_id,const std::string & sender_id,UnregisterCallback callback)1023 void PushMessagingServiceImpl::Unsubscribe(
1024 blink::mojom::PushUnregistrationReason reason,
1025 const GURL& requesting_origin,
1026 int64_t service_worker_registration_id,
1027 const std::string& sender_id,
1028 UnregisterCallback callback) {
1029 PushMessagingAppIdentifier app_identifier =
1030 PushMessagingAppIdentifier::FindByServiceWorker(
1031 profile_, requesting_origin, service_worker_registration_id);
1032
1033 UnsubscribeInternal(
1034 reason, requesting_origin, service_worker_registration_id,
1035 app_identifier.is_null() ? std::string() : app_identifier.app_id(),
1036 sender_id, std::move(callback));
1037 }
1038
UnsubscribeInternal(blink::mojom::PushUnregistrationReason reason,const GURL & origin,int64_t service_worker_registration_id,const std::string & app_id,const std::string & sender_id,UnregisterCallback callback)1039 void PushMessagingServiceImpl::UnsubscribeInternal(
1040 blink::mojom::PushUnregistrationReason reason,
1041 const GURL& origin,
1042 int64_t service_worker_registration_id,
1043 const std::string& app_id,
1044 const std::string& sender_id,
1045 UnregisterCallback callback) {
1046 DCHECK(!app_id.empty() || (!origin.is_empty() &&
1047 service_worker_registration_id !=
1048 -1 /* kInvalidServiceWorkerRegistrationId */))
1049 << "Need an app_id and/or origin+service_worker_registration_id";
1050
1051 RecordUnsubscribeReason(reason);
1052
1053 if (origin.is_empty() ||
1054 service_worker_registration_id ==
1055 -1 /* kInvalidServiceWorkerRegistrationId */) {
1056 // Can't clear Service Worker database.
1057 DidClearPushSubscriptionId(reason, app_id, sender_id, std::move(callback));
1058 return;
1059 }
1060 ClearPushSubscriptionId(
1061 profile_, origin, service_worker_registration_id,
1062 base::BindOnce(&PushMessagingServiceImpl::DidClearPushSubscriptionId,
1063 weak_factory_.GetWeakPtr(), reason, app_id, sender_id,
1064 std::move(callback)));
1065 }
1066
DidClearPushSubscriptionId(blink::mojom::PushUnregistrationReason reason,const std::string & app_id,const std::string & sender_id,UnregisterCallback callback)1067 void PushMessagingServiceImpl::DidClearPushSubscriptionId(
1068 blink::mojom::PushUnregistrationReason reason,
1069 const std::string& app_id,
1070 const std::string& sender_id,
1071 UnregisterCallback callback) {
1072 if (app_id.empty()) {
1073 // Without an |app_id|, we can neither delete the subscription from the
1074 // PushMessagingAppIdentifier map, nor unsubscribe with the GCM Driver.
1075 std::move(callback).Run(
1076 blink::mojom::PushUnregistrationStatus::SUCCESS_WAS_NOT_REGISTERED);
1077 return;
1078 }
1079
1080 // Delete the mapping for this app_id, to guarantee that no messages get
1081 // delivered in future (even if unregistration fails).
1082 // TODO(johnme): Instead of deleting these app ids, store them elsewhere, and
1083 // retry unregistration if it fails due to network errors (crbug.com/465399).
1084 PushMessagingAppIdentifier app_identifier =
1085 PushMessagingAppIdentifier::FindByAppId(profile_, app_id);
1086 bool was_subscribed = !app_identifier.is_null();
1087 if (was_subscribed)
1088 app_identifier.DeleteFromPrefs(profile_);
1089
1090 // Run the unsubscribe callback *before* asking the InstanceIDDriver/GCMDriver
1091 // to unsubscribe, since that's a slow process involving network retries, and
1092 // by this point enough local state has been deleted that the subscription is
1093 // inactive. Note that DeliverMessageCallback automatically unsubscribes if
1094 // messages are later received for a subscription that was locally deleted,
1095 // so as long as messages keep getting sent to it, the unsubscription should
1096 // eventually reach GCM servers even if this particular attempt fails.
1097 std::move(callback).Run(
1098 was_subscribed
1099 ? blink::mojom::PushUnregistrationStatus::SUCCESS_UNREGISTERED
1100 : blink::mojom::PushUnregistrationStatus::SUCCESS_WAS_NOT_REGISTERED);
1101
1102 if (PushMessagingAppIdentifier::UseInstanceID(app_id)) {
1103 GetInstanceIDDriver()->GetInstanceID(app_id)->DeleteID(
1104 base::BindOnce(&PushMessagingServiceImpl::DidDeleteID,
1105 weak_factory_.GetWeakPtr(), app_id, was_subscribed));
1106
1107 } else {
1108 auto unregister_callback =
1109 base::BindOnce(&PushMessagingServiceImpl::DidUnregister,
1110 weak_factory_.GetWeakPtr(), was_subscribed);
1111 #if defined(OS_ANDROID)
1112 // On Android the backend is different, and requires the original sender_id.
1113 // DidGetSenderIdUnexpectedUnsubscribe and
1114 // DidDeleteServiceWorkerRegistration sometimes call us with an empty one.
1115 if (sender_id.empty()) {
1116 std::move(unregister_callback).Run(gcm::GCMClient::INVALID_PARAMETER);
1117 } else {
1118 GetGCMDriver()->UnregisterWithSenderId(
1119 app_id, push_messaging::NormalizeSenderInfo(sender_id),
1120 std::move(unregister_callback));
1121 }
1122 #else
1123 GetGCMDriver()->Unregister(app_id, std::move(unregister_callback));
1124 #endif
1125 }
1126 }
1127
DidUnregister(bool was_subscribed,gcm::GCMClient::Result result)1128 void PushMessagingServiceImpl::DidUnregister(bool was_subscribed,
1129 gcm::GCMClient::Result result) {
1130 RecordUnsubscribeGCMResult(result);
1131 DidUnsubscribe(std::string() /* app_id_when_instance_id */, was_subscribed);
1132 }
1133
DidDeleteID(const std::string & app_id,bool was_subscribed,InstanceID::Result result)1134 void PushMessagingServiceImpl::DidDeleteID(const std::string& app_id,
1135 bool was_subscribed,
1136 InstanceID::Result result) {
1137 RecordUnsubscribeIIDResult(result);
1138 // DidUnsubscribe must be run asynchronously when passing a non-empty
1139 // |app_id_when_instance_id|, since it calls
1140 // InstanceIDDriver::RemoveInstanceID which deletes the InstanceID itself.
1141 // Calling that immediately would cause a use-after-free in our caller.
1142 base::ThreadTaskRunnerHandle::Get()->PostTask(
1143 FROM_HERE,
1144 base::BindOnce(&PushMessagingServiceImpl::DidUnsubscribe,
1145 weak_factory_.GetWeakPtr(), app_id, was_subscribed));
1146 }
1147
DidUnsubscribe(const std::string & app_id_when_instance_id,bool was_subscribed)1148 void PushMessagingServiceImpl::DidUnsubscribe(
1149 const std::string& app_id_when_instance_id,
1150 bool was_subscribed) {
1151 if (!app_id_when_instance_id.empty())
1152 GetInstanceIDDriver()->RemoveInstanceID(app_id_when_instance_id);
1153
1154 if (was_subscribed)
1155 DecreasePushSubscriptionCount(1, false /* was_pending */);
1156
1157 if (!unsubscribe_callback_for_testing_.is_null())
1158 unsubscribe_callback_for_testing_.Run();
1159 }
1160
SetUnsubscribeCallbackForTesting(const base::Closure & callback)1161 void PushMessagingServiceImpl::SetUnsubscribeCallbackForTesting(
1162 const base::Closure& callback) {
1163 unsubscribe_callback_for_testing_ = callback;
1164 }
1165
1166 // DidDeleteServiceWorkerRegistration methods ----------------------------------
1167
DidDeleteServiceWorkerRegistration(const GURL & origin,int64_t service_worker_registration_id)1168 void PushMessagingServiceImpl::DidDeleteServiceWorkerRegistration(
1169 const GURL& origin,
1170 int64_t service_worker_registration_id) {
1171 const PushMessagingAppIdentifier& app_identifier =
1172 PushMessagingAppIdentifier::FindByServiceWorker(
1173 profile_, origin, service_worker_registration_id);
1174 if (app_identifier.is_null()) {
1175 if (!service_worker_unregistered_callback_for_testing_.is_null())
1176 service_worker_unregistered_callback_for_testing_.Run();
1177 return;
1178 }
1179 // Note this will not fully unsubscribe pre-InstanceID subscriptions on
1180 // Android from GCM, as that requires a sender_id. (Ideally we'd fetch it
1181 // from the SWDB in some "before_unregistered" SWObserver event.)
1182 UnsubscribeInternal(
1183 blink::mojom::PushUnregistrationReason::SERVICE_WORKER_UNREGISTERED,
1184 origin, service_worker_registration_id, app_identifier.app_id(),
1185 std::string() /* sender_id */,
1186 base::BindOnce(&UnregisterCallbackToClosure,
1187 service_worker_unregistered_callback_for_testing_.is_null()
1188 ? base::DoNothing()
1189 : service_worker_unregistered_callback_for_testing_));
1190 }
1191
SetServiceWorkerUnregisteredCallbackForTesting(base::RepeatingClosure callback)1192 void PushMessagingServiceImpl::SetServiceWorkerUnregisteredCallbackForTesting(
1193 base::RepeatingClosure callback) {
1194 service_worker_unregistered_callback_for_testing_ = std::move(callback);
1195 }
1196
1197 // DidDeleteServiceWorkerDatabase methods --------------------------------------
1198
DidDeleteServiceWorkerDatabase()1199 void PushMessagingServiceImpl::DidDeleteServiceWorkerDatabase() {
1200 std::vector<PushMessagingAppIdentifier> app_identifiers =
1201 PushMessagingAppIdentifier::GetAll(profile_);
1202
1203 base::RepeatingClosure completed_closure = base::BarrierClosure(
1204 app_identifiers.size(),
1205 service_worker_database_wiped_callback_for_testing_.is_null()
1206 ? base::DoNothing()
1207 : service_worker_database_wiped_callback_for_testing_);
1208
1209 for (const PushMessagingAppIdentifier& app_identifier : app_identifiers) {
1210 // Note this will not fully unsubscribe pre-InstanceID subscriptions on
1211 // Android from GCM, as that requires a sender_id. We can't fetch those from
1212 // the Service Worker database anymore as it's been deleted.
1213 UnsubscribeInternal(
1214 blink::mojom::PushUnregistrationReason::SERVICE_WORKER_DATABASE_WIPED,
1215 app_identifier.origin(),
1216 app_identifier.service_worker_registration_id(),
1217 app_identifier.app_id(), std::string() /* sender_id */,
1218 base::BindOnce(&UnregisterCallbackToClosure, completed_closure));
1219 }
1220 }
1221
SetServiceWorkerDatabaseWipedCallbackForTesting(base::RepeatingClosure callback)1222 void PushMessagingServiceImpl::SetServiceWorkerDatabaseWipedCallbackForTesting(
1223 base::RepeatingClosure callback) {
1224 service_worker_database_wiped_callback_for_testing_ = std::move(callback);
1225 }
1226
1227 // OnContentSettingChanged methods ---------------------------------------------
1228
OnContentSettingChanged(const ContentSettingsPattern & primary_pattern,const ContentSettingsPattern & secondary_pattern,ContentSettingsType content_type)1229 void PushMessagingServiceImpl::OnContentSettingChanged(
1230 const ContentSettingsPattern& primary_pattern,
1231 const ContentSettingsPattern& secondary_pattern,
1232 ContentSettingsType content_type) {
1233 if (content_type != ContentSettingsType::NOTIFICATIONS)
1234 return;
1235
1236 std::vector<PushMessagingAppIdentifier> all_app_identifiers =
1237 PushMessagingAppIdentifier::GetAll(profile_);
1238
1239 base::RepeatingClosure barrier_closure = base::BarrierClosure(
1240 all_app_identifiers.size(),
1241 content_setting_changed_callback_for_testing_.is_null()
1242 ? base::DoNothing()
1243 : content_setting_changed_callback_for_testing_);
1244
1245 for (const PushMessagingAppIdentifier& app_identifier : all_app_identifiers) {
1246 // If |primary_pattern| is not valid, we should always check for a
1247 // permission change because it can happen for example when the entire
1248 // Push or Notifications permissions are cleared.
1249 // Otherwise, the permission should be checked if the pattern matches the
1250 // origin.
1251 if (primary_pattern.IsValid() &&
1252 !primary_pattern.Matches(app_identifier.origin())) {
1253 barrier_closure.Run();
1254 continue;
1255 }
1256
1257 if (IsPermissionSet(app_identifier.origin())) {
1258 barrier_closure.Run();
1259 continue;
1260 }
1261
1262 UnexpectedChange(app_identifier,
1263 blink::mojom::PushUnregistrationReason::PERMISSION_REVOKED,
1264 barrier_closure);
1265 }
1266 }
1267
UnexpectedUnsubscribe(const PushMessagingAppIdentifier & app_identifier,blink::mojom::PushUnregistrationReason reason,UnregisterCallback unregister_callback)1268 void PushMessagingServiceImpl::UnexpectedUnsubscribe(
1269 const PushMessagingAppIdentifier& app_identifier,
1270 blink::mojom::PushUnregistrationReason reason,
1271 UnregisterCallback unregister_callback) {
1272 // When `pushsubscriptionchange` is supported by default, get |sender_id| from
1273 // GetPushSubscriptionFromAppIdentifier callback and do not get the info from
1274 // IO twice
1275 bool need_sender_id = false;
1276 #if defined(OS_ANDROID)
1277 need_sender_id =
1278 !PushMessagingAppIdentifier::UseInstanceID(app_identifier.app_id());
1279 #endif
1280 if (need_sender_id) {
1281 GetSenderId(
1282 profile_, app_identifier.origin(),
1283 app_identifier.service_worker_registration_id(),
1284 base::BindOnce(
1285 &PushMessagingServiceImpl::DidGetSenderIdUnexpectedUnsubscribe,
1286 weak_factory_.GetWeakPtr(), app_identifier, reason,
1287 std::move(unregister_callback)));
1288 } else {
1289 UnsubscribeInternal(reason, app_identifier.origin(),
1290 app_identifier.service_worker_registration_id(),
1291 app_identifier.app_id(),
1292 std::string() /* sender_id */,
1293 std::move(unregister_callback));
1294 }
1295 }
1296
GetPushSubscriptionFromAppIdentifier(const PushMessagingAppIdentifier & app_identifier,base::OnceCallback<void (blink::mojom::PushSubscriptionPtr)> subscription_cb)1297 void PushMessagingServiceImpl::GetPushSubscriptionFromAppIdentifier(
1298 const PushMessagingAppIdentifier& app_identifier,
1299 base::OnceCallback<void(blink::mojom::PushSubscriptionPtr)>
1300 subscription_cb) {
1301 GetSWData(profile_, app_identifier.origin(),
1302 app_identifier.service_worker_registration_id(),
1303 base::BindOnce(&PushMessagingServiceImpl::DidGetSWData,
1304 weak_factory_.GetWeakPtr(), app_identifier,
1305 std::move(subscription_cb)));
1306 }
1307
DidGetSWData(const PushMessagingAppIdentifier & app_identifier,base::OnceCallback<void (blink::mojom::PushSubscriptionPtr)> subscription_cb,const std::string & sender_id,const std::string & subscription_id)1308 void PushMessagingServiceImpl::DidGetSWData(
1309 const PushMessagingAppIdentifier& app_identifier,
1310 base::OnceCallback<void(blink::mojom::PushSubscriptionPtr)> subscription_cb,
1311 const std::string& sender_id,
1312 const std::string& subscription_id) {
1313 // SW Database was corrupted, return immediately
1314 if (sender_id.empty() || subscription_id.empty()) {
1315 std::move(subscription_cb).Run(nullptr /* subscription */);
1316 return;
1317 }
1318 GetSubscriptionInfo(
1319 app_identifier.origin(), app_identifier.service_worker_registration_id(),
1320 sender_id, subscription_id,
1321 base::BindOnce(
1322 &PushMessagingServiceImpl::GetPushSubscriptionFromAppIdentifierEnd,
1323 weak_factory_.GetWeakPtr(), std::move(subscription_cb), sender_id));
1324 }
1325
GetPushSubscriptionFromAppIdentifierEnd(base::OnceCallback<void (blink::mojom::PushSubscriptionPtr)> callback,const std::string & sender_id,bool is_valid,const GURL & endpoint,const base::Optional<base::Time> & expiration_time,const std::vector<uint8_t> & p256dh,const std::vector<uint8_t> & auth)1326 void PushMessagingServiceImpl::GetPushSubscriptionFromAppIdentifierEnd(
1327 base::OnceCallback<void(blink::mojom::PushSubscriptionPtr)> callback,
1328 const std::string& sender_id,
1329 bool is_valid,
1330 const GURL& endpoint,
1331 const base::Optional<base::Time>& expiration_time,
1332 const std::vector<uint8_t>& p256dh,
1333 const std::vector<uint8_t>& auth) {
1334 if (!is_valid) {
1335 // TODO(viviy): Log error in UMA
1336 std::move(callback).Run(nullptr /* subscription */);
1337 return;
1338 }
1339
1340 std::move(callback).Run(blink::mojom::PushSubscription::New(
1341 endpoint, expiration_time, push_messaging::MakeOptions(sender_id), p256dh,
1342 auth));
1343 }
1344
FirePushSubscriptionChange(const PushMessagingAppIdentifier & app_identifier,base::OnceClosure completed_closure,blink::mojom::PushSubscriptionPtr new_subscription,blink::mojom::PushSubscriptionPtr old_subscription)1345 void PushMessagingServiceImpl::FirePushSubscriptionChange(
1346 const PushMessagingAppIdentifier& app_identifier,
1347 base::OnceClosure completed_closure,
1348 blink::mojom::PushSubscriptionPtr new_subscription,
1349 blink::mojom::PushSubscriptionPtr old_subscription) {
1350 // Ensure |completed_closure| is run after this function
1351 base::ScopedClosureRunner scoped_closure(std::move(completed_closure));
1352
1353 if (!base::FeatureList::IsEnabled(features::kPushSubscriptionChangeEvent))
1354 return;
1355
1356 if (app_identifier.is_null()) {
1357 FirePushSubscriptionChangeCallback(
1358 app_identifier, blink::mojom::PushEventStatus::UNKNOWN_APP_ID);
1359 return;
1360 }
1361
1362 content::BrowserContext::FirePushSubscriptionChangeEvent(
1363 profile_, app_identifier.origin(),
1364 app_identifier.service_worker_registration_id(),
1365 std::move(new_subscription), std::move(old_subscription),
1366 base::BindOnce(
1367 &PushMessagingServiceImpl::FirePushSubscriptionChangeCallback,
1368 weak_factory_.GetWeakPtr(), app_identifier));
1369 }
1370
FirePushSubscriptionChangeCallback(const PushMessagingAppIdentifier & app_identifier,blink::mojom::PushEventStatus status)1371 void PushMessagingServiceImpl::FirePushSubscriptionChangeCallback(
1372 const PushMessagingAppIdentifier& app_identifier,
1373 blink::mojom::PushEventStatus status) {
1374 // Log Data in UMA
1375 RecordPushSubcriptionChangeStatus(status);
1376 }
1377
DidGetSenderIdUnexpectedUnsubscribe(const PushMessagingAppIdentifier & app_identifier,blink::mojom::PushUnregistrationReason reason,UnregisterCallback callback,const std::string & sender_id)1378 void PushMessagingServiceImpl::DidGetSenderIdUnexpectedUnsubscribe(
1379 const PushMessagingAppIdentifier& app_identifier,
1380 blink::mojom::PushUnregistrationReason reason,
1381 UnregisterCallback callback,
1382 const std::string& sender_id) {
1383 // Unsubscribe the PushMessagingAppIdentifier with the push service.
1384 // It's possible for GetSenderId to have failed and sender_id to be empty, if
1385 // cookies (and the SW database) for an origin got cleared before permissions
1386 // are cleared for the origin. In that case for legacy GCM registrations on
1387 // Android, Unsubscribe will just delete the app identifier to block future
1388 // messages.
1389 // TODO(johnme): Auto-unregister before SW DB is cleared (crbug.com/402458).
1390 UnsubscribeInternal(reason, app_identifier.origin(),
1391 app_identifier.service_worker_registration_id(),
1392 app_identifier.app_id(), sender_id, std::move(callback));
1393 }
1394
SetContentSettingChangedCallbackForTesting(base::RepeatingClosure callback)1395 void PushMessagingServiceImpl::SetContentSettingChangedCallbackForTesting(
1396 base::RepeatingClosure callback) {
1397 content_setting_changed_callback_for_testing_ = std::move(callback);
1398 }
1399
1400 // KeyedService methods -------------------------------------------------------
1401
Shutdown()1402 void PushMessagingServiceImpl::Shutdown() {
1403 GetGCMDriver()->RemoveAppHandler(kPushMessagingAppIdentifierPrefix);
1404 HostContentSettingsMapFactory::GetForProfile(profile_)->RemoveObserver(this);
1405 }
1406
1407 // content::NotificationObserver methods ---------------------------------------
1408
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)1409 void PushMessagingServiceImpl::Observe(
1410 int type,
1411 const content::NotificationSource& source,
1412 const content::NotificationDetails& details) {
1413 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
1414 shutdown_started_ = true;
1415 #if BUILDFLAG(ENABLE_BACKGROUND_MODE)
1416 in_flight_keep_alive_.reset();
1417 #endif // BUILDFLAG(ENABLE_BACKGROUND_MODE)
1418 }
1419
1420 // OnSubscriptionInvalidation methods ------------------------------------------
1421
OnSubscriptionInvalidation(const std::string & app_id)1422 void PushMessagingServiceImpl::OnSubscriptionInvalidation(
1423 const std::string& app_id) {
1424 DCHECK(base::FeatureList::IsEnabled(features::kPushSubscriptionChangeEvent))
1425 << "It is not allowed to call this method when "
1426 "features::kPushSubscriptionChangeEvent is disabled.";
1427 PushMessagingAppIdentifier old_app_identifier =
1428 PushMessagingAppIdentifier::FindByAppId(profile_, app_id);
1429 if (old_app_identifier.is_null())
1430 return;
1431
1432 GetSenderId(profile_, old_app_identifier.origin(),
1433 old_app_identifier.service_worker_registration_id(),
1434 base::BindOnce(&PushMessagingServiceImpl::GetOldSubscription,
1435 weak_factory_.GetWeakPtr(), old_app_identifier));
1436 }
1437
GetOldSubscription(PushMessagingAppIdentifier old_app_identifier,const std::string & sender_id)1438 void PushMessagingServiceImpl::GetOldSubscription(
1439 PushMessagingAppIdentifier old_app_identifier,
1440 const std::string& sender_id) {
1441 GetPushSubscriptionFromAppIdentifier(
1442 old_app_identifier,
1443 base::BindOnce(&PushMessagingServiceImpl::StartRefresh,
1444 weak_factory_.GetWeakPtr(), old_app_identifier,
1445 sender_id));
1446 }
1447
StartRefresh(PushMessagingAppIdentifier old_app_identifier,const std::string & sender_id,blink::mojom::PushSubscriptionPtr old_subscription)1448 void PushMessagingServiceImpl::StartRefresh(
1449 PushMessagingAppIdentifier old_app_identifier,
1450 const std::string& sender_id,
1451 blink::mojom::PushSubscriptionPtr old_subscription) {
1452 // Generate a new app_identifier with the same information, but a different
1453 // app_id. Expiration time will be overwritten by DoSubscribe, if the flag
1454 // features::kPushSubscriptionWithExpiration time is enabled
1455 PushMessagingAppIdentifier new_app_identifier =
1456 PushMessagingAppIdentifier::Generate(
1457 old_app_identifier.origin(),
1458 old_app_identifier.service_worker_registration_id(),
1459 base::nullopt /* expiration_time */);
1460
1461 refresher_.Refresh(old_app_identifier, new_app_identifier.app_id(),
1462 sender_id);
1463
1464 UpdateSubscription(
1465 new_app_identifier, push_messaging::MakeOptions(sender_id),
1466 base::BindOnce(&PushMessagingServiceImpl::DidUpdateSubscription,
1467 weak_factory_.GetWeakPtr(), new_app_identifier.app_id(),
1468 old_app_identifier.app_id(), std::move(old_subscription),
1469 sender_id));
1470 }
1471
UpdateSubscription(PushMessagingAppIdentifier app_identifier,blink::mojom::PushSubscriptionOptionsPtr options,RegisterCallback callback)1472 void PushMessagingServiceImpl::UpdateSubscription(
1473 PushMessagingAppIdentifier app_identifier,
1474 blink::mojom::PushSubscriptionOptionsPtr options,
1475 RegisterCallback callback) {
1476 // After getting a new GCM registration, update the |subscription_id| in SW
1477 // database before running the callback
1478 auto register_callback = base::BindOnce(
1479 [](RegisterCallback cb, Profile* profile, PushMessagingAppIdentifier ai,
1480 const std::string& registration_id, const GURL& endpoint,
1481 const base::Optional<base::Time>& expiration_time,
1482 const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& auth,
1483 blink::mojom::PushRegistrationStatus status) {
1484 base::OnceClosure closure =
1485 base::BindOnce(std::move(cb), registration_id, endpoint,
1486 expiration_time, p256dh, auth, status);
1487 base::ScopedClosureRunner closure_runner(std::move(closure));
1488 if (status ==
1489 blink::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE) {
1490 UpdatePushSubscriptionId(profile, ai.origin(),
1491 ai.service_worker_registration_id(),
1492 registration_id, closure_runner.Release());
1493 }
1494 },
1495 std::move(callback), profile_, app_identifier);
1496 // Subscribe using the new subscription information, this will overwrite
1497 // the expiration time of |app_identifier|
1498 DoSubscribe(app_identifier, std::move(options), std::move(register_callback),
1499 -1 /* render_process_id */, -1 /* render_frame_id */,
1500 CONTENT_SETTING_ALLOW);
1501 }
1502
DidUpdateSubscription(const std::string & new_app_id,const std::string & old_app_id,blink::mojom::PushSubscriptionPtr old_subscription,const std::string & sender_id,const std::string & registration_id,const GURL & endpoint,const base::Optional<base::Time> & expiration_time,const std::vector<uint8_t> & p256dh,const std::vector<uint8_t> & auth,blink::mojom::PushRegistrationStatus status)1503 void PushMessagingServiceImpl::DidUpdateSubscription(
1504 const std::string& new_app_id,
1505 const std::string& old_app_id,
1506 blink::mojom::PushSubscriptionPtr old_subscription,
1507 const std::string& sender_id,
1508 const std::string& registration_id,
1509 const GURL& endpoint,
1510 const base::Optional<base::Time>& expiration_time,
1511 const std::vector<uint8_t>& p256dh,
1512 const std::vector<uint8_t>& auth,
1513 blink::mojom::PushRegistrationStatus status) {
1514 // TODO(crbug.com/1122545): Currently, if |status| is unsuccessful, the old
1515 // subscription remains in SW database and preferences and the refresh is
1516 // aborted. Instead, one should abort the refresh and retry to refresh
1517 // periodically.
1518 if (status !=
1519 blink::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE) {
1520 return;
1521 }
1522
1523 // Old subscription is now replaced locally by the new subscription
1524 refresher_.OnSubscriptionUpdated(new_app_id);
1525
1526 PushMessagingAppIdentifier new_app_identifier =
1527 PushMessagingAppIdentifier::FindByAppId(profile_, new_app_id);
1528
1529 // Callback for testing
1530 base::OnceClosure callback =
1531 (invalidation_callback_for_testing_)
1532 ? std::move(invalidation_callback_for_testing_)
1533 : base::DoNothing();
1534
1535 FirePushSubscriptionChange(
1536 new_app_identifier, std::move(callback),
1537 blink::mojom::PushSubscription::New(
1538 endpoint, expiration_time, push_messaging::MakeOptions(sender_id),
1539 p256dh, auth),
1540 std::move(old_subscription));
1541 }
1542
1543 // PushMessagingRefresher::Observer methods ------------------------------------
1544
OnOldSubscriptionExpired(const std::string & app_id,const std::string & sender_id)1545 void PushMessagingServiceImpl::OnOldSubscriptionExpired(
1546 const std::string& app_id,
1547 const std::string& sender_id) {
1548 // Unsubscribe without clearing SW database, since values of the new
1549 // subscription are already saved there.
1550 // After unsubscribing, the refresher will get notified.
1551 UnsubscribeInternal(
1552 blink::mojom::PushUnregistrationReason::REFRESH_FINISHED,
1553 GURL::EmptyGURL() /* origin */, -1 /* service_worker_registration_id */,
1554 app_id, sender_id,
1555 base::BindOnce(&UnregisterCallbackToClosure,
1556 base::BindOnce(&PushMessagingRefresher::OnUnsubscribed,
1557 refresher_.GetWeakPtr(), app_id)));
1558 }
1559
OnRefreshFinished(const PushMessagingAppIdentifier & app_identifier)1560 void PushMessagingServiceImpl::OnRefreshFinished(
1561 const PushMessagingAppIdentifier& app_identifier) {
1562 // TODO(viviy): Log data in UMA
1563 }
1564
SetInvalidationCallbackForTesting(base::OnceClosure callback)1565 void PushMessagingServiceImpl::SetInvalidationCallbackForTesting(
1566 base::OnceClosure callback) {
1567 invalidation_callback_for_testing_ = std::move(callback);
1568 }
1569
1570 // Helper methods --------------------------------------------------------------
1571
SetRemoveExpiredSubscriptionsCallbackForTesting(base::OnceClosure closure)1572 void PushMessagingServiceImpl::SetRemoveExpiredSubscriptionsCallbackForTesting(
1573 base::OnceClosure closure) {
1574 remove_expired_subscriptions_callback_for_testing_ = std::move(closure);
1575 }
1576
1577 // Assumes user_visible always since this is just meant to check
1578 // if the permission was previously granted and not revoked.
IsPermissionSet(const GURL & origin,bool user_visible)1579 bool PushMessagingServiceImpl::IsPermissionSet(const GURL& origin,
1580 bool user_visible) {
1581 return GetPermissionStatus(origin, user_visible) ==
1582 blink::mojom::PermissionStatus::GRANTED;
1583 }
1584
GetEncryptionInfoForAppId(const std::string & app_id,const std::string & sender_id,gcm::GCMEncryptionProvider::EncryptionInfoCallback callback)1585 void PushMessagingServiceImpl::GetEncryptionInfoForAppId(
1586 const std::string& app_id,
1587 const std::string& sender_id,
1588 gcm::GCMEncryptionProvider::EncryptionInfoCallback callback) {
1589 if (PushMessagingAppIdentifier::UseInstanceID(app_id)) {
1590 GetInstanceIDDriver()->GetInstanceID(app_id)->GetEncryptionInfo(
1591 push_messaging::NormalizeSenderInfo(sender_id), std::move(callback));
1592 } else {
1593 GetGCMDriver()->GetEncryptionInfo(app_id, std::move(callback));
1594 }
1595 }
1596
GetGCMDriver() const1597 gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const {
1598 gcm::GCMProfileService* gcm_profile_service =
1599 gcm::GCMProfileServiceFactory::GetForProfile(profile_);
1600 CHECK(gcm_profile_service);
1601 CHECK(gcm_profile_service->driver());
1602 return gcm_profile_service->driver();
1603 }
1604
GetInstanceIDDriver() const1605 instance_id::InstanceIDDriver* PushMessagingServiceImpl::GetInstanceIDDriver()
1606 const {
1607 instance_id::InstanceIDProfileService* instance_id_profile_service =
1608 instance_id::InstanceIDProfileServiceFactory::GetForProfile(profile_);
1609 CHECK(instance_id_profile_service);
1610 CHECK(instance_id_profile_service->driver());
1611 return instance_id_profile_service->driver();
1612 }
1613
1614 content::DevToolsBackgroundServicesContext*
GetDevToolsContext(const GURL & origin) const1615 PushMessagingServiceImpl::GetDevToolsContext(const GURL& origin) const {
1616 auto* storage_partition =
1617 content::BrowserContext::GetStoragePartitionForSite(profile_, origin);
1618 if (!storage_partition)
1619 return nullptr;
1620
1621 auto* devtools_context =
1622 storage_partition->GetDevToolsBackgroundServicesContext();
1623
1624 if (!devtools_context->IsRecording(
1625 content::DevToolsBackgroundService::kPushMessaging)) {
1626 return nullptr;
1627 }
1628
1629 return devtools_context;
1630 }
1631