chromium/chrome/browser/ash/child_accounts/website_approval_notifier.cc

// Copyright 2021 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/ash/child_accounts/website_approval_notifier.h"

#include <memory>
#include <string>

#include "ash/constants/notifier_catalogs.h"
#include "ash/public/cpp/new_window_delegate.h"
#include "ash/public/cpp/notification_utils.h"
#include "base/functional/bind.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/notifications/notification_display_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_key.h"
#include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/ui/vector_icons/vector_icons.h"
#include "components/supervised_user/core/browser/supervised_user_settings_service.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/public/cpp/notification.h"
#include "url/gurl.h"

namespace ash {

namespace {

// Notifier id representing the app.
constexpr char kWebsiteApprovalNotifierId[] = "family-link";

// Prefix for website approval notifications. Each hostname is associated with a
// different suffix, so that all notifications are shown (subsequent ones do NOT
// displace previous ones).
constexpr char kWebsiteApprovalNotificationIdPrefix[] = "website-approval-";

const char kNotificationClickedActionName[] =
    "SupervisedUsers_RemoteWebApproval_NotificationClicked";

const char kNotificationShownActionName[] =
    "SupervisedUsers_RemoteWebApproval_NotificationShown";

GURL GetURLToOpen(const std::string& allowed_host) {
  // When a match pattern containing * (e.g. *.google.*) is allowlisted, return
  // an empty URL because we can't know which URL to open.
  if (allowed_host.find('*') != std::string::npos) {
    return GURL();
  }

  // Constructs a URL that the user can open, defaulting to HTTPS.
  GURL url = GURL(base::StrCat(
      {url::kHttpsScheme, url::kStandardSchemeSeparator, allowed_host}));
  DLOG_IF(ERROR, !url.is_valid()) << "Invalid URL spec " << allowed_host;
  return url;
}

void OnNotificationClick(const GURL& url) {
  base::RecordAction(base::UserMetricsAction(kNotificationClickedActionName));
  NewWindowDelegate::GetPrimary()->OpenUrl(
      url, NewWindowDelegate::OpenUrlFrom::kUserInteraction,
      NewWindowDelegate::Disposition::kNewForegroundTab);
}

}  // namespace

WebsiteApprovalNotifier::WebsiteApprovalNotifier(Profile* profile)
    : profile_(profile) {
  supervised_user::SupervisedUserSettingsService* settings_service =
      SupervisedUserSettingsServiceFactory::GetForKey(
          profile_->GetProfileKey());
  website_approval_subscription_ =
      settings_service->SubscribeForNewWebsiteApproval(base::BindRepeating(
          &WebsiteApprovalNotifier::MaybeShowApprovalNotification,
          weak_ptr_factory_.GetWeakPtr()));
}

WebsiteApprovalNotifier::~WebsiteApprovalNotifier() = default;

void WebsiteApprovalNotifier::MaybeShowApprovalNotification(
    const std::string& allowed_host) {
  GURL url = GetURLToOpen(allowed_host);
  if (!url.is_valid()) {
    return;
  }
  message_center::RichNotificationData option_fields;
  option_fields.fullscreen_visibility =
      message_center::FullscreenVisibility::OVER_USER;
  message_center::Notification notification = CreateSystemNotification(
      message_center::NOTIFICATION_TYPE_SIMPLE,
      kWebsiteApprovalNotificationIdPrefix + allowed_host,
      l10n_util::GetStringUTF16(IDS_WEBSITE_APPROVED_NOTIFICATION_TITLE),
      l10n_util::GetStringFUTF16(IDS_WEBSITE_APPROVED_NOTIFICATION_MESSAGE,
                                 base::UTF8ToUTF16(allowed_host)),
      l10n_util::GetStringUTF16(
          IDS_WEBSITE_APPROVED_NOTIFICATION_DISPLAY_SOURCE),
      GURL(),
      message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
                                 kWebsiteApprovalNotifierId,
                                 NotificationCatalogName::kWebsiteApproval),
      option_fields,
      base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
          base::BindRepeating(&OnNotificationClick, url)),
      chromeos::kNotificationSupervisedUserIcon,
      message_center::SystemNotificationWarningLevel::NORMAL);
  base::RecordAction(base::UserMetricsAction(kNotificationShownActionName));
  NotificationDisplayService::GetForProfile(profile_)->Display(
      NotificationHandler::Type::TRANSIENT, notification,
      /*metadata=*/nullptr);
}

}  // namespace ash