// 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/common/chromeos/extensions/chromeos_system_extension_info.h"
#include <memory>
#include <optional>
#include <string>
#include "base/check.h"
#include "base/command_line.h"
#include "base/containers/fixed_flat_map.h"
#include "base/containers/flat_set.h"
#include "base/logging.h"
#include "build/chromeos_buildflags.h"
#include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_features.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace chromeos {
namespace switches {
// Overrides |manufacturer| field of the ChromeOSSystemExtensionInfo structure.
// Used for development/testing.
const char kTelemetryExtensionManufacturerOverrideForTesting[] =
"telemetry-extension-manufacturer-override-for-testing";
// Overrides |pwa_origin| field of the ChromeOSSystemExtensionInfo structure.
// Used for development/testing.
const char kTelemetryExtensionPwaOriginOverrideForTesting[] =
"telemetry-extension-pwa-origin-override-for-testing";
// Overrides |iwa_id| field of the ChromeOSSystemExtensionInfo structure.
// Used for development/testing.
const char kTelemetryExtensionIwaIdOverrideForTesting[] =
"telemetry-extension-iwa-id-override-for-testing";
} // namespace switches
namespace {
using ChromeOSSystemExtensionInfoMap =
base::flat_map<std::string, ChromeOSSystemExtensionInfo>;
ChromeOSSystemExtensionInfoMap ConstructMap() {
ChromeOSSystemExtensionInfoMap map{
{/*extension_id=*/"gogonhoemckpdpadfnjnpgbjpbjnodgc",
{
/*manufacturers=*/{"HP", "ASUS"},
/*pwa_origin=*/"*://googlechromelabs.github.io/*",
/*iwa_id=*/std::nullopt,
}},
{/*extension_id=*/"alnedpmllcfpgldkagbfbjkloonjlfjb",
{
/*manufacturers=*/{"HP"},
/*pwa_origin=*/"https://hpcs-appschr.hpcloud.hp.com/*",
/*iwa_id=*/std::nullopt,
}},
{/*extension_id=*/"hdnhcpcfohaeangjpkcjkgmgmjanbmeo",
{
/*manufacturers=*/{"ASUS"},
/*pwa_origin=*/"https://dlcdnccls.asus.com/*",
/*iwa_id=*/std::nullopt,
}},
};
if (IsChromeOSSystemExtensionDevExtensionEnabled()) {
map.try_emplace(
kChromeOSSystemExtensionDevExtensionId,
ChromeOSSystemExtensionInfo{
/*manufacturers=*/{"Google", "HP", "ASUS"},
/*pwa_origin=*/"*://googlechromelabs.github.io/*",
/*iwa_id=*/
web_package::SignedWebBundleId::Create(
"pt2jysa7yu326m2cbu5mce4rrajvguagronrsqwn5dhbaris6eaaaaic")
.value(),
});
}
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(
switches::kTelemetryExtensionPwaOriginOverrideForTesting)) {
auto pwa_origin = command_line->GetSwitchValueASCII(
switches::kTelemetryExtensionPwaOriginOverrideForTesting);
for (auto& [extension_id, extension_info] : map) {
extension_info.pwa_origin = pwa_origin;
}
}
if (command_line->HasSwitch(
switches::kTelemetryExtensionManufacturerOverrideForTesting)) {
auto manufacturer = command_line->GetSwitchValueASCII(
switches::kTelemetryExtensionManufacturerOverrideForTesting);
for (auto& [extension_id, extension_info] : map) {
extension_info.manufacturers = {manufacturer};
}
}
if (command_line->HasSwitch(
switches::kTelemetryExtensionIwaIdOverrideForTesting)) {
auto iwa_id_str = command_line->GetSwitchValueASCII(
switches::kTelemetryExtensionIwaIdOverrideForTesting);
auto iwa_id_res = web_package::SignedWebBundleId::Create(iwa_id_str);
if (iwa_id_res.has_value()) {
for (auto& [extension_id, extension_info] : map) {
extension_info.iwa_id = iwa_id_res.value();
}
} else {
LOG(ERROR) << "Failed to parse iwa id " << iwa_id_str << ": "
<< iwa_id_res.error();
}
}
return map;
}
ChromeOSSystemExtensionInfoMap*& GetMap() {
static ChromeOSSystemExtensionInfoMap* g_map =
new ChromeOSSystemExtensionInfoMap{ConstructMap()};
return g_map;
}
} // namespace
bool IsChromeOSSystemExtensionDevExtensionEnabled() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
return ash::features::IsShimlessRMA3pDiagnosticsDevModeEnabled();
#else
return false;
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
ChromeOSSystemExtensionInfo::ChromeOSSystemExtensionInfo(
const base::flat_set<std::string>& manufacturers,
const std::optional<std::string>& pwa_origin,
const std::optional<web_package::SignedWebBundleId>& iwa_id)
: manufacturers(manufacturers), pwa_origin(pwa_origin), iwa_id(iwa_id) {}
ChromeOSSystemExtensionInfo::ChromeOSSystemExtensionInfo(
const ChromeOSSystemExtensionInfo&) = default;
ChromeOSSystemExtensionInfo& ChromeOSSystemExtensionInfo::operator=(
const ChromeOSSystemExtensionInfo&) = default;
ChromeOSSystemExtensionInfo::~ChromeOSSystemExtensionInfo() = default;
const ChromeOSSystemExtensionInfo& GetChromeOSExtensionInfoById(
const std::string& id) {
CHECK(IsChromeOSSystemExtension(id));
return GetMap()->at(id);
}
bool IsChromeOSSystemExtension(const std::string& id) {
return GetMap()->find(id) != GetMap()->end();
}
bool Is3pDiagnosticsIwaId(const web_package::SignedWebBundleId& id) {
for (const auto& [extension_id, extension_info] : *GetMap()) {
if (extension_info.iwa_id == id) {
return true;
}
}
return false;
}
bool IsChromeOSSystemExtensionProvider(const std::string& manufacturer) {
for (const auto& [extension_id, info] : *GetMap()) {
if (info.manufacturers.contains(manufacturer)) {
return true;
}
}
return false;
}
class ScopedChromeOSSystemExtensionInfoImpl
: public ScopedChromeOSSystemExtensionInfo {
public:
ScopedChromeOSSystemExtensionInfoImpl();
ScopedChromeOSSystemExtensionInfoImpl(
ScopedChromeOSSystemExtensionInfoImpl&) = delete;
ScopedChromeOSSystemExtensionInfoImpl& operator=(
ScopedChromeOSSystemExtensionInfoImpl&) = delete;
~ScopedChromeOSSystemExtensionInfoImpl() override;
void ApplyCommandLineSwitchesForTesting() override; // IN-TEST
private:
raw_ptr<ChromeOSSystemExtensionInfoMap> map_;
};
// static
std::unique_ptr<ScopedChromeOSSystemExtensionInfo>
ScopedChromeOSSystemExtensionInfo::CreateForTesting() {
return std::make_unique<ScopedChromeOSSystemExtensionInfoImpl>();
}
ScopedChromeOSSystemExtensionInfoImpl::ScopedChromeOSSystemExtensionInfoImpl() {
map_ = GetMap();
GetMap() = new ChromeOSSystemExtensionInfoMap{ConstructMap()};
}
ScopedChromeOSSystemExtensionInfoImpl::
~ScopedChromeOSSystemExtensionInfoImpl() {
delete GetMap();
GetMap() = map_;
}
void ScopedChromeOSSystemExtensionInfoImpl::
ApplyCommandLineSwitchesForTesting() {
delete GetMap();
GetMap() = new ChromeOSSystemExtensionInfoMap{ConstructMap()};
}
} // namespace chromeos