From 6a75a934b64edb19edccf9447056bb6d58aa5705 Mon Sep 17 00:00:00 2001 From: Aleksei Khoroshilov <5928869+goodov@users.noreply.github.com> Date: Fri, 20 Dec 2024 21:56:31 +0700 Subject: [PATCH] Prevent external favicons fetch on password manager page. (#27066) * Prevent external favicons fetch on password manager page. * Add test. --- browser/password_manager/BUILD.gn | 22 +++++ .../password_manager_browsertest.cc | 98 +++++++++++++++++++ .../password_manager/site_favicon.ts | 22 +++++ chromium_src/tools/polymer/html_to_wrapper.py | 22 +++++ .../tools-polymer-html_to_wrapper.py.patch | 11 +++ test/BUILD.gn | 1 + 6 files changed, 176 insertions(+) create mode 100644 browser/password_manager/BUILD.gn create mode 100644 browser/password_manager/password_manager_browsertest.cc create mode 100644 chromium_src/chrome/browser/resources/password_manager/site_favicon.ts create mode 100644 chromium_src/tools/polymer/html_to_wrapper.py create mode 100644 patches/tools-polymer-html_to_wrapper.py.patch diff --git a/browser/password_manager/BUILD.gn b/browser/password_manager/BUILD.gn new file mode 100644 index 000000000000..af7ebb2e4b9d --- /dev/null +++ b/browser/password_manager/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright (c) 2024 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. + +if (!is_android) { + source_set("browser_tests") { + testonly = true + defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + + sources = [ "password_manager_browsertest.cc" ] + + deps = [ + "//brave/browser", + "//chrome/browser", + "//chrome/browser/ui", + "//chrome/test:test_support", + "//chrome/test:test_support_ui", + "//content/test:test_support", + ] + } +} diff --git a/browser/password_manager/password_manager_browsertest.cc b/browser/password_manager/password_manager_browsertest.cc new file mode 100644 index 000000000000..cf53d8c3538e --- /dev/null +++ b/browser/password_manager/password_manager_browsertest.cc @@ -0,0 +1,98 @@ +/* Copyright (c) 2024 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "base/test/bind.h" +#include "chrome/browser/password_manager/profile_password_store_factory.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_commands.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/test/base/chrome_test_utils.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/password_manager/core/browser/password_form_manager_for_ui.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "url/gurl.h" + +class PasswordManagerTest : public InProcessBrowserTest { + public: + PasswordManagerTest() = default; + ~PasswordManagerTest() override = default; + + void SetUpOnMainThread() override { + InProcessBrowserTest::SetUpOnMainThread(); + store_ = ProfilePasswordStoreFactory::GetForProfile( + browser()->profile(), ServiceAccessType::EXPLICIT_ACCESS); + } + + protected: + scoped_refptr store_; +}; + +IN_PROC_BROWSER_TEST_F(PasswordManagerTest, + SavePasswordAndOpenSettingsNoErrors) { + // Create test credentials. + password_manager::PasswordForm form; + form.url = GURL("https://example.com"); + form.signon_realm = "https://example.com"; + form.username_value = u"test_user"; + form.password_value = u"test_password"; + form.scheme = password_manager::PasswordForm::Scheme::kHtml; + base::RunLoop run_loop; + store_->AddLogin(form, run_loop.QuitClosure()); + run_loop.Run(); + + // Open password settings and expect no errors. + content::WebContents* contents = + chrome_test_utils::GetActiveWebContents(this); + content::WebContentsConsoleObserver console_observer(contents); + console_observer.SetFilter(base::BindLambdaForTesting( + [](const content::WebContentsConsoleObserver::Message& message) { + return message.log_level == blink::mojom::ConsoleMessageLevel::kError; + })); + ASSERT_TRUE(ui_test_utils::NavigateToURL( + browser(), GURL(chrome::kChromeUIPasswordManagerURL))); + + // Wait for the password list to be populated. + EXPECT_TRUE(content::ExecJs(contents, R"( + (async () => { + new Promise((resolve) => { + function queryShadowRoot(node, selector) { + const nodes = [...node.querySelectorAll(selector)]; + const nodeIterator = document.createNodeIterator( + node, + NodeFilter.SHOW_ELEMENT, + (node) => + node instanceof Element && node.shadowRoot + ? NodeFilter.FILTER_ACCEPT + : NodeFilter.FILTER_REJECT + ); + + for ( + let currentNode = nodeIterator.nextNode(); + currentNode; + currentNode = nodeIterator.nextNode() + ) { + nodes.push(...queryShadowRoot(currentNode.shadowRoot, selector)); + } + + return nodes; + } + + function checkPasswords() { + const password_items = queryShadowRoot(document, "password-list-item"); + if (password_items.length > 0) { + resolve(true); + return; + } + setTimeout(checkPasswords, 100); + } + checkPasswords(); + }); + })(); + )")); + + EXPECT_TRUE(console_observer.messages().empty()); +} diff --git a/chromium_src/chrome/browser/resources/password_manager/site_favicon.ts b/chromium_src/chrome/browser/resources/password_manager/site_favicon.ts new file mode 100644 index 000000000000..f0a0133c0130 --- /dev/null +++ b/chromium_src/chrome/browser/resources/password_manager/site_favicon.ts @@ -0,0 +1,22 @@ +// Copyright (c) 2024 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +import { RegisterPolymerTemplateModifications } from '//resources/brave/polymer_overriding.js' + +RegisterPolymerTemplateModifications({ + 'site-favicon': (templateContent) => { + const downloadedFavicon = + templateContent.querySelector('#downloadedFavicon') + if (!downloadedFavicon) { + throw new Error( + `[Brave Password Manager Overrides] Could not find '#downloadedFavicon'` + ) + } else { + downloadedFavicon.removeAttribute('auto-src') + } + } +}) + +export * from './site_favicon-chromium.js' diff --git a/chromium_src/tools/polymer/html_to_wrapper.py b/chromium_src/tools/polymer/html_to_wrapper.py new file mode 100644 index 000000000000..ca94ca05a5eb --- /dev/null +++ b/chromium_src/tools/polymer/html_to_wrapper.py @@ -0,0 +1,22 @@ +# Copyright (c) 2024 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. + +import override_utils + +POLYMER_OVERRIDING_TOKEN = '//resources/brave/polymer_overriding.js' +LIT_OVERRIDING_TOKEN = '//resources/brave/lit_overriding.js' + + +@override_utils.override_function(globals()) +def detect_template_type(original_method, definition_file): + with open(definition_file, encoding='utf-8', mode='r') as f: + content = f.read() + + if POLYMER_OVERRIDING_TOKEN in content: + return 'polymer' + if LIT_OVERRIDING_TOKEN in content: + return 'lit' + + return original_method(definition_file) diff --git a/patches/tools-polymer-html_to_wrapper.py.patch b/patches/tools-polymer-html_to_wrapper.py.patch new file mode 100644 index 000000000000..3a560a895a00 --- /dev/null +++ b/patches/tools-polymer-html_to_wrapper.py.patch @@ -0,0 +1,11 @@ +diff --git a/tools/polymer/html_to_wrapper.py b/tools/polymer/html_to_wrapper.py +index 062ef045cecb11d5684806e2875439dad8efdfbd..5e699156c63ada808095ff67a8cbdb58189ebaba 100644 +--- a/tools/polymer/html_to_wrapper.py ++++ b/tools/polymer/html_to_wrapper.py +@@ -282,5 +282,6 @@ def main(argv): + return + + ++from brave_chromium_utils import inline_chromium_src_override; inline_chromium_src_override(globals(), locals()) + if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/test/BUILD.gn b/test/BUILD.gn index 7373603347e6..937692b026eb 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -1136,6 +1136,7 @@ test("brave_browser_tests") { "//brave/browser/ai_chat:browser_tests", "//brave/browser/banners:browser_tests", "//brave/browser/brave_ads/creatives/search_result_ad:browser_tests", + "//brave/browser/password_manager:browser_tests", "//brave/browser/sharing_hub:browser_tests", "//brave/browser/ui/ai_rewriter:browsertest", "//brave/browser/ui/geolocation:browser_tests",