Commit bb07547c authored by Ben Wells's avatar Ben Wells Committed by Commit Bot

Add related_web_apps extensions manifest field.

This will be used in the chrome.management.installWebApp API to verify
that the extension calling installWebApp owns the web app to be
installed.

Bug: 944397
Change-Id: I95ee4819ff8b9f342736c9d81b20f547d63f34d2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1549300
Commit-Queue: Ben Wells <benwells@chromium.org>
Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#649338}
parent 74f3dd3f
......@@ -227,6 +227,8 @@ if (enable_extensions) {
"manifest_handlers/options_page_info.h",
"manifest_handlers/permissions_parser.cc",
"manifest_handlers/permissions_parser.h",
"manifest_handlers/replacement_web_app.cc",
"manifest_handlers/replacement_web_app.h",
"manifest_handlers/requirements_info.cc",
"manifest_handlers/requirements_info.h",
"manifest_handlers/sandboxed_page_info.cc",
......@@ -425,6 +427,7 @@ if (enable_extensions) {
"manifest_handlers/incognito_manifest_unittest.cc",
"manifest_handlers/kiosk_mode_info_unittest.cc",
"manifest_handlers/oauth2_manifest_unittest.cc",
"manifest_handlers/replacement_web_app_unittest.cc",
"manifest_handlers/shared_module_manifest_unittest.cc",
"message_bundle_unittest.cc",
"permissions/api_permission_set_unittest.cc",
......
......@@ -286,6 +286,11 @@
"extension", "legacy_packaged_app", "hosted_app", "platform_app"
]
},
"replacement_web_app": {
"channel": "trunk",
"extension_types": ["extension", "platform_app"],
"min_manifest_version": 2
},
"sandbox": {
"channel": "stable",
"extension_types": [
......
......@@ -27,6 +27,7 @@
#include "extensions/common/manifest_handlers/nacl_modules_handler.h"
#include "extensions/common/manifest_handlers/oauth2_manifest_handler.h"
#include "extensions/common/manifest_handlers/offline_enabled_info.h"
#include "extensions/common/manifest_handlers/replacement_web_app.h"
#include "extensions/common/manifest_handlers/requirements_info.h"
#include "extensions/common/manifest_handlers/sandboxed_page_info.h"
#include "extensions/common/manifest_handlers/shared_module_info.h"
......@@ -68,6 +69,7 @@ void RegisterCommonManifestHandlers() {
#endif
registry->RegisterHandler(std::make_unique<OAuth2ManifestHandler>());
registry->RegisterHandler(std::make_unique<OfflineEnabledHandler>());
registry->RegisterHandler(std::make_unique<ReplacementWebAppHandler>());
registry->RegisterHandler(std::make_unique<RequirementsHandler>());
registry->RegisterHandler(std::make_unique<SandboxedPageHandler>());
registry->RegisterHandler(std::make_unique<SharedModuleHandler>());
......
......@@ -133,6 +133,7 @@ const char kPlatformAppBackgroundScripts[] = "app.background.scripts";
const char kPlatformAppContentSecurityPolicy[] = "app.content_security_policy";
const char kPublicKey[] = "key";
const char kRemoveButton[] = "remove_button";
const char kReplacementWebApp[] = "replacement_web_app";
const char kRequirements[] = "requirements";
const char kRunAt[] = "run_at";
const char kSandboxedPages[] = "sandbox.pages";
......@@ -595,6 +596,8 @@ const char kInvalidPermissions[] =
"Invalid value for 'permissions'.";
const char kInvalidPermissionScheme[] =
"Invalid scheme for 'permissions[*]'.";
const char kInvalidReplacementWebApp[] =
"Invalid value for 'replacement_web_app'.";
const char kInvalidRequirement[] =
"Invalid value for requirement \"*\"";
const char kInvalidRequirements[] =
......
......@@ -134,6 +134,7 @@ extern const char kPlatformAppBackgroundPage[];
extern const char kPlatformAppBackgroundScripts[];
extern const char kPlatformAppContentSecurityPolicy[];
extern const char kPublicKey[];
extern const char kReplacementWebApp[];
extern const char kRemoveButton[];
extern const char kRequirements[];
extern const char kRunAt[];
......@@ -424,6 +425,7 @@ extern const char kInvalidPermissionWithDetail[];
extern const char kInvalidPermission[];
extern const char kInvalidPermissions[];
extern const char kInvalidPermissionScheme[];
extern const char kInvalidReplacementWebApp[];
extern const char kInvalidRequirement[];
extern const char kInvalidRequirements[];
extern const char kInvalidRunAt[];
......
......@@ -177,7 +177,7 @@ class ManifestHandlerRegistry {
// Any new manifest handlers added may cause the small_map to overflow
// to the backup std::unordered_map, which we don't want, as that would
// defeat the optimization of using small_map.
static constexpr size_t kHandlerMax = 72;
static constexpr size_t kHandlerMax = 73;
using FallbackMap = std::unordered_map<std::string, ManifestHandler*>;
using ManifestHandlerMap = base::small_map<FallbackMap, kHandlerMax>;
using FallbackPriorityMap = std::unordered_map<ManifestHandler*, int>;
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/common/manifest_handlers/replacement_web_app.h"
#include <memory>
#include "base/strings/utf_string_conversions.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#include "url/gurl.h"
#include "url/url_constants.h"
namespace extensions {
namespace keys = manifest_keys;
namespace errors = manifest_errors;
namespace {
const ReplacementWebAppInfo* GetReplacementWebAppInfo(
const Extension* extension) {
return static_cast<ReplacementWebAppInfo*>(
extension->GetManifestData(keys::kReplacementWebApp));
}
} // namespace
ReplacementWebAppInfo::ReplacementWebAppInfo() {}
ReplacementWebAppInfo::~ReplacementWebAppInfo() {}
// static
bool ReplacementWebAppInfo::IsReplacementWebApp(const Extension* extension,
const GURL& web_app_url) {
const ReplacementWebAppInfo* info = GetReplacementWebAppInfo(extension);
return info && info->replacement_web_app == web_app_url;
}
ReplacementWebAppHandler::ReplacementWebAppHandler() {}
ReplacementWebAppHandler::~ReplacementWebAppHandler() {}
bool ReplacementWebAppHandler::Parse(Extension* extension,
base::string16* error) {
std::string string_value;
if (!extension->manifest()->GetString(keys::kReplacementWebApp,
&string_value)) {
*error = base::ASCIIToUTF16(errors::kInvalidReplacementWebApp);
return false;
}
const GURL replacement_web_app(string_value);
if (!replacement_web_app.is_valid() ||
!replacement_web_app.SchemeIs(url::kHttpsScheme)) {
*error = base::ASCIIToUTF16(errors::kInvalidReplacementWebApp);
return false;
}
auto info = std::make_unique<ReplacementWebAppInfo>();
info->replacement_web_app = std::move(replacement_web_app);
extension->SetManifestData(keys::kReplacementWebApp, std::move(info));
return true;
}
base::span<const char* const> ReplacementWebAppHandler::Keys() const {
static constexpr const char* kKeys[] = {keys::kReplacementWebApp};
return kKeys;
}
} // namespace extensions
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef EXTENSIONS_COMMON_MANIFEST_HANDLERS_REPLACEMENT_WEB_APP_H_
#define EXTENSIONS_COMMON_MANIFEST_HANDLERS_REPLACEMENT_WEB_APP_H_
#include "base/strings/string16.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_handler.h"
class GURL;
namespace extensions {
// A structure to hold the replacement web app that may be specified in the
// manifest of an extension using the "replacement_web_app" key.
struct ReplacementWebAppInfo : public Extension::ManifestData {
ReplacementWebAppInfo();
~ReplacementWebAppInfo() override;
// Returns true if the specified URL is the replacement web app.
static bool IsReplacementWebApp(const Extension* extension,
const GURL& web_app_url);
GURL replacement_web_app;
};
// Parses the "related_web_apps" manifest key.
class ReplacementWebAppHandler : public ManifestHandler {
public:
ReplacementWebAppHandler();
~ReplacementWebAppHandler() override;
bool Parse(Extension* extension, base::string16* error) override;
private:
base::span<const char* const> Keys() const override;
DISALLOW_COPY_AND_ASSIGN(ReplacementWebAppHandler);
};
} // namespace extensions
#endif // EXTENSIONS_COMMON_MANIFEST_HANDLERS_REPLACEMENT_WEB_APP_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <utility>
#include "base/strings/stringprintf.h"
#include "base/test/values_test_util.h"
#include "components/version_info/version_info.h"
#include "extensions/common/features/feature_channel.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/replacement_web_app.h"
#include "extensions/common/manifest_test.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
namespace {
class ReplacementWebAppManifestTest : public ManifestTest {
public:
ReplacementWebAppManifestTest() : channel_(version_info::Channel::UNKNOWN) {}
protected:
ManifestData CreateManifest(const char* replacement_web_app) {
constexpr char kManifest[] =
R"({
"name": "test",
"version": "1",
"manifest_version": 2,
"replacement_web_app": %s
})";
base::Value manifest = base::test::ParseJson(
base::StringPrintf(kManifest, replacement_web_app));
return ManifestData(base::Value::ToUniquePtrValue(std::move(manifest)),
"test");
}
private:
ScopedCurrentChannel channel_;
};
} // namespace
TEST_F(ReplacementWebAppManifestTest, InvalidType) {
LoadAndExpectError(CreateManifest("32"),
manifest_errors::kInvalidReplacementWebApp);
LoadAndExpectError(CreateManifest("true"),
manifest_errors::kInvalidReplacementWebApp);
LoadAndExpectError(CreateManifest(R"("not_a_valid_url")"),
manifest_errors::kInvalidReplacementWebApp);
LoadAndExpectError(CreateManifest("{}"),
manifest_errors::kInvalidReplacementWebApp);
LoadAndExpectError(CreateManifest(R"({"foo": false})"),
manifest_errors::kInvalidReplacementWebApp);
LoadAndExpectError(CreateManifest(R"("http://not_secure.com")"),
manifest_errors::kInvalidReplacementWebApp);
LoadAndExpectError(CreateManifest(R"(["https://secure.com"])"),
manifest_errors::kInvalidReplacementWebApp);
LoadAndExpectError(
CreateManifest(R"(["https://www.google.com", "not_a_valid_url"])"),
manifest_errors::kInvalidReplacementWebApp);
}
TEST_F(ReplacementWebAppManifestTest, VerifyParse) {
scoped_refptr<Extension> good =
LoadAndExpectSuccess(CreateManifest(R"("https://www.google.com")"));
EXPECT_TRUE(ReplacementWebAppInfo::IsReplacementWebApp(
good.get(), GURL("https://www.google.com")));
EXPECT_FALSE(ReplacementWebAppInfo::IsReplacementWebApp(
good.get(), GURL("https://www.youtube.com")));
}
} // namespace extensions
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment