From d17176a7439584330cbb5815b1bd68fc5bc37c04 Mon Sep 17 00:00:00 2001 From: Kelvin Jiang Date: Sun, 18 Dec 2022 07:17:57 +0000 Subject: [PATCH] [Extensions] Do not load scripts that exceed a maximum size This CL enforces maximum sizes for individual content scripts and all scripts in an extension. The maximum sizes are: - 500 MB per script - 1 GB for all content scripts (manifest and dynamic) for a single extension Any file in a script entry that would exceed one of these limits will not be loaded and will generate an install warning for the extension if it's a manifest script. For dynamic scripts, the registerContentScripts function should return an error and be a no-op if a limit is exceeded. This will be tackled in a follow up. Bug: 1379187 Change-Id: I2de4f123f85783350b10415c5cee022355f47f1f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4095461 Commit-Queue: Kelvin Jiang Reviewed-by: Devlin Cronin Cr-Commit-Position: refs/heads/main@{#1084757} --- .../extensions/api/scripting/scripting_api.cc | 5 +- .../extensions/content_script_apitest.cc | 34 +++++++ .../content_scripts/large_scripts/big.js | 23 +++++ .../large_scripts/change_title.js | 5 ++ .../large_scripts/inject_element.js | 7 ++ .../large_scripts/inject_element_2.js | 20 +++++ .../large_scripts/manifest.json | 29 ++++++ .../content_scripts/large_scripts/worker.js | 40 +++++++++ .../browser/extension_user_script_loader.cc | 56 ++++++++++-- .../content_scripts_handler.cc | 2 +- .../common/utils/content_script_utils.cc | 88 ++++++++++++++++--- .../common/utils/content_script_utils.h | 23 ++++- extensions/strings/extensions_strings.grd | 3 + ...ION_CONTENT_SCRIPT_FILE_TOO_LARGE.png.sha1 | 1 + 14 files changed, 315 insertions(+), 21 deletions(-) create mode 100644 chrome/test/data/extensions/api_test/content_scripts/large_scripts/big.js create mode 100644 chrome/test/data/extensions/api_test/content_scripts/large_scripts/change_title.js create mode 100644 chrome/test/data/extensions/api_test/content_scripts/large_scripts/inject_element.js create mode 100644 chrome/test/data/extensions/api_test/content_scripts/large_scripts/inject_element_2.js create mode 100644 chrome/test/data/extensions/api_test/content_scripts/large_scripts/manifest.json create mode 100644 chrome/test/data/extensions/api_test/content_scripts/large_scripts/worker.js create mode 100644 extensions/strings/extensions_strings_grd/IDS_EXTENSION_CONTENT_SCRIPT_FILE_TOO_LARGE.png.sha1 diff --git a/chrome/browser/extensions/api/scripting/scripting_api.cc b/chrome/browser/extensions/api/scripting/scripting_api.cc index b3e29dc63838b..089980b0513b7 100644 --- a/chrome/browser/extensions/api/scripting/scripting_api.cc +++ b/chrome/browser/extensions/api/scripting/scripting_api.cc @@ -501,8 +501,9 @@ ValidateContentScriptsResult ValidateParsedScriptsOnFileThread( // Validate that claimed script resources actually exist, and are UTF-8 // encoded. std::string error; - bool are_script_files_valid = - script_parsing::ValidateFileSources(*scripts, symlink_policy, &error); + std::vector warnings; + bool are_script_files_valid = script_parsing::ValidateFileSources( + *scripts, symlink_policy, &error, &warnings); return std::make_pair(std::move(scripts), are_script_files_valid ? absl::nullopt diff --git a/chrome/browser/extensions/content_script_apitest.cc b/chrome/browser/extensions/content_script_apitest.cc index e2ce790854d2f..8960971758f8a 100644 --- a/chrome/browser/extensions/content_script_apitest.cc +++ b/chrome/browser/extensions/content_script_apitest.cc @@ -45,9 +45,12 @@ #include "extensions/browser/browsertest_util.h" #include "extensions/browser/content_script_tracker.h" #include "extensions/browser/extension_registry.h" +#include "extensions/common/api/content_scripts.h" #include "extensions/common/extension.h" #include "extensions/common/extension_features.h" #include "extensions/common/identifiability_metrics.h" +#include "extensions/common/utils/content_script_utils.h" +#include "extensions/strings/grit/extensions_strings.h" #include "extensions/test/extension_test_message_listener.h" #include "extensions/test/result_catcher.h" #include "extensions/test/test_extension_dir.h" @@ -58,6 +61,7 @@ #include "services/network/public/cpp/features.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/privacy_budget/identifiable_surface.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/page_transition_types.h" #include "url/gurl.h" @@ -406,6 +410,36 @@ IN_PROC_BROWSER_TEST_F(ContentScriptApiTest, FetchExemptFromCSP) { EXPECT_EQ("Failed to fetch", listener.message()); } +// Test that content scripts that exceed the individual script size limit or the +// total extensions script limit will not be loaded/injected, and will generate +// an install warning. +IN_PROC_BROWSER_TEST_F(ContentScriptApiTest, LargeScriptFilesNotLoaded) { + auto single_scripts_limit_reset = + script_parsing::CreateScopedMaxScriptLengthForTesting(800u); + auto extension_scripts_limit_reset = + script_parsing::CreateScopedMaxScriptsLengthPerExtensionForTesting(1000u); + ASSERT_TRUE(StartEmbeddedTestServer()); + + ResultCatcher result_catcher; + const Extension* extension = + LoadExtension(test_data_dir_.AppendASCII("content_scripts/large_scripts"), + {.ignore_manifest_warnings = true}); + ASSERT_TRUE(extension); + EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message(); + + std::vector expected_warnings; + expected_warnings.emplace_back( + l10n_util::GetStringFUTF8(IDS_EXTENSION_CONTENT_SCRIPT_FILE_TOO_LARGE, + u"big.js"), + api::content_scripts::ManifestKeys::kContentScripts); + expected_warnings.emplace_back( + l10n_util::GetStringFUTF8(IDS_EXTENSION_CONTENT_SCRIPT_FILE_TOO_LARGE, + u"inject_element_2.js"), + api::content_scripts::ManifestKeys::kContentScripts); + + EXPECT_EQ(extension->install_warnings(), expected_warnings); +} + class ContentScriptCssInjectionTest : public ExtensionApiTest { protected: // TODO(rdevlin.cronin): Make a testing switch that looks like FeatureSwitch, diff --git a/chrome/test/data/extensions/api_test/content_scripts/large_scripts/big.js b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/big.js new file mode 100644 index 0000000000000..b8ef5a6abd783 --- /dev/null +++ b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/big.js @@ -0,0 +1,23 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var div = document.createElement('div'); +div.id = 'BIG'; +document.body.appendChild(div); +/* +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +PADDING OUT THE FILE TO BE OVER 800 BYTES +*/ diff --git a/chrome/test/data/extensions/api_test/content_scripts/large_scripts/change_title.js b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/change_title.js new file mode 100644 index 0000000000000..ae4561cdc7904 --- /dev/null +++ b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/change_title.js @@ -0,0 +1,5 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +document.title = 'I CHANGED TITLE!!!'; diff --git a/chrome/test/data/extensions/api_test/content_scripts/large_scripts/inject_element.js b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/inject_element.js new file mode 100644 index 0000000000000..9356405f2004f --- /dev/null +++ b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/inject_element.js @@ -0,0 +1,7 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var div = document.createElement('div'); +div.id = 'injected'; +document.body.appendChild(div); diff --git a/chrome/test/data/extensions/api_test/content_scripts/large_scripts/inject_element_2.js b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/inject_element_2.js new file mode 100644 index 0000000000000..59141b6a35045 --- /dev/null +++ b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/inject_element_2.js @@ -0,0 +1,20 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var div = document.createElement('div'); +div.id = 'injected_2'; +document.body.appendChild(div); +/* +PADDING OUT THE FILE TO BE OVER 700 BYTES +PADDING OUT THE FILE TO BE OVER 700 BYTES +PADDING OUT THE FILE TO BE OVER 700 BYTES +PADDING OUT THE FILE TO BE OVER 700 BYTES +PADDING OUT THE FILE TO BE OVER 700 BYTES +PADDING OUT THE FILE TO BE OVER 700 BYTES +PADDING OUT THE FILE TO BE OVER 700 BYTES +PADDING OUT THE FILE TO BE OVER 700 BYTES +PADDING OUT THE FILE TO BE OVER 700 BYTES +PADDING OUT THE FILE TO BE OVER 700 BYTES +PADDING OUT THE FILE TO BE OVER 700 BYTES +*/ diff --git a/chrome/test/data/extensions/api_test/content_scripts/large_scripts/manifest.json b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/manifest.json new file mode 100644 index 0000000000000..ab518373b79e4 --- /dev/null +++ b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/manifest.json @@ -0,0 +1,29 @@ +{ + "name": "Large content scripts", + "version": "1.0", + "manifest_version": 3, + "description": "Content scripts that surpass the size limit are not loaded.", + "background": { + "service_worker": "worker.js", + "type": "module" + }, + "permissions": ["scripting", "tabs"], + "host_permissions": ["*://example.com/*"], + "content_scripts": [ + { + "matches": [""], + "js": ["big.js"], + "run_at": "document_end" + }, + { + "matches": [""], + "js": ["inject_element.js", "change_title.js"], + "run_at": "document_end" + }, + { + "matches": [""], + "js": ["inject_element_2.js"], + "run_at": "document_end" + } + ] +} diff --git a/chrome/test/data/extensions/api_test/content_scripts/large_scripts/worker.js b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/worker.js new file mode 100644 index 0000000000000..1123c105d99de --- /dev/null +++ b/chrome/test/data/extensions/api_test/content_scripts/large_scripts/worker.js @@ -0,0 +1,40 @@ +// Copyright 2022 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {openTab} from '/_test_resources/test_util/tabs_util.js'; + +function getInjectedElementIds() { + let childIds = []; + for (const child of document.body.children) + childIds.push(child.id); + return childIds.sort(); +}; + +chrome.test.runTests([ + async function checkContentScriptInjectionResults() { + async function getTitleForTab(tabId) { + let results = await chrome.scripting.executeScript( + {target: {tabId}, func: () => document.title}); + chrome.test.assertEq(1, results.length); + return results[0].result; + }; + + const config = await chrome.test.getConfig(); + const url = `http://example.com:${config.testServer.port}/simple.html`; + const tab = await openTab(url); + const title = await getTitleForTab(tab.id); + chrome.test.assertEq('I CHANGED TITLE!!!', title); + + let results = await chrome.scripting.executeScript( + {target: {tabId: tab.id}, func: getInjectedElementIds}); + + // Only inject_element_1.js and change_title.js should be loaded/injected as + // big.js exceeds the individual script size limit, and loading + // inject_element_2.js would exceed the extension's total script size limit. + chrome.test.assertEq(1, results.length); + chrome.test.assertEq(['injected'], results[0].result); + + chrome.test.succeed(); + }, +]); diff --git a/extensions/browser/extension_user_script_loader.cc b/extensions/browser/extension_user_script_loader.cc index f4a449eaa0976..a50fb50f85808 100644 --- a/extensions/browser/extension_user_script_loader.cc +++ b/extensions/browser/extension_user_script_loader.cc @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -111,7 +112,8 @@ struct VerifyContentInfo { // couldn't be read. std::tuple, ReadScriptContentSource> ReadScriptContent(UserScript::File* script_file, - const absl::optional& script_resource_id) { + const absl::optional& script_resource_id, + size_t& remaining_length) { const base::FilePath& path = ExtensionResource::GetFilePath( script_file->extension_root(), script_file->relative_path(), ExtensionResource::SYMLINKS_MUST_RESOLVE_WITHIN_ROOT); @@ -127,11 +129,20 @@ ReadScriptContent(UserScript::File* script_file, return {absl::nullopt, ReadScriptContentSource::kFile}; } + size_t max_script_length = + std::min(remaining_length, script_parsing::GetMaxScriptLength()); std::string content; - if (!base::ReadFileToString(path, &content)) { - LOG(WARNING) << "Failed to load user script file: " << path.value(); + if (!base::ReadFileToStringWithMaxSize(path, &content, max_script_length)) { + if (content.empty()) { + LOG(WARNING) << "Failed to load user script file: " << path.value(); + } else { + LOG(WARNING) << "Failed to load user script file, maximum size exceeded: " + << path.value(); + } return {absl::nullopt, ReadScriptContentSource::kFile}; } + + remaining_length -= content.size(); return {std::move(content), ReadScriptContentSource::kFile}; } @@ -202,9 +213,11 @@ void LoadScriptContent(const mojom::HostID& host_id, UserScript::File* script_file, const absl::optional& script_resource_id, const SubstitutionMap* localization_messages, - const scoped_refptr& verifier) { + const scoped_refptr& verifier, + size_t& remaining_length) { DCHECK(script_file); - auto [content, source] = ReadScriptContent(script_file, script_resource_id); + auto [content, source] = + ReadScriptContent(script_file, script_resource_id, remaining_length); bool needs_content_verification = source == ReadScriptContentSource::kFile; if (needs_content_verification && verifier.get()) { @@ -265,6 +278,23 @@ void FillScriptFileResourceIds(const UserScript::FileList& script_files, } } +// Returns the total length of scripts that were previously loaded (i.e. not +// present in `added_script_ids`). +size_t GetTotalLoadedScriptsLength( + UserScriptList* user_scripts, + const std::set& added_script_ids) { + size_t total_length = 0u; + for (const std::unique_ptr& script : *user_scripts) { + if (added_script_ids.count(script->id()) == 0) { + for (const auto& js_script : script->js_scripts()) + total_length += js_script->GetContent().length(); + for (const auto& js_script : script->css_scripts()) + total_length += js_script->GetContent().length(); + } + } + return total_length; +} + void LoadUserScripts( UserScriptList* user_scripts, ScriptResourceIds script_resource_ids, @@ -277,6 +307,17 @@ void LoadUserScripts( size_t manifest_script_length = 0u; size_t dynamic_script_length = 0u; + // Calculate the remaining storage allocated for scripts for this extension by + // subtracting the length of all loaded scripts from the extension's max + // scripts length. Note that subtraction is only done if the result will be + // positive (to avoid unsigned wraparound). + size_t loaded_length = + GetTotalLoadedScriptsLength(user_scripts, added_script_ids); + size_t remaining_length = + loaded_length >= script_parsing::GetMaxScriptsLengthPerExtension() + ? 0u + : script_parsing::GetMaxScriptsLengthPerExtension() - loaded_length; + for (const std::unique_ptr& script : *user_scripts) { size_t script_files_length = 0u; @@ -287,7 +328,7 @@ void LoadUserScripts( if (script_file->GetContent().empty()) { LoadScriptContent(script->host_id(), script_file.get(), script_resource_ids[script_file.get()], nullptr, - verifier); + verifier, remaining_length); } script_files_length += script_file->GetContent().length(); @@ -303,7 +344,8 @@ void LoadUserScripts( if (script_file->GetContent().empty()) { LoadScriptContent(script->host_id(), script_file.get(), script_resource_ids[script_file.get()], - localization_messages.get(), verifier); + localization_messages.get(), verifier, + remaining_length); } script_files_length += script_file->GetContent().length(); diff --git a/extensions/common/manifest_handlers/content_scripts_handler.cc b/extensions/common/manifest_handlers/content_scripts_handler.cc index 06bd219a47dc9..19bd68172181b 100644 --- a/extensions/common/manifest_handlers/content_scripts_handler.cc +++ b/extensions/common/manifest_handlers/content_scripts_handler.cc @@ -256,7 +256,7 @@ bool ContentScriptsHandler::Validate( // and are UTF-8 encoded. return script_parsing::ValidateFileSources( ContentScriptsInfo::GetContentScripts(extension), - script_parsing::GetSymlinkPolicy(extension), error); + script_parsing::GetSymlinkPolicy(extension), error, warnings); } } // namespace extensions diff --git a/extensions/common/utils/content_script_utils.cc b/extensions/common/utils/content_script_utils.cc index a572e0c873fdd..558d828fab1bf 100644 --- a/extensions/common/utils/content_script_utils.cc +++ b/extensions/common/utils/content_script_utils.cc @@ -6,6 +6,7 @@ #include +#include #include #include "base/files/file_util.h" @@ -15,6 +16,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "content/public/common/url_constants.h" +#include "extensions/common/api/content_scripts.h" #include "extensions/common/error_utils.h" #include "extensions/common/extension_features.h" #include "extensions/common/manifest_constants.h" @@ -36,16 +38,46 @@ namespace script_parsing { namespace { +size_t g_max_script_length_in_bytes = 1024u * 1024u * 500u; // 500 MB. +size_t g_max_scripts_length_per_extension_in_bytes = + 1024u * 1024u * 1024u; // 1 GB. + // Returns false and sets the error if script file can't be loaded, or if it's -// not UTF-8 encoded. +// not UTF-8 encoded. If a script file can be loaded but will exceed +// `max_script_length`, return true but add an install warning to `warnings`. +// Otherwise, decrement `remaining_length` by the script file's size. bool IsScriptValid(const base::FilePath& path, const base::FilePath& relative_path, + size_t max_script_length, int message_id, - std::string* error) { + std::string* error, + std::vector* warnings, + size_t& remaining_length) { + InstallWarning script_file_too_large_warning( + l10n_util::GetStringFUTF8(IDS_EXTENSION_CONTENT_SCRIPT_FILE_TOO_LARGE, + relative_path.LossyDisplayName()), + api::content_scripts::ManifestKeys::kContentScripts); + if (remaining_length == 0u) { + warnings->push_back(std::move(script_file_too_large_warning)); + return true; + } + std::string content; - if (!base::PathExists(path) || !base::ReadFileToString(path, &content)) { - *error = - l10n_util::GetStringFUTF8(message_id, relative_path.LossyDisplayName()); + std::string file_not_read_error = + l10n_util::GetStringFUTF8(message_id, relative_path.LossyDisplayName()); + + if (!base::PathExists(path)) { + *error = file_not_read_error; + return false; + } + + bool read_successful = + base::ReadFileToStringWithMaxSize(path, &content, max_script_length); + // If the size of the file in `path` exceeds `max_script_length`, + // ReadFileToStringWithMaxSize will return false but `content` will contain + // the file's content truncated to `max_script_length`. + if (!read_successful && content.length() != max_script_length) { + *error = file_not_read_error; return false; } @@ -55,11 +87,38 @@ bool IsScriptValid(const base::FilePath& path, return false; } + if (read_successful) { + remaining_length -= content.size(); + } else { + // Even though the script file is over the max size, we don't throw a hard + // error so as not to break any existing extensions for which this is the + // case. + warnings->push_back(std::move(script_file_too_large_warning)); + } return true; } } // namespace +size_t GetMaxScriptLength() { + return g_max_script_length_in_bytes; +} + +size_t GetMaxScriptsLengthPerExtension() { + return g_max_scripts_length_per_extension_in_bytes; +} + +ScopedMaxScriptLengthOverride CreateScopedMaxScriptLengthForTesting( // IN-TEST + size_t max) { + return ScopedMaxScriptLengthOverride(&g_max_script_length_in_bytes, max); +} + +ScopedMaxScriptLengthOverride +CreateScopedMaxScriptsLengthPerExtensionForTesting(size_t max) { + return ScopedMaxScriptLengthOverride( + &g_max_scripts_length_per_extension_in_bytes, max); +} + mojom::RunLocation ConvertManifestRunLocation( api::content_scripts::RunAt run_at) { switch (run_at) { @@ -209,15 +268,21 @@ bool ParseFileSources(const Extension* extension, bool ValidateFileSources(const UserScriptList& scripts, ExtensionResource::SymlinkPolicy symlink_policy, - std::string* error) { + std::string* error, + std::vector* warnings) { + size_t remaining_scripts_length = GetMaxScriptsLengthPerExtension(); + for (const std::unique_ptr& script : scripts) { for (const std::unique_ptr& js_script : script->js_scripts()) { const base::FilePath& path = ExtensionResource::GetFilePath( js_script->extension_root(), js_script->relative_path(), symlink_policy); - if (!IsScriptValid(path, js_script->relative_path(), - IDS_EXTENSION_LOAD_JAVASCRIPT_FAILED, error)) { + size_t max_script_length = + std::min(remaining_scripts_length, GetMaxScriptLength()); + if (!IsScriptValid(path, js_script->relative_path(), max_script_length, + IDS_EXTENSION_LOAD_JAVASCRIPT_FAILED, error, warnings, + remaining_scripts_length)) { return false; } } @@ -227,8 +292,11 @@ bool ValidateFileSources(const UserScriptList& scripts, const base::FilePath& path = ExtensionResource::GetFilePath( css_script->extension_root(), css_script->relative_path(), symlink_policy); - if (!IsScriptValid(path, css_script->relative_path(), - IDS_EXTENSION_LOAD_CSS_FAILED, error)) { + size_t max_script_length = + std::min(remaining_scripts_length, GetMaxScriptLength()); + if (!IsScriptValid(path, css_script->relative_path(), max_script_length, + IDS_EXTENSION_LOAD_CSS_FAILED, error, warnings, + remaining_scripts_length)) { return false; } } diff --git a/extensions/common/utils/content_script_utils.h b/extensions/common/utils/content_script_utils.h index 154c5cc97d7c4..a0db64fea28d2 100644 --- a/extensions/common/utils/content_script_utils.h +++ b/extensions/common/utils/content_script_utils.h @@ -7,6 +7,7 @@ #include +#include "base/auto_reset.h" #include "base/callback.h" #include "extensions/common/api/content_scripts.h" #include "extensions/common/extension.h" @@ -18,6 +19,25 @@ namespace extensions { namespace script_parsing { +// Returns the maximum length allowed in an individual script file. Scripts +// above this length will not be loaded. +size_t GetMaxScriptLength(); + +// Returns the maximum allowed total length for all scripts loaded for a single +// extension. Any scripts past this limit will not be loaded. +size_t GetMaxScriptsLengthPerExtension(); + +using ScopedMaxScriptLengthOverride = base::AutoReset; + +// Temporarily sets the max per-file limit to `max`. The value gets reset once +// the AutoReset falls out of scope and is destroyed. +ScopedMaxScriptLengthOverride CreateScopedMaxScriptLengthForTesting(size_t max); + +// Temporarily sets the per-extension limit to `max`. The value gets reset once +// the AutoReset falls out of scope and is destroyed. +ScopedMaxScriptLengthOverride +CreateScopedMaxScriptsLengthPerExtensionForTesting(size_t max); + // Converts api::content_scripts::RunAt to mojom::RunLocation. mojom::RunLocation ConvertManifestRunLocation( api::content_scripts::RunAt run_at); @@ -56,7 +76,8 @@ bool ParseFileSources(const Extension* extension, // I/O. bool ValidateFileSources(const UserScriptList& scripts, ExtensionResource::SymlinkPolicy symlink_policy, - std::string* error); + std::string* error, + std::vector* warnings); ExtensionResource::SymlinkPolicy GetSymlinkPolicy(const Extension* extension); diff --git a/extensions/strings/extensions_strings.grd b/extensions/strings/extensions_strings.grd index 992acd937a92e..eb965b2bd89b3 100644 --- a/extensions/strings/extensions_strings.grd +++ b/extensions/strings/extensions_strings.grd @@ -214,6 +214,9 @@ There is already a CRX file present with this name. + + Could not load file '$1file.js' for content script as it would exceed the maximum script size or the extension's maximum total content script size. + Input directory must exist. diff --git a/extensions/strings/extensions_strings_grd/IDS_EXTENSION_CONTENT_SCRIPT_FILE_TOO_LARGE.png.sha1 b/extensions/strings/extensions_strings_grd/IDS_EXTENSION_CONTENT_SCRIPT_FILE_TOO_LARGE.png.sha1 new file mode 100644 index 0000000000000..7c0b193db39c2 --- /dev/null +++ b/extensions/strings/extensions_strings_grd/IDS_EXTENSION_CONTENT_SCRIPT_FILE_TOO_LARGE.png.sha1 @@ -0,0 +1 @@ +aae4bae434a25109f18d94f9bf93eb73a8251bbc \ No newline at end of file