fix: broken chrome.scripting
compilation (#39725)
fix: broken chrome.scripting impl after roll
This commit is contained in:
parent
89659fa9c9
commit
54d8402a6c
2 changed files with 264 additions and 331 deletions
|
@ -51,9 +51,7 @@ constexpr char kDuplicateFileSpecifiedError[] =
|
||||||
"Duplicate file specified: '*'.";
|
"Duplicate file specified: '*'.";
|
||||||
constexpr char kExactlyOneOfCssAndFilesError[] =
|
constexpr char kExactlyOneOfCssAndFilesError[] =
|
||||||
"Exactly one of 'css' and 'files' must be specified.";
|
"Exactly one of 'css' and 'files' must be specified.";
|
||||||
constexpr char kFilesExceededSizeLimitError[] =
|
constexpr char kNonExistentScriptIdError[] = "Nonexistent script ID '*'";
|
||||||
"Scripts could not be loaded because '*' exceeds the maximum script size "
|
|
||||||
"or the extension's maximum total script size.";
|
|
||||||
|
|
||||||
// Note: CSS always injects as soon as possible, so we default to
|
// Note: CSS always injects as soon as possible, so we default to
|
||||||
// document_start. Because of tab loading, there's no guarantee this will
|
// document_start. Because of tab loading, there's no guarantee this will
|
||||||
|
@ -61,45 +59,6 @@ constexpr char kFilesExceededSizeLimitError[] =
|
||||||
constexpr mojom::RunLocation kCSSRunLocation =
|
constexpr mojom::RunLocation kCSSRunLocation =
|
||||||
mojom::RunLocation::kDocumentStart;
|
mojom::RunLocation::kDocumentStart;
|
||||||
|
|
||||||
// Returns if the extension provided `script_id` (without an internal UserScript
|
|
||||||
// prefix) is valid and populates `error` if invalid.
|
|
||||||
bool IsScriptIDValid(const std::string& script_id, std::string* error) {
|
|
||||||
if (script_id.empty()) {
|
|
||||||
*error = "Script's ID must not be empty";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (script_id[0] == UserScript::kReservedScriptIDPrefix) {
|
|
||||||
*error = base::StringPrintf("Script's ID '%s' must not start with '%c'",
|
|
||||||
script_id.c_str(),
|
|
||||||
UserScript::kReservedScriptIDPrefix);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterates over `scripts` and adds a prefix to each script's id to indicate
|
|
||||||
// that the script is a dynamic content script. Returns false and populates
|
|
||||||
// `error` if any extension provided id in `scripts` is invalid. While this
|
|
||||||
// might result in only some of the ids in `scripts` being modified, this should
|
|
||||||
// have no effect on API calls as the API method handler will return with
|
|
||||||
// `error`.
|
|
||||||
bool AddDynamicScriptPrefixToScriptIDs(
|
|
||||||
std::vector<api::scripting::RegisteredContentScript>& scripts,
|
|
||||||
std::string* error) {
|
|
||||||
CHECK(error);
|
|
||||||
for (auto& script : scripts) {
|
|
||||||
if (!IsScriptIDValid(script.id, error)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
script.id = scripting::CreateDynamicScriptID(script.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts the given `style_origin` to a CSSOrigin.
|
// Converts the given `style_origin` to a CSSOrigin.
|
||||||
mojom::CSSOrigin ConvertStyleOriginToCSSOrigin(
|
mojom::CSSOrigin ConvertStyleOriginToCSSOrigin(
|
||||||
api::scripting::StyleOrigin style_origin) {
|
api::scripting::StyleOrigin style_origin) {
|
||||||
|
@ -537,37 +496,12 @@ std::unique_ptr<UserScript> ParseUserScript(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidateContentScriptsResult ValidateParsedScriptsOnFileThread(
|
|
||||||
ExtensionResource::SymlinkPolicy symlink_policy,
|
|
||||||
std::unique_ptr<UserScriptList> scripts) {
|
|
||||||
DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence());
|
|
||||||
|
|
||||||
// Validate that claimed script resources actually exist, and are UTF-8
|
|
||||||
// encoded.
|
|
||||||
std::string error;
|
|
||||||
std::vector<InstallWarning> warnings;
|
|
||||||
bool are_script_files_valid = script_parsing::ValidateFileSources(
|
|
||||||
*scripts, symlink_policy, &error, &warnings);
|
|
||||||
|
|
||||||
// Script files over the per script/extension limit are recorded as warnings.
|
|
||||||
// However, for the scripting API we should treat "install warnings" as
|
|
||||||
// errors by turning this call into a no-op and returning an error.
|
|
||||||
if (!warnings.empty() && error.empty()) {
|
|
||||||
error = ErrorUtils::FormatErrorMessage(kFilesExceededSizeLimitError,
|
|
||||||
warnings[0].specific);
|
|
||||||
are_script_files_valid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(std::move(scripts), are_script_files_valid
|
|
||||||
? absl::nullopt
|
|
||||||
: absl::make_optional(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts a UserScript object to a api::scripting::RegisteredContentScript
|
// Converts a UserScript object to a api::scripting::RegisteredContentScript
|
||||||
// object, used for getRegisteredContentScripts.
|
// object, used for getRegisteredContentScripts.
|
||||||
api::scripting::RegisteredContentScript CreateRegisteredContentScriptInfo(
|
api::scripting::RegisteredContentScript CreateRegisteredContentScriptInfo(
|
||||||
const UserScript& script) {
|
const UserScript& script) {
|
||||||
api::scripting::RegisteredContentScript script_info;
|
api::scripting::RegisteredContentScript script_info;
|
||||||
|
CHECK_EQ(UserScript::Source::kDynamicContentScript, script.GetSource());
|
||||||
script_info.id = script.id();
|
script_info.id = script.id();
|
||||||
|
|
||||||
script_info.matches.emplace();
|
script_info.matches.emplace();
|
||||||
|
@ -965,250 +899,6 @@ ScriptingRegisterContentScriptsFunction::
|
||||||
ScriptingRegisterContentScriptsFunction::
|
ScriptingRegisterContentScriptsFunction::
|
||||||
~ScriptingRegisterContentScriptsFunction() = default;
|
~ScriptingRegisterContentScriptsFunction() = default;
|
||||||
|
|
||||||
ExtensionFunction::ResponseAction
|
|
||||||
ScriptingRegisterContentScriptsFunction::Run() {
|
|
||||||
absl::optional<api::scripting::RegisterContentScripts::Params> params =
|
|
||||||
api::scripting::RegisterContentScripts::Params::Create(args());
|
|
||||||
EXTENSION_FUNCTION_VALIDATE(params);
|
|
||||||
|
|
||||||
std::vector<api::scripting::RegisteredContentScript>& scripts =
|
|
||||||
params->scripts;
|
|
||||||
std::string error;
|
|
||||||
// Add the prefix for dynamic content scripts onto the IDs of all scripts in
|
|
||||||
// `scripts` before continuing.
|
|
||||||
if (!AddDynamicScriptPrefixToScriptIDs(scripts, &error)) {
|
|
||||||
return RespondNow(Error(std::move(error)));
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtensionUserScriptLoader* loader =
|
|
||||||
ExtensionSystem::Get(browser_context())
|
|
||||||
->user_script_manager()
|
|
||||||
->GetUserScriptLoaderForExtension(extension()->id());
|
|
||||||
std::set<std::string> existing_script_ids = loader->GetDynamicScriptIDs();
|
|
||||||
std::set<std::string> new_script_ids;
|
|
||||||
|
|
||||||
for (const auto& script : scripts) {
|
|
||||||
if (base::Contains(existing_script_ids, script.id) ||
|
|
||||||
base::Contains(new_script_ids, script.id)) {
|
|
||||||
std::string error_script_id =
|
|
||||||
UserScript::TrimPrefixFromScriptID(script.id);
|
|
||||||
return RespondNow(Error(base::StringPrintf("Duplicate script ID '%s'",
|
|
||||||
error_script_id.c_str())));
|
|
||||||
}
|
|
||||||
|
|
||||||
new_script_ids.insert(script.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::u16string parse_error;
|
|
||||||
auto parsed_scripts = std::make_unique<UserScriptList>();
|
|
||||||
std::set<std::string> persistent_script_ids;
|
|
||||||
const int valid_schemes = UserScript::ValidUserScriptSchemes(
|
|
||||||
scripting::kScriptsCanExecuteEverywhere);
|
|
||||||
|
|
||||||
parsed_scripts->reserve(scripts.size());
|
|
||||||
for (size_t i = 0; i < scripts.size(); ++i) {
|
|
||||||
if (!scripts[i].matches) {
|
|
||||||
std::string error_script_id =
|
|
||||||
UserScript::TrimPrefixFromScriptID(scripts[i].id);
|
|
||||||
return RespondNow(
|
|
||||||
Error(base::StringPrintf("Script with ID '%s' must specify 'matches'",
|
|
||||||
error_script_id.c_str())));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse/Create user script.
|
|
||||||
std::unique_ptr<UserScript> user_script =
|
|
||||||
ParseUserScript(browser_context(), *extension(), scripts[i], i,
|
|
||||||
valid_schemes, &parse_error);
|
|
||||||
if (!user_script)
|
|
||||||
return RespondNow(Error(base::UTF16ToASCII(parse_error)));
|
|
||||||
|
|
||||||
// Scripts will persist across sessions by default.
|
|
||||||
if (!scripts[i].persist_across_sessions ||
|
|
||||||
*scripts[i].persist_across_sessions) {
|
|
||||||
persistent_script_ids.insert(user_script->id());
|
|
||||||
}
|
|
||||||
parsed_scripts->push_back(std::move(user_script));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add new script IDs now in case another call with the same script IDs is
|
|
||||||
// made immediately following this one.
|
|
||||||
loader->AddPendingDynamicScriptIDs(std::move(new_script_ids));
|
|
||||||
|
|
||||||
GetExtensionFileTaskRunner()->PostTaskAndReplyWithResult(
|
|
||||||
FROM_HERE,
|
|
||||||
base::BindOnce(&ValidateParsedScriptsOnFileThread,
|
|
||||||
script_parsing::GetSymlinkPolicy(extension()),
|
|
||||||
std::move(parsed_scripts)),
|
|
||||||
base::BindOnce(&ScriptingRegisterContentScriptsFunction::
|
|
||||||
OnContentScriptFilesValidated,
|
|
||||||
this, std::move(persistent_script_ids)));
|
|
||||||
|
|
||||||
// Balanced in `OnContentScriptFilesValidated()` or
|
|
||||||
// `OnContentScriptsRegistered()`.
|
|
||||||
AddRef();
|
|
||||||
return RespondLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScriptingRegisterContentScriptsFunction::OnContentScriptFilesValidated(
|
|
||||||
std::set<std::string> persistent_script_ids,
|
|
||||||
ValidateContentScriptsResult result) {
|
|
||||||
// We cannot proceed if the `browser_context` is not valid as the
|
|
||||||
// `ExtensionSystem` will not exist.
|
|
||||||
if (!browser_context()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto error = std::move(result.second);
|
|
||||||
auto scripts = std::move(result.first);
|
|
||||||
ExtensionUserScriptLoader* loader =
|
|
||||||
ExtensionSystem::Get(browser_context())
|
|
||||||
->user_script_manager()
|
|
||||||
->GetUserScriptLoaderForExtension(extension()->id());
|
|
||||||
|
|
||||||
if (error.has_value()) {
|
|
||||||
std::set<std::string> ids_to_remove;
|
|
||||||
for (const auto& script : *scripts)
|
|
||||||
ids_to_remove.insert(script->id());
|
|
||||||
|
|
||||||
loader->RemovePendingDynamicScriptIDs(std::move(ids_to_remove));
|
|
||||||
Respond(Error(std::move(*error)));
|
|
||||||
Release(); // Matches the `AddRef()` in `Run()`.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
loader->AddDynamicScripts(
|
|
||||||
std::move(scripts), std::move(persistent_script_ids),
|
|
||||||
base::BindOnce(
|
|
||||||
&ScriptingRegisterContentScriptsFunction::OnContentScriptsRegistered,
|
|
||||||
this));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScriptingRegisterContentScriptsFunction::OnContentScriptsRegistered(
|
|
||||||
const absl::optional<std::string>& error) {
|
|
||||||
if (error.has_value())
|
|
||||||
Respond(Error(std::move(*error)));
|
|
||||||
else
|
|
||||||
Respond(NoArguments());
|
|
||||||
Release(); // Matches the `AddRef()` in `Run()`.
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptingGetRegisteredContentScriptsFunction::
|
|
||||||
ScriptingGetRegisteredContentScriptsFunction() = default;
|
|
||||||
ScriptingGetRegisteredContentScriptsFunction::
|
|
||||||
~ScriptingGetRegisteredContentScriptsFunction() = default;
|
|
||||||
|
|
||||||
ExtensionFunction::ResponseAction
|
|
||||||
ScriptingGetRegisteredContentScriptsFunction::Run() {
|
|
||||||
absl::optional<api::scripting::GetRegisteredContentScripts::Params> params =
|
|
||||||
api::scripting::GetRegisteredContentScripts::Params::Create(args());
|
|
||||||
EXTENSION_FUNCTION_VALIDATE(params);
|
|
||||||
|
|
||||||
const absl::optional<api::scripting::ContentScriptFilter>& filter =
|
|
||||||
params->filter;
|
|
||||||
std::set<std::string> id_filter;
|
|
||||||
if (filter && filter->ids) {
|
|
||||||
for (const std::string& id : *(filter->ids)) {
|
|
||||||
id_filter.insert(scripting::CreateDynamicScriptID(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtensionUserScriptLoader* loader =
|
|
||||||
ExtensionSystem::Get(browser_context())
|
|
||||||
->user_script_manager()
|
|
||||||
->GetUserScriptLoaderForExtension(extension()->id());
|
|
||||||
const UserScriptList& dynamic_scripts = loader->GetLoadedDynamicScripts();
|
|
||||||
|
|
||||||
std::vector<api::scripting::RegisteredContentScript> script_infos;
|
|
||||||
std::set<std::string> persistent_script_ids =
|
|
||||||
loader->GetPersistentDynamicScriptIDs();
|
|
||||||
for (const std::unique_ptr<UserScript>& script : dynamic_scripts) {
|
|
||||||
if (id_filter.empty() || base::Contains(id_filter, script->id())) {
|
|
||||||
auto registered_script = CreateRegisteredContentScriptInfo(*script);
|
|
||||||
registered_script.persist_across_sessions =
|
|
||||||
base::Contains(persistent_script_ids, script->id());
|
|
||||||
|
|
||||||
// Remove the internally used prefix from the `script`'s ID before
|
|
||||||
// returning.
|
|
||||||
registered_script.id = script->GetIDWithoutPrefix();
|
|
||||||
script_infos.push_back(std::move(registered_script));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RespondNow(
|
|
||||||
ArgumentList(api::scripting::GetRegisteredContentScripts::Results::Create(
|
|
||||||
script_infos)));
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptingUnregisterContentScriptsFunction::
|
|
||||||
ScriptingUnregisterContentScriptsFunction() = default;
|
|
||||||
ScriptingUnregisterContentScriptsFunction::
|
|
||||||
~ScriptingUnregisterContentScriptsFunction() = default;
|
|
||||||
|
|
||||||
ExtensionFunction::ResponseAction
|
|
||||||
ScriptingUnregisterContentScriptsFunction::Run() {
|
|
||||||
auto params =
|
|
||||||
api::scripting::UnregisterContentScripts::Params::Create(args());
|
|
||||||
EXTENSION_FUNCTION_VALIDATE(params);
|
|
||||||
|
|
||||||
absl::optional<api::scripting::ContentScriptFilter>& filter = params->filter;
|
|
||||||
std::set<std::string> ids_to_remove;
|
|
||||||
|
|
||||||
ExtensionUserScriptLoader* loader =
|
|
||||||
ExtensionSystem::Get(browser_context())
|
|
||||||
->user_script_manager()
|
|
||||||
->GetUserScriptLoaderForExtension(extension()->id());
|
|
||||||
std::set<std::string> existing_script_ids = loader->GetDynamicScriptIDs();
|
|
||||||
if (filter && filter->ids) {
|
|
||||||
for (const auto& provided_id : *filter->ids) {
|
|
||||||
std::string error;
|
|
||||||
if (!IsScriptIDValid(provided_id, &error)) {
|
|
||||||
return RespondNow(Error(std::move(error)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the dynamic content script prefix to `provided_id` before checking
|
|
||||||
// against `existing_script_ids`.
|
|
||||||
std::string id_with_prefix =
|
|
||||||
scripting::CreateDynamicScriptID(provided_id);
|
|
||||||
if (!base::Contains(existing_script_ids, id_with_prefix)) {
|
|
||||||
return RespondNow(Error(base::StringPrintf("Nonexistent script ID '%s'",
|
|
||||||
provided_id.c_str())));
|
|
||||||
}
|
|
||||||
|
|
||||||
ids_to_remove.insert(id_with_prefix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(crbug.com/1300657): Only clear all scripts if `filter` did not specify
|
|
||||||
// the list of scripts ids to remove.
|
|
||||||
if (ids_to_remove.empty()) {
|
|
||||||
loader->ClearDynamicScripts(
|
|
||||||
base::BindOnce(&ScriptingUnregisterContentScriptsFunction::
|
|
||||||
OnContentScriptsUnregistered,
|
|
||||||
this));
|
|
||||||
} else {
|
|
||||||
loader->RemoveDynamicScripts(
|
|
||||||
std::move(ids_to_remove),
|
|
||||||
base::BindOnce(&ScriptingUnregisterContentScriptsFunction::
|
|
||||||
OnContentScriptsUnregistered,
|
|
||||||
this));
|
|
||||||
}
|
|
||||||
|
|
||||||
return RespondLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScriptingUnregisterContentScriptsFunction::OnContentScriptsUnregistered(
|
|
||||||
const absl::optional<std::string>& error) {
|
|
||||||
if (error.has_value())
|
|
||||||
Respond(Error(std::move(*error)));
|
|
||||||
else
|
|
||||||
Respond(NoArguments());
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptingUpdateContentScriptsFunction::ScriptingUpdateContentScriptsFunction() =
|
|
||||||
default;
|
|
||||||
ScriptingUpdateContentScriptsFunction::
|
|
||||||
~ScriptingUpdateContentScriptsFunction() = default;
|
|
||||||
|
|
||||||
ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
|
ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
|
||||||
absl::optional<api::scripting::UpdateContentScripts::Params> params =
|
absl::optional<api::scripting::UpdateContentScripts::Params> params =
|
||||||
api::scripting::UpdateContentScripts::Params::Create(args());
|
api::scripting::UpdateContentScripts::Params::Create(args());
|
||||||
|
@ -1217,9 +907,15 @@ ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
|
||||||
std::vector<api::scripting::RegisteredContentScript>& scripts =
|
std::vector<api::scripting::RegisteredContentScript>& scripts =
|
||||||
params->scripts;
|
params->scripts;
|
||||||
std::string error;
|
std::string error;
|
||||||
|
|
||||||
// Add the prefix for dynamic content scripts onto the IDs of all scripts in
|
// Add the prefix for dynamic content scripts onto the IDs of all scripts in
|
||||||
// `scripts` before continuing.
|
// `scripts` before continuing.
|
||||||
if (!AddDynamicScriptPrefixToScriptIDs(scripts, &error)) {
|
std::set<std::string> ids_to_update = scripting::CreateDynamicScriptIds(
|
||||||
|
scripts, UserScript::Source::kDynamicContentScript,
|
||||||
|
std::set<std::string>(), &error);
|
||||||
|
|
||||||
|
if (!error.empty()) {
|
||||||
|
CHECK(ids_to_update.empty());
|
||||||
return RespondNow(Error(std::move(error)));
|
return RespondNow(Error(std::move(error)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1232,11 +928,12 @@ ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
|
||||||
loaded_scripts_metadata;
|
loaded_scripts_metadata;
|
||||||
const UserScriptList& dynamic_scripts = loader->GetLoadedDynamicScripts();
|
const UserScriptList& dynamic_scripts = loader->GetLoadedDynamicScripts();
|
||||||
for (const std::unique_ptr<UserScript>& script : dynamic_scripts) {
|
for (const std::unique_ptr<UserScript>& script : dynamic_scripts) {
|
||||||
loaded_scripts_metadata.emplace(script->id(),
|
if (script->GetSource() == UserScript::Source::kDynamicContentScript) {
|
||||||
CreateRegisteredContentScriptInfo(*script));
|
loaded_scripts_metadata.emplace(
|
||||||
|
script->id(), CreateRegisteredContentScriptInfo(*script));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::string> ids_to_update;
|
|
||||||
for (const auto& script : scripts) {
|
for (const auto& script : scripts) {
|
||||||
std::string error_script_id = UserScript::TrimPrefixFromScriptID(script.id);
|
std::string error_script_id = UserScript::TrimPrefixFromScriptID(script.id);
|
||||||
if (loaded_scripts_metadata.find(script.id) ==
|
if (loaded_scripts_metadata.find(script.id) ==
|
||||||
|
@ -1246,13 +943,6 @@ ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
|
||||||
"or is not fully registered",
|
"or is not fully registered",
|
||||||
error_script_id.c_str())));
|
error_script_id.c_str())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base::Contains(ids_to_update, script.id)) {
|
|
||||||
return RespondNow(Error(base::StringPrintf("Duplicate script ID '%s'",
|
|
||||||
error_script_id.c_str())));
|
|
||||||
}
|
|
||||||
|
|
||||||
ids_to_update.insert(script.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::u16string parse_error;
|
std::u16string parse_error;
|
||||||
|
@ -1321,7 +1011,7 @@ ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
|
||||||
|
|
||||||
GetExtensionFileTaskRunner()->PostTaskAndReplyWithResult(
|
GetExtensionFileTaskRunner()->PostTaskAndReplyWithResult(
|
||||||
FROM_HERE,
|
FROM_HERE,
|
||||||
base::BindOnce(&ValidateParsedScriptsOnFileThread,
|
base::BindOnce(&scripting::ValidateParsedScriptsOnFileThread,
|
||||||
script_parsing::GetSymlinkPolicy(extension()),
|
script_parsing::GetSymlinkPolicy(extension()),
|
||||||
std::move(parsed_scripts)),
|
std::move(parsed_scripts)),
|
||||||
base::BindOnce(
|
base::BindOnce(
|
||||||
|
@ -1334,12 +1024,257 @@ ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
|
||||||
return RespondLater();
|
return RespondLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptingUpdateContentScriptsFunction::OnContentScriptFilesValidated(
|
void ScriptingRegisterContentScriptsFunction::OnContentScriptFilesValidated(
|
||||||
std::set<std::string> persistent_script_ids,
|
std::set<std::string> persistent_script_ids,
|
||||||
ValidateContentScriptsResult result) {
|
scripting::ValidateScriptsResult result) {
|
||||||
// We cannot proceed if the `browser_context` is not valid as the
|
// We cannot proceed if the `browser_context` is not valid as the
|
||||||
// `ExtensionSystem` will not exist.
|
// `ExtensionSystem` will not exist.
|
||||||
if (!browser_context()) {
|
if (!browser_context()) {
|
||||||
|
Release(); // Matches the `AddRef()` in `Run()`.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto error = std::move(result.second);
|
||||||
|
auto scripts = std::move(result.first);
|
||||||
|
ExtensionUserScriptLoader* loader =
|
||||||
|
ExtensionSystem::Get(browser_context())
|
||||||
|
->user_script_manager()
|
||||||
|
->GetUserScriptLoaderForExtension(extension()->id());
|
||||||
|
|
||||||
|
if (error.has_value()) {
|
||||||
|
std::set<std::string> ids_to_remove;
|
||||||
|
for (const auto& script : *scripts) {
|
||||||
|
ids_to_remove.insert(script->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
loader->RemovePendingDynamicScriptIDs(std::move(ids_to_remove));
|
||||||
|
Respond(Error(std::move(*error)));
|
||||||
|
Release(); // Matches the `AddRef()` in `Run()`.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loader->AddDynamicScripts(
|
||||||
|
std::move(scripts), std::move(persistent_script_ids),
|
||||||
|
base::BindOnce(
|
||||||
|
&ScriptingRegisterContentScriptsFunction::OnContentScriptsRegistered,
|
||||||
|
this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptingRegisterContentScriptsFunction::OnContentScriptsRegistered(
|
||||||
|
const absl::optional<std::string>& error) {
|
||||||
|
if (error.has_value())
|
||||||
|
Respond(Error(std::move(*error)));
|
||||||
|
else
|
||||||
|
Respond(NoArguments());
|
||||||
|
Release(); // Matches the `AddRef()` in `Run()`.
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptingGetRegisteredContentScriptsFunction::
|
||||||
|
ScriptingGetRegisteredContentScriptsFunction() = default;
|
||||||
|
ScriptingGetRegisteredContentScriptsFunction::
|
||||||
|
~ScriptingGetRegisteredContentScriptsFunction() = default;
|
||||||
|
|
||||||
|
ExtensionFunction::ResponseAction
|
||||||
|
ScriptingGetRegisteredContentScriptsFunction::Run() {
|
||||||
|
absl::optional<api::scripting::GetRegisteredContentScripts::Params> params =
|
||||||
|
api::scripting::GetRegisteredContentScripts::Params::Create(args());
|
||||||
|
EXTENSION_FUNCTION_VALIDATE(params);
|
||||||
|
|
||||||
|
const absl::optional<api::scripting::ContentScriptFilter>& filter =
|
||||||
|
params->filter;
|
||||||
|
std::set<std::string> id_filter;
|
||||||
|
if (filter && filter->ids) {
|
||||||
|
for (const std::string& id : *(filter->ids)) {
|
||||||
|
id_filter.insert(scripting::AddPrefixToDynamicScriptId(
|
||||||
|
id, UserScript::Source::kDynamicContentScript));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtensionUserScriptLoader* loader =
|
||||||
|
ExtensionSystem::Get(browser_context())
|
||||||
|
->user_script_manager()
|
||||||
|
->GetUserScriptLoaderForExtension(extension()->id());
|
||||||
|
const UserScriptList& dynamic_scripts = loader->GetLoadedDynamicScripts();
|
||||||
|
|
||||||
|
std::vector<api::scripting::RegisteredContentScript> script_infos;
|
||||||
|
std::set<std::string> persistent_script_ids =
|
||||||
|
loader->GetPersistentDynamicScriptIDs();
|
||||||
|
for (const std::unique_ptr<UserScript>& script : dynamic_scripts) {
|
||||||
|
if (script->GetSource() != UserScript::Source::kDynamicContentScript) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!id_filter.empty() && !base::Contains(id_filter, script->id())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto registered_script = CreateRegisteredContentScriptInfo(*script);
|
||||||
|
registered_script.persist_across_sessions =
|
||||||
|
base::Contains(persistent_script_ids, script->id());
|
||||||
|
// Remove the internally used prefix from the `script`'s ID before
|
||||||
|
// returning.
|
||||||
|
registered_script.id = script->GetIDWithoutPrefix();
|
||||||
|
script_infos.push_back(std::move(registered_script));
|
||||||
|
}
|
||||||
|
|
||||||
|
return RespondNow(
|
||||||
|
ArgumentList(api::scripting::GetRegisteredContentScripts::Results::Create(
|
||||||
|
script_infos)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptingUnregisterContentScriptsFunction::
|
||||||
|
ScriptingUnregisterContentScriptsFunction() = default;
|
||||||
|
ScriptingUnregisterContentScriptsFunction::
|
||||||
|
~ScriptingUnregisterContentScriptsFunction() = default;
|
||||||
|
|
||||||
|
ExtensionFunction::ResponseAction
|
||||||
|
ScriptingUnregisterContentScriptsFunction::Run() {
|
||||||
|
auto params =
|
||||||
|
api::scripting::UnregisterContentScripts::Params::Create(args());
|
||||||
|
EXTENSION_FUNCTION_VALIDATE(params);
|
||||||
|
|
||||||
|
absl::optional<api::scripting::ContentScriptFilter>& filter = params->filter;
|
||||||
|
ExtensionUserScriptLoader* loader =
|
||||||
|
ExtensionSystem::Get(browser_context())
|
||||||
|
->user_script_manager()
|
||||||
|
->GetUserScriptLoaderForExtension(extension()->id());
|
||||||
|
|
||||||
|
// TODO(crbug.com/1300657): Only clear all scripts if `filter` did not specify
|
||||||
|
// the list of scripts ids to remove.
|
||||||
|
if (!filter || !filter->ids || filter->ids->empty()) {
|
||||||
|
loader->ClearDynamicScripts(
|
||||||
|
UserScript::Source::kDynamicContentScript,
|
||||||
|
base::BindOnce(&ScriptingUnregisterContentScriptsFunction::
|
||||||
|
OnContentScriptsUnregistered,
|
||||||
|
this));
|
||||||
|
return RespondLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<std::string> ids_to_remove;
|
||||||
|
std::set<std::string> existing_script_ids =
|
||||||
|
loader->GetDynamicScriptIDs(UserScript::Source::kDynamicContentScript);
|
||||||
|
|
||||||
|
std::string error;
|
||||||
|
for (const auto& provided_id : *filter->ids) {
|
||||||
|
if (!scripting::IsScriptIdValid(provided_id, &error)) {
|
||||||
|
return RespondNow(Error(std::move(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the dynamic content script prefix to `provided_id` before checking
|
||||||
|
// against `existing_script_ids`.
|
||||||
|
std::string id_with_prefix = scripting::AddPrefixToDynamicScriptId(
|
||||||
|
provided_id, UserScript::Source::kDynamicContentScript);
|
||||||
|
if (!base::Contains(existing_script_ids, id_with_prefix)) {
|
||||||
|
return RespondNow(Error(ErrorUtils::FormatErrorMessage(
|
||||||
|
kNonExistentScriptIdError, provided_id.c_str())));
|
||||||
|
}
|
||||||
|
|
||||||
|
ids_to_remove.insert(id_with_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
loader->RemoveDynamicScripts(
|
||||||
|
std::move(ids_to_remove),
|
||||||
|
base::BindOnce(&ScriptingUnregisterContentScriptsFunction::
|
||||||
|
OnContentScriptsUnregistered,
|
||||||
|
this));
|
||||||
|
|
||||||
|
return RespondLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptingUnregisterContentScriptsFunction::OnContentScriptsUnregistered(
|
||||||
|
const absl::optional<std::string>& error) {
|
||||||
|
if (error.has_value())
|
||||||
|
Respond(Error(std::move(*error)));
|
||||||
|
else
|
||||||
|
Respond(NoArguments());
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptingUpdateContentScriptsFunction::ScriptingUpdateContentScriptsFunction() =
|
||||||
|
default;
|
||||||
|
ScriptingUpdateContentScriptsFunction::
|
||||||
|
~ScriptingUpdateContentScriptsFunction() = default;
|
||||||
|
|
||||||
|
ExtensionFunction::ResponseAction
|
||||||
|
ScriptingRegisterContentScriptsFunction::Run() {
|
||||||
|
absl::optional<api::scripting::RegisterContentScripts::Params> params =
|
||||||
|
api::scripting::RegisterContentScripts::Params::Create(args());
|
||||||
|
EXTENSION_FUNCTION_VALIDATE(params);
|
||||||
|
|
||||||
|
std::vector<api::scripting::RegisteredContentScript>& scripts =
|
||||||
|
params->scripts;
|
||||||
|
ExtensionUserScriptLoader* loader =
|
||||||
|
ExtensionSystem::Get(browser_context())
|
||||||
|
->user_script_manager()
|
||||||
|
->GetUserScriptLoaderForExtension(extension()->id());
|
||||||
|
|
||||||
|
// Create script ids for dynamic content scripts.
|
||||||
|
std::string error;
|
||||||
|
std::set<std::string> existing_script_ids =
|
||||||
|
loader->GetDynamicScriptIDs(UserScript::Source::kDynamicContentScript);
|
||||||
|
std::set<std::string> new_script_ids = scripting::CreateDynamicScriptIds(
|
||||||
|
scripts, UserScript::Source::kDynamicContentScript, existing_script_ids,
|
||||||
|
&error);
|
||||||
|
|
||||||
|
if (!error.empty()) {
|
||||||
|
CHECK(new_script_ids.empty());
|
||||||
|
return RespondNow(Error(std::move(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse content scripts.
|
||||||
|
std::u16string parse_error;
|
||||||
|
auto parsed_scripts = std::make_unique<UserScriptList>();
|
||||||
|
std::set<std::string> persistent_script_ids;
|
||||||
|
const int valid_schemes = UserScript::ValidUserScriptSchemes(
|
||||||
|
scripting::kScriptsCanExecuteEverywhere);
|
||||||
|
|
||||||
|
parsed_scripts->reserve(scripts.size());
|
||||||
|
for (size_t i = 0; i < scripts.size(); ++i) {
|
||||||
|
if (!scripts[i].matches) {
|
||||||
|
std::string error_script_id =
|
||||||
|
UserScript::TrimPrefixFromScriptID(scripts[i].id);
|
||||||
|
return RespondNow(
|
||||||
|
Error(base::StringPrintf("Script with ID '%s' must specify 'matches'",
|
||||||
|
error_script_id.c_str())));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<UserScript> user_script =
|
||||||
|
ParseUserScript(browser_context(), *extension(), scripts[i], i,
|
||||||
|
valid_schemes, &parse_error);
|
||||||
|
if (!user_script)
|
||||||
|
return RespondNow(Error(base::UTF16ToASCII(parse_error)));
|
||||||
|
|
||||||
|
// Scripts will persist across sessions by default.
|
||||||
|
if (!scripts[i].persist_across_sessions ||
|
||||||
|
*scripts[i].persist_across_sessions) {
|
||||||
|
persistent_script_ids.insert(user_script->id());
|
||||||
|
}
|
||||||
|
parsed_scripts->push_back(std::move(user_script));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new script IDs now in case another call with the same script IDs is
|
||||||
|
// made immediately following this one.
|
||||||
|
loader->AddPendingDynamicScriptIDs(std::move(new_script_ids));
|
||||||
|
|
||||||
|
GetExtensionFileTaskRunner()->PostTaskAndReplyWithResult(
|
||||||
|
FROM_HERE,
|
||||||
|
base::BindOnce(&scripting::ValidateParsedScriptsOnFileThread,
|
||||||
|
script_parsing::GetSymlinkPolicy(extension()),
|
||||||
|
std::move(parsed_scripts)),
|
||||||
|
base::BindOnce(&ScriptingRegisterContentScriptsFunction::
|
||||||
|
OnContentScriptFilesValidated,
|
||||||
|
this, std::move(persistent_script_ids)));
|
||||||
|
|
||||||
|
// Balanced in `OnContentScriptFilesValidated()` or
|
||||||
|
// `OnContentScriptsRegistered()`.
|
||||||
|
AddRef();
|
||||||
|
return RespondLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptingUpdateContentScriptsFunction::OnContentScriptFilesValidated(
|
||||||
|
std::set<std::string> persistent_script_ids,
|
||||||
|
scripting::ValidateScriptsResult result) {
|
||||||
|
// We cannot proceed if the `browser_context` is not valid as the
|
||||||
|
// `ExtensionSystem` will not exist.
|
||||||
|
if (!browser_context()) {
|
||||||
|
Release(); // Matches the `AddRef()` in `Run()`.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "chrome/common/extensions/api/scripting.h"
|
#include "chrome/common/extensions/api/scripting.h"
|
||||||
|
#include "extensions/browser/api/scripting/scripting_utils.h"
|
||||||
#include "extensions/browser/extension_function.h"
|
#include "extensions/browser/extension_function.h"
|
||||||
#include "extensions/browser/script_executor.h"
|
#include "extensions/browser/script_executor.h"
|
||||||
#include "extensions/common/mojom/code_injection.mojom.h"
|
#include "extensions/common/mojom/code_injection.mojom.h"
|
||||||
|
@ -108,9 +109,6 @@ class ScriptingRemoveCSSFunction : public ExtensionFunction {
|
||||||
void OnCSSRemoved(std::vector<ScriptExecutor::FrameResult> results);
|
void OnCSSRemoved(std::vector<ScriptExecutor::FrameResult> results);
|
||||||
};
|
};
|
||||||
|
|
||||||
using ValidateContentScriptsResult =
|
|
||||||
std::pair<std::unique_ptr<UserScriptList>, absl::optional<std::string>>;
|
|
||||||
|
|
||||||
class ScriptingRegisterContentScriptsFunction : public ExtensionFunction {
|
class ScriptingRegisterContentScriptsFunction : public ExtensionFunction {
|
||||||
public:
|
public:
|
||||||
DECLARE_EXTENSION_FUNCTION("scripting.registerContentScripts",
|
DECLARE_EXTENSION_FUNCTION("scripting.registerContentScripts",
|
||||||
|
@ -131,7 +129,7 @@ class ScriptingRegisterContentScriptsFunction : public ExtensionFunction {
|
||||||
// Called when script files have been checked.
|
// Called when script files have been checked.
|
||||||
void OnContentScriptFilesValidated(
|
void OnContentScriptFilesValidated(
|
||||||
std::set<std::string> persistent_script_ids,
|
std::set<std::string> persistent_script_ids,
|
||||||
ValidateContentScriptsResult result);
|
scripting::ValidateScriptsResult result);
|
||||||
|
|
||||||
// Called when content scripts have been registered.
|
// Called when content scripts have been registered.
|
||||||
void OnContentScriptsRegistered(const absl::optional<std::string>& error);
|
void OnContentScriptsRegistered(const absl::optional<std::string>& error);
|
||||||
|
@ -196,7 +194,7 @@ class ScriptingUpdateContentScriptsFunction : public ExtensionFunction {
|
||||||
// Called when script files have been checked.
|
// Called when script files have been checked.
|
||||||
void OnContentScriptFilesValidated(
|
void OnContentScriptFilesValidated(
|
||||||
std::set<std::string> persistent_script_ids,
|
std::set<std::string> persistent_script_ids,
|
||||||
ValidateContentScriptsResult result);
|
scripting::ValidateScriptsResult result);
|
||||||
|
|
||||||
// Called when content scripts have been updated.
|
// Called when content scripts have been updated.
|
||||||
void OnContentScriptsUpdated(const absl::optional<std::string>& error);
|
void OnContentScriptsUpdated(const absl::optional<std::string>& error);
|
||||||
|
|
Loading…
Reference in a new issue