chromium/chrome/browser/apps/intent_helper/chromeos_disabled_apps_throttle.cc

// Copyright 2023 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/apps/intent_helper/chromeos_disabled_apps_throttle.h"

#include <memory>
#include <vector>

#include "base/memory/ptr_util.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/policy/system_features_disable_list_policy_handler.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/grit/browser_resources.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/navigation_throttle.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/webui/jstemplate_builder.h"
#include "ui/base/webui/web_ui_util.h"

namespace apps {
namespace {
using ThrottleCheckResult = content::NavigationThrottle::ThrottleCheckResult;

std::string GetAppDisabledErrorPage() {
  base::Value::Dict strings;

  strings.Set("disabledPageHeader",
              l10n_util::GetStringUTF16(IDS_CHROME_URLS_DISABLED_PAGE_HEADER));
  strings.Set("disabledPageTitle",
              l10n_util::GetStringUTF16(IDS_CHROME_URLS_DISABLED_PAGE_TITLE));
  strings.Set("disabledPageMessage",
              l10n_util::GetStringUTF16(IDS_CHROME_URLS_DISABLED_PAGE_MESSAGE));
  std::string html =
      ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
          IDR_CHROME_URLS_DISABLED_PAGE_HTML);
  const std::string& app_locale = g_browser_process->GetApplicationLocale();
  webui::SetLoadTimeDataDefaults(app_locale, &strings);
  return webui::GetI18nTemplateHtml(html, strings);
}
}  // namespace

// static
std::unique_ptr<content::NavigationThrottle>
ChromeOsDisabledAppsThrottle::MaybeCreate(content::NavigationHandle* handle) {
  // Don't handle navigations in subframes or main frames that are in a nested
  // frame tree (e.g. portals, fenced-frame).
  if (!handle->IsInPrimaryMainFrame() && !handle->IsInPrerenderedMainFrame()) {
    return nullptr;
  }

  content::WebContents* web_contents = handle->GetWebContents();
  Profile* profile =
      Profile::FromBrowserContext(web_contents->GetBrowserContext());
  if (!AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) {
    return nullptr;
  }

  return base::WrapUnique(new ChromeOsDisabledAppsThrottle(handle));
}

ChromeOsDisabledAppsThrottle::ChromeOsDisabledAppsThrottle(
    content::NavigationHandle* navigation_handle)
    : content::NavigationThrottle(navigation_handle) {}
ChromeOsDisabledAppsThrottle::~ChromeOsDisabledAppsThrottle() = default;

const char* ChromeOsDisabledAppsThrottle::GetNameForLogging() {
  return "ChromeOsDisabledAppsThrottle";
}

ThrottleCheckResult ChromeOsDisabledAppsThrottle::WillStartRequest() {
  return HandleRequest();
}

ThrottleCheckResult ChromeOsDisabledAppsThrottle::WillRedirectRequest() {
  return HandleRequest();
}

ThrottleCheckResult ChromeOsDisabledAppsThrottle::HandleRequest() {
  content::WebContents* web_contents = navigation_handle()->GetWebContents();
  const GURL& url = navigation_handle()->GetURL();

  Profile* profile =
      Profile::FromBrowserContext(web_contents->GetBrowserContext());

  std::vector<std::string> app_ids =
      apps::AppServiceProxyFactory::GetForProfile(profile)->GetAppIdsForUrl(
          url, /*exclude_browsers=*/true, /*exclude_browser_tab_apps=*/false);

  for (const auto& app_id : app_ids) {
    policy::SystemFeature system_feature =
        policy::SystemFeaturesDisableListPolicyHandler::
            GetSystemFeatureFromAppId(app_id);

    if (system_feature == policy::SystemFeature::kUnknownSystemFeature) {
      continue;
    }

    if (!policy::SystemFeaturesDisableListPolicyHandler::
            IsSystemFeatureDisabled(system_feature,
                                    g_browser_process->local_state())) {
      continue;
    }

    return ThrottleCheckResult(content::NavigationThrottle::CANCEL,
                               net::ERR_BLOCKED_BY_ADMINISTRATOR,
                               GetAppDisabledErrorPage());
  }
  return content::NavigationThrottle::PROCEED;
}

}  // namespace apps