chromium/chrome/browser/push_messaging/push_messaging_service_impl.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/push_messaging/push_messaging_service_impl.h"

#include <map>
#include <sstream>
#include <vector>

#include "base/barrier_closure.h"
#include "base/base64url.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/gcm/gcm_profile_service_factory.h"
#include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h"
#include "chrome/browser/lifetime/termination_notification.h"
#include "chrome/browser/permissions/permission_revocation_request.h"
#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
#include "chrome/browser/push_messaging/push_messaging_constants.h"
#include "chrome/browser/push_messaging/push_messaging_features.h"
#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
#include "chrome/browser/push_messaging/push_messaging_utils.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/gcm_driver/gcm_driver.h"
#include "components/gcm_driver/gcm_profile_service.h"
#include "components/gcm_driver/instance_id/instance_id.h"
#include "components/gcm_driver/instance_id/instance_id_driver.h"
#include "components/gcm_driver/instance_id/instance_id_profile_service.h"
#include "components/permissions/permission_manager.h"
#include "components/permissions/permission_uma_util.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/child_process_host.h"
#include "content/public/browser/devtools_background_services_context.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/permission_result.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/service_worker_context.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "extensions/common/constants.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
#include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
#include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/origin.h"

#if BUILDFLAG(ENABLE_BACKGROUND_MODE)
#include "chrome/browser/background/background_mode_manager.h"
#include "components/keep_alive_registry/keep_alive_types.h"
#include "components/keep_alive_registry/scoped_keep_alive.h"
#endif

#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "chrome/android/chrome_jni_headers/PushMessagingServiceBridge_jni.h"
#include "chrome/android/chrome_jni_headers/PushMessagingServiceObserver_jni.h"
#include "chrome/browser/android/shortcut_helper.h"
#include "chrome/browser/notifications/notification_platform_bridge.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/permissions/android/android_permission_util.h"
#endif

#if BUILDFLAG(IS_ANDROID)
using base::android::ConvertJavaStringToUTF8;
using base::android::JavaParamRef;
#endif

InstanceID;

namespace {

// Scope passed to getToken to obtain GCM registration tokens.
// Must match Java GoogleCloudMessaging.INSTANCE_ID_SCOPE.
const char kGCMScope[] =;

const int kMaxRegistrations =;

// Chrome does not yet support silent push messages, and requires websites to
// indicate that they will only send user-visible messages.
const char kSilentPushUnsupportedMessage[] =;

// Message displayed in the console (as an error) when a GCM Sender ID is used
// to create a subscription, which is unsupported. The subscription request will
// have been blocked, and an exception will be thrown as well.
const char kSenderIdRegistrationDisallowedMessage[] =;

// Message displayed in the console (as a warning) when a GCM Sender ID is used
// to create a subscription, which will soon be unsupported.
const char kSenderIdRegistrationDeprecatedMessage[] =;

#if BUILDFLAG(IS_ANDROID)
// The serialized base::Time used for Notifications permission revocation grace
// period checks. This is usually the time at which the first push message was
// received without app-level Notifications permission. An empty
// (default-constructed) base::Time if there is no known time without app-level
// Notifications permission.
const char kNotificationsPermissionRevocationGracePeriodDate[] =
    "notifications_permission_revocation_grace_period";

// The grace period that will be applied before site-level Notifications
// permissions will be revoked and FCM unsubscribed.
int GetNotificationsRevocationGracePeriodInDays() {
  return base::GetFieldTrialParamByFeatureAsInt(
      features::kRevokeNotificationsPermissionIfDisabledOnAppLevel,
      features::kNotificationRevocationGracePeriodInDays, 3);
}
#endif

void RecordDeliveryStatus(blink::mojom::PushEventStatus status) {}

void RecordUnsubscribeReason(blink::mojom::PushUnregistrationReason reason) {}

void UnregisterCallbackToClosure(
    base::OnceClosure closure,
    blink::mojom::PushUnregistrationStatus status) {}

void 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) {}

PendingMessage::PendingMessage(std::string app_id, gcm::IncomingMessage message)
    :{}
PendingMessage::PendingMessage(const PendingMessage& other) = default;
PendingMessage::PendingMessage(PendingMessage&& other) = default;
PendingMessage& PendingMessage::operator=(PendingMessage&& other) = default;
PendingMessage::~PendingMessage() = default;

}  // namespace

// static
void PushMessagingServiceImpl::InitializeForProfile(Profile* profile) {}

void PushMessagingServiceImpl::RemoveExpiredSubscriptions() {}

void PushMessagingServiceImpl::UnexpectedChange(
    PushMessagingAppIdentifier identifier,
    blink::mojom::PushUnregistrationReason reason,
    base::OnceClosure completed_closure) {}

PushMessagingServiceImpl::PushMessagingServiceImpl(Profile* profile)
    :{}

PushMessagingServiceImpl::~PushMessagingServiceImpl() = default;

void PushMessagingServiceImpl::IncreasePushSubscriptionCount(int add,
                                                             bool is_pending) {}

void PushMessagingServiceImpl::DecreasePushSubscriptionCount(int subtract,
                                                             bool was_pending) {}

bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const {}

void PushMessagingServiceImpl::ShutdownHandler() {}

void PushMessagingServiceImpl::OnStoreReset() {}

// OnMessage methods -----------------------------------------------------------

void PushMessagingServiceImpl::OnMessage(const std::string& app_id,
                                         const gcm::IncomingMessage& message) {}

void PushMessagingServiceImpl::CheckOriginAndDispatchNextMessage() {}

void PushMessagingServiceImpl::OnCheckedOrigin(
    PendingMessage message,
    PermissionRevocationRequest::Outcome outcome) {}

void PushMessagingServiceImpl::
    DeliverNextQueuedMessageForServiceWorkerRegistration(
        const GURL& origin,
        int64_t service_worker_registration_id) {}

void PushMessagingServiceImpl::DeliverMessageCallback(
    const std::string& app_id,
    const GURL& requesting_origin,
    int64_t service_worker_registration_id,
    const gcm::IncomingMessage& message,
    bool did_enqueue_message,
    blink::mojom::PushEventStatus status) {}

void PushMessagingServiceImpl::DidHandleEnqueuedMessage(
    const GURL& origin,
    int64_t service_worker_registration_id,
    base::OnceCallback<void(bool)> message_handled_callback,
    bool did_show_generic_notification) {}

void PushMessagingServiceImpl::DidHandleMessage(
    const std::string& app_id,
    const std::string& push_message_id,
    bool did_show_generic_notification) {}

void PushMessagingServiceImpl::SetMessageCallbackForTesting(
    const base::RepeatingClosure& callback) {}

// Other gcm::GCMAppHandler methods --------------------------------------------

void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) {}

void PushMessagingServiceImpl::OnSendError(
    const std::string& app_id,
    const gcm::GCMClient::SendErrorDetails& send_error_details) {}

void PushMessagingServiceImpl::OnSendAcknowledged(
    const std::string& app_id,
    const std::string& message_id) {}

void PushMessagingServiceImpl::OnMessageDecryptionFailed(
    const std::string& app_id,
    const std::string& message_id,
    const std::string& error_message) {}

// Subscribe and GetPermissionStatus methods -----------------------------------

void PushMessagingServiceImpl::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) {}

void PushMessagingServiceImpl::SubscribeFromWorker(
    const GURL& requesting_origin,
    int64_t service_worker_registration_id,
    int render_process_id,
    blink::mojom::PushSubscriptionOptionsPtr options,
    RegisterCallback register_callback) {}

blink::mojom::PermissionStatus PushMessagingServiceImpl::GetPermissionStatus(
    const GURL& origin,
    bool user_visible) {}

#if BUILDFLAG(IS_ANDROID)
// static
void PushMessagingServiceImpl::RegisterPrefs(PrefRegistrySimple* registry) {
  registry->RegisterTimePref(kNotificationsPermissionRevocationGracePeriodDate,
                             base::Time());
}

static void
JNI_PushMessagingServiceBridge_VerifyAndRevokeNotificationsPermission(
    JNIEnv* env,
    std::string& origin,
    std::string& profile_id,
    jboolean app_level_notifications_enabled) {
  if (!base::FeatureList::IsEnabled(
          features::kRevokeNotificationsPermissionIfDisabledOnAppLevel)) {
    return;
  }

  ProfileManager* profile_manager = g_browser_process->profile_manager();
  DCHECK(profile_manager);

  profile_manager->LoadProfile(
      NotificationPlatformBridge::GetProfileBaseNameFromProfileId(profile_id),
      /*incognito=*/false,
      base::BindOnce(&PushMessagingServiceImpl::RevokePermissionIfPossible,
                     GURL(origin), app_level_notifications_enabled,
                     g_browser_process->local_state()));
}

void PushMessagingServiceImpl::RevokePermissionIfPossible(
    GURL origin,
    bool app_level_notifications_enabled,
    PrefService* prefs,
    Profile* profile) {
  if (app_level_notifications_enabled) {
    // Chrome has app-level Notifications permission. Reset the grace period
    // flag and continue as normal.
    prefs->ClearPref(kNotificationsPermissionRevocationGracePeriodDate);
    return;
  }

  if (prefs->GetTime(kNotificationsPermissionRevocationGracePeriodDate) ==
      base::Time()) {
    prefs->SetTime(kNotificationsPermissionRevocationGracePeriodDate,
                   base::Time::Now());
    return;
  }

  base::TimeDelta permission_revocation_activated_duration =
      base::Time::Now() -
      prefs->GetTime(kNotificationsPermissionRevocationGracePeriodDate);
  if (permission_revocation_activated_duration.InDays() >=
      GetNotificationsRevocationGracePeriodInDays()) {
    content::PermissionController* permission_controller =
        profile->GetPermissionController();

    // As soon as permission is reset,
    // `PushMessagingServiceImpl::OnContentSettingChanged` is notified and it
    // revokes a push message registration token.
    permission_controller->ResetPermission(blink::PermissionType::NOTIFICATIONS,
                                           url::Origin::Create(origin));
  }
}

#endif

bool PushMessagingServiceImpl::SupportNonVisibleMessages() {}

void PushMessagingServiceImpl::DoSubscribe(
    PushMessagingAppIdentifier app_identifier,
    blink::mojom::PushSubscriptionOptionsPtr options,
    RegisterCallback register_callback,
    int render_process_id,
    int render_frame_id,
    blink::mojom::PermissionStatus permission_status) {}

void PushMessagingServiceImpl::SubscribeEnd(
    RegisterCallback callback,
    const std::string& subscription_id,
    const GURL& endpoint,
    const std::optional<base::Time>& expiration_time,
    const std::vector<uint8_t>& p256dh,
    const std::vector<uint8_t>& auth,
    blink::mojom::PushRegistrationStatus status) {}

void PushMessagingServiceImpl::SubscribeEndWithError(
    RegisterCallback callback,
    blink::mojom::PushRegistrationStatus status) {}

void PushMessagingServiceImpl::DidSubscribe(
    const PushMessagingAppIdentifier& app_identifier,
    const std::string& sender_id,
    RegisterCallback callback,
    const std::string& subscription_id,
    InstanceID::Result result) {}

void PushMessagingServiceImpl::DidSubscribeWithEncryptionInfo(
    const PushMessagingAppIdentifier& app_identifier,
    RegisterCallback callback,
    const std::string& subscription_id,
    const GURL& endpoint,
    std::string p256dh,
    std::string auth_secret) {}

// GetSubscriptionInfo methods -------------------------------------------------

void PushMessagingServiceImpl::GetSubscriptionInfo(
    const GURL& origin,
    int64_t service_worker_registration_id,
    const std::string& sender_id,
    const std::string& subscription_id,
    SubscriptionInfoCallback callback) {}

void PushMessagingServiceImpl::DidValidateSubscription(
    const std::string& app_id,
    const std::string& sender_id,
    const GURL& endpoint,
    const std::optional<base::Time>& expiration_time,
    SubscriptionInfoCallback callback,
    bool is_valid) {}

void PushMessagingServiceImpl::DidGetEncryptionInfo(
    const GURL& endpoint,
    const std::optional<base::Time>& expiration_time,
    SubscriptionInfoCallback callback,
    std::string p256dh,
    std::string auth_secret) const {}

// Unsubscribe methods ---------------------------------------------------------

void PushMessagingServiceImpl::Unsubscribe(
    blink::mojom::PushUnregistrationReason reason,
    const GURL& requesting_origin,
    int64_t service_worker_registration_id,
    const std::string& sender_id,
    UnregisterCallback callback) {}

void PushMessagingServiceImpl::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) {}

void PushMessagingServiceImpl::DidClearPushSubscriptionId(
    blink::mojom::PushUnregistrationReason reason,
    const std::string& app_id,
    const std::string& sender_id,
    UnregisterCallback callback) {}

void PushMessagingServiceImpl::DidUnregister(bool was_subscribed,
                                             gcm::GCMClient::Result result) {}

void PushMessagingServiceImpl::DidDeleteID(const std::string& app_id,
                                           bool was_subscribed,
                                           InstanceID::Result result) {}

void PushMessagingServiceImpl::DidUnsubscribe(
    const std::string& app_id_when_instance_id,
    bool was_subscribed) {}

void PushMessagingServiceImpl::SetUnsubscribeCallbackForTesting(
    base::OnceClosure callback) {}

// DidDeleteServiceWorkerRegistration methods ----------------------------------

void PushMessagingServiceImpl::DidDeleteServiceWorkerRegistration(
    const GURL& origin,
    int64_t service_worker_registration_id) {}

void PushMessagingServiceImpl::SetServiceWorkerUnregisteredCallbackForTesting(
    base::RepeatingClosure callback) {}

// DidDeleteServiceWorkerDatabase methods --------------------------------------

void PushMessagingServiceImpl::DidDeleteServiceWorkerDatabase() {}

void PushMessagingServiceImpl::SetServiceWorkerDatabaseWipedCallbackForTesting(
    base::RepeatingClosure callback) {}

// OnContentSettingChanged methods ---------------------------------------------

void PushMessagingServiceImpl::OnContentSettingChanged(
    const ContentSettingsPattern& primary_pattern,
    const ContentSettingsPattern& secondary_pattern,
    ContentSettingsTypeSet content_type_set) {}

void PushMessagingServiceImpl::UnexpectedUnsubscribe(
    const PushMessagingAppIdentifier& app_identifier,
    blink::mojom::PushUnregistrationReason reason,
    UnregisterCallback unregister_callback) {}

void PushMessagingServiceImpl::GetPushSubscriptionFromAppIdentifier(
    const PushMessagingAppIdentifier& app_identifier,
    base::OnceCallback<void(blink::mojom::PushSubscriptionPtr)>
        subscription_cb) {}

void PushMessagingServiceImpl::DidGetSWData(
    const PushMessagingAppIdentifier& app_identifier,
    base::OnceCallback<void(blink::mojom::PushSubscriptionPtr)> subscription_cb,
    const std::string& sender_id,
    const std::string& subscription_id) {}

void PushMessagingServiceImpl::GetPushSubscriptionFromAppIdentifierEnd(
    base::OnceCallback<void(blink::mojom::PushSubscriptionPtr)> callback,
    const std::string& sender_id,
    bool is_valid,
    const GURL& endpoint,
    const std::optional<base::Time>& expiration_time,
    const std::vector<uint8_t>& p256dh,
    const std::vector<uint8_t>& auth) {}

void PushMessagingServiceImpl::FirePushSubscriptionChange(
    const PushMessagingAppIdentifier& app_identifier,
    base::OnceClosure completed_closure,
    blink::mojom::PushSubscriptionPtr new_subscription,
    blink::mojom::PushSubscriptionPtr old_subscription) {}

void PushMessagingServiceImpl::FirePushSubscriptionChangeCallback(
    const PushMessagingAppIdentifier& app_identifier,
    blink::mojom::PushEventStatus status) {}

void PushMessagingServiceImpl::DidGetSenderIdUnexpectedUnsubscribe(
    const PushMessagingAppIdentifier& app_identifier,
    blink::mojom::PushUnregistrationReason reason,
    UnregisterCallback callback,
    const std::string& sender_id) {}

void PushMessagingServiceImpl::SetContentSettingChangedCallbackForTesting(
    base::RepeatingClosure callback) {}

// KeyedService methods -------------------------------------------------------

void PushMessagingServiceImpl::Shutdown() {}

void PushMessagingServiceImpl::OnAppTerminating() {}

// OnSubscriptionInvalidation methods ------------------------------------------

void PushMessagingServiceImpl::OnSubscriptionInvalidation(
    const std::string& app_id) {}

void PushMessagingServiceImpl::GetOldSubscription(
    PushMessagingAppIdentifier old_app_identifier,
    const std::string& sender_id) {}

void PushMessagingServiceImpl::StartRefresh(
    PushMessagingAppIdentifier old_app_identifier,
    const std::string& sender_id,
    blink::mojom::PushSubscriptionPtr old_subscription) {}

void PushMessagingServiceImpl::UpdateSubscription(
    PushMessagingAppIdentifier app_identifier,
    blink::mojom::PushSubscriptionOptionsPtr options,
    RegisterCallback callback) {}

void PushMessagingServiceImpl::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 std::optional<base::Time>& expiration_time,
    const std::vector<uint8_t>& p256dh,
    const std::vector<uint8_t>& auth,
    blink::mojom::PushRegistrationStatus status) {}

// PushMessagingRefresher::Observer methods ------------------------------------

void PushMessagingServiceImpl::OnOldSubscriptionExpired(
    const std::string& app_id,
    const std::string& sender_id) {}

void PushMessagingServiceImpl::OnRefreshFinished(
    const PushMessagingAppIdentifier& app_identifier) {}

void PushMessagingServiceImpl::SetInvalidationCallbackForTesting(
    base::OnceClosure callback) {}

// Helper methods --------------------------------------------------------------

void PushMessagingServiceImpl::SetRemoveExpiredSubscriptionsCallbackForTesting(
    base::OnceClosure closure) {}

// Assumes user_visible always since this is just meant to check
// if the permission was previously granted and not revoked.
bool PushMessagingServiceImpl::IsPermissionSet(const GURL& origin,
                                               bool user_visible) {}

void PushMessagingServiceImpl::GetEncryptionInfoForAppId(
    const std::string& app_id,
    const std::string& sender_id,
    gcm::GCMEncryptionProvider::EncryptionInfoCallback callback) {}

gcm::GCMDriver* PushMessagingServiceImpl::GetGCMDriver() const {}

instance_id::InstanceIDDriver* PushMessagingServiceImpl::GetInstanceIDDriver()
    const {}

content::DevToolsBackgroundServicesContext*
PushMessagingServiceImpl::GetDevToolsContext(const GURL& origin) const {}