| // 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_extensions_manifest_handler.h" |
| |
| #include "base/strings/strcat.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/values.h" |
| #include "chrome/common/chromeos/extensions/chromeos_system_extension_info.h" |
| #include "chrome/common/chromeos/extensions/chromeos_system_extensions_manifest_constants.h" |
| #include "chromeos/constants/chromeos_features.h" |
| #include "components/webapps/isolated_web_apps/scheme.h" |
| #include "extensions/common/extension.h" |
| #include "extensions/common/manifest_constants.h" |
| #include "extensions/common/manifest_handlers/permissions_parser.h" |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| using extensions::PermissionsParser; |
| using extensions::mojom::APIPermissionID; |
| |
| bool VerifyExternallyConnectableDefinition(extensions::Extension* extension) { |
| const base::Value::Dict* externally_connectable_dict = |
| extension->manifest()->FindDictPath( |
| extensions::manifest_keys::kExternallyConnectable); |
| // chromeos_system_extension's 'externally_connectable' must exist. |
| if (!externally_connectable_dict) { |
| return false; |
| } |
| |
| // chromeos_system_extension's 'externally_connectable' can only specify |
| // "matches". |
| if (externally_connectable_dict->size() != 1 || |
| !externally_connectable_dict->Find("matches")) { |
| return false; |
| } |
| |
| const auto* matches_list = |
| externally_connectable_dict->Find("matches")->GetIfList(); |
| if (!matches_list || matches_list->empty()) { |
| return false; |
| } |
| |
| const auto& extension_info = GetChromeOSExtensionInfoById(extension->id()); |
| |
| std::optional<std::string> iwa_origin; |
| if (extension_info.iwa_id.has_value()) { |
| iwa_origin = base::StrCat({webapps::kIsolatedAppScheme, |
| url::kStandardSchemeSeparator, |
| extension_info.iwa_id->id(), "/*"}); |
| } |
| for (const auto& match : *matches_list) { |
| const auto& match_str = match.GetString(); |
| if (match_str != extension_info.pwa_origin && match_str != iwa_origin) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| } // namespace |
| |
| ChromeOSSystemExtensionHandler::ChromeOSSystemExtensionHandler() = default; |
| |
| ChromeOSSystemExtensionHandler::~ChromeOSSystemExtensionHandler() = default; |
| |
| bool ChromeOSSystemExtensionHandler::Parse(extensions::Extension* extension, |
| std::u16string* error) { |
| if (extension->id() == kChromeOSSystemExtensionDevExtensionId && |
| !IsChromeOSSystemExtensionDevExtensionEnabled()) { |
| *error = base::ASCIIToUTF16(kInvalidChromeOSSystemExtensionId); |
| return false; |
| } |
| |
| if (!extension->manifest()->FindDictPath( |
| extensions::manifest_keys::kChromeOSSystemExtension)) { |
| *error = base::ASCIIToUTF16(kInvalidChromeOSSystemExtensionDeclaration); |
| return false; |
| } |
| |
| // Verifies that chromeos_system_extension's externally_connectable key exists |
| // and contains one origin only. |
| if (!VerifyExternallyConnectableDefinition(extension)) { |
| *error = base::ASCIIToUTF16(kInvalidExternallyConnectableDeclaration); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| base::span<const char* const> ChromeOSSystemExtensionHandler::Keys() const { |
| static constexpr const char* kKeys[] = { |
| extensions::manifest_keys::kChromeOSSystemExtension}; |
| return kKeys; |
| } |
| |
| } // namespace chromeos |