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