chromium/chrome/browser/chromeos/platform_keys/extension_platform_keys_service_factory.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/chromeos/platform_keys/extension_platform_keys_service_factory.h"

#include <memory>
#include <utility>

#include "base/check.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/no_destructor.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/chromeos/platform_keys/extension_platform_keys_service.h"
#include "chrome/browser/ui/platform_keys_certificate_selector_chromeos.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "net/cert/x509_certificate.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/crosapi/keystore_service_factory_ash.h"
#endif

namespace chromeos {
namespace {

// This delegate selects a certificate by showing the certificate selection
// dialog to the user.
class DefaultSelectDelegate
    : public chromeos::ExtensionPlatformKeysService::SelectDelegate {
 public:
  DefaultSelectDelegate() {}
  DefaultSelectDelegate(const DefaultSelectDelegate&) = delete;
  auto operator=(const DefaultSelectDelegate&) = delete;
  ~DefaultSelectDelegate() override {}

  void Select(const std::string& extension_id,
              const net::CertificateList& certs,
              CertificateSelectedCallback callback,
              content::WebContents* web_contents,
              content::BrowserContext* context) override {
    CHECK(web_contents);
    const extensions::Extension* const extension =
        extensions::ExtensionRegistry::Get(context)
            ->enabled_extensions()
            .GetByID(extension_id);
    if (!extension) {
      std::move(callback).Run(nullptr /* no certificate selected */);
      return;
    }
    ShowPlatformKeysCertificateSelector(
        web_contents, extension->short_name(), certs,
        // Don't call |callback| once this delegate is destructed, thus use a
        // WeakPtr.
        base::BindOnce(&DefaultSelectDelegate::SelectedCertificate,
                       weak_factory_.GetWeakPtr(), std::move(callback)));
  }

  void SelectedCertificate(
      CertificateSelectedCallback callback,
      const scoped_refptr<net::X509Certificate>& selected_cert) {
    std::move(callback).Run(selected_cert);
  }

 private:
  base::WeakPtrFactory<DefaultSelectDelegate> weak_factory_{this};
};

}  // namespace

// static
ExtensionPlatformKeysService*
ExtensionPlatformKeysServiceFactory::GetForBrowserContext(
    content::BrowserContext* context) {
  return static_cast<ExtensionPlatformKeysService*>(
      GetInstance()->GetServiceForBrowserContext(context, true));
}

// static
ExtensionPlatformKeysServiceFactory*
ExtensionPlatformKeysServiceFactory::GetInstance() {
  static base::NoDestructor<ExtensionPlatformKeysServiceFactory> instance;
  return instance.get();
}

ExtensionPlatformKeysServiceFactory::ExtensionPlatformKeysServiceFactory()
    : ProfileKeyedServiceFactory(
          "ExtensionPlatformKeysService",
          ProfileSelections::Builder()
              .WithRegular(ProfileSelection::kRedirectedToOriginal)
              // TODO(crbug.com/40257657): Check if this service is needed in
              // Guest mode.
              .WithGuest(ProfileSelection::kRedirectedToOriginal)
              // TODO(crbug.com/41488885): Check if this service is needed for
              // Ash Internals.
              .WithAshInternals(ProfileSelection::kRedirectedToOriginal)
              .Build()) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
  DependsOn(crosapi::KeystoreServiceFactoryAsh::GetInstance());
#endif
}

ExtensionPlatformKeysServiceFactory::~ExtensionPlatformKeysServiceFactory() =
    default;

KeyedService* ExtensionPlatformKeysServiceFactory::BuildServiceInstanceFor(
    content::BrowserContext* context) const {
  ExtensionPlatformKeysService* const service =
      new ExtensionPlatformKeysService(context);

  service->SetSelectDelegate(std::make_unique<DefaultSelectDelegate>());
  return service;
}

}  // namespace chromeos