Option to disable autofill while in private browsing mode (#19585)
This commit is contained in:
@@ -150,6 +150,14 @@
|
||||
</message>
|
||||
</if>
|
||||
|
||||
<!-- Settings / Autofill -->
|
||||
<message name="IDS_SETTINGS_BRAVE_AUTOFILL_PRIVATE_WINDOWS_LABEL" desc="The label to enable autofill in private profiles">
|
||||
Allow auto-fill in private windows
|
||||
</message>
|
||||
<message name="IDS_SETTINGS_BRAVE_AUTOFILL_PRIVATE_WINDOWS_DESC" desc="The description for the label to enable autofill in private profiles">
|
||||
Info from regular windows can be read/auto-filled in private windows
|
||||
</message>
|
||||
|
||||
<!-- Settings / New tab page -->
|
||||
<message name="IDS_SETTINGS_NEW_TAB" desc="The text label for the New Tab settings page">
|
||||
New Tab Page
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Copyright (c) 2023 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/path_service.h"
|
||||
#include "brave/components/constants/brave_paths.h"
|
||||
#include "brave/components/constants/pref_names.h"
|
||||
#include "chrome/browser/password_manager/chrome_password_manager_client.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/test/base/in_process_browser_test.h"
|
||||
#include "chrome/test/base/ui_test_utils.h"
|
||||
#include "components/autofill/content/browser/content_autofill_driver.h"
|
||||
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
|
||||
#include "components/autofill/core/browser/browser_autofill_manager.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/test/browser_test.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
#include "net/dns/mock_host_resolver.h"
|
||||
|
||||
class BraveAutofillBrowserTest : public InProcessBrowserTest {
|
||||
public:
|
||||
void SetUpOnMainThread() override {
|
||||
InProcessBrowserTest::SetUpOnMainThread();
|
||||
host_resolver()->AddRule("*", "127.0.0.1");
|
||||
|
||||
brave::RegisterPathProvider();
|
||||
base::FilePath test_data_dir;
|
||||
base::PathService::Get(brave::DIR_TEST_DATA, &test_data_dir);
|
||||
embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
|
||||
|
||||
ASSERT_TRUE(embedded_test_server()->Start());
|
||||
}
|
||||
|
||||
content::WebContents* PrepareWebContents(Browser* browser, const GURL& url) {
|
||||
TabStripModel* model = browser->tab_strip_model();
|
||||
auto* active_contents = model->GetActiveWebContents();
|
||||
EXPECT_TRUE(content::NavigateToURL(active_contents, url));
|
||||
EXPECT_TRUE(WaitForLoadStop(active_contents));
|
||||
EXPECT_EQ(url, active_contents->GetVisibleURL());
|
||||
return active_contents;
|
||||
}
|
||||
|
||||
void TestAutofillInWindow(Browser* browser, const GURL& url, bool enabled) {
|
||||
auto* active_contents = PrepareWebContents(browser, url);
|
||||
// Logins.
|
||||
autofill::ChromeAutofillClient* autofill_client =
|
||||
autofill::ChromeAutofillClient::FromWebContentsForTesting(
|
||||
active_contents);
|
||||
EXPECT_EQ(autofill_client->IsAutocompleteEnabled(), enabled);
|
||||
// Passwords.
|
||||
ChromePasswordManagerClient* client =
|
||||
ChromePasswordManagerClient::FromWebContents(active_contents);
|
||||
EXPECT_EQ(client->IsFillingEnabled(url), enabled);
|
||||
// Other info.
|
||||
autofill::ContentAutofillDriver* cross_driver =
|
||||
autofill::ContentAutofillDriverFactory::FromWebContents(active_contents)
|
||||
->DriverForFrame(active_contents->GetPrimaryMainFrame());
|
||||
ASSERT_TRUE(cross_driver);
|
||||
EXPECT_EQ(static_cast<autofill::BrowserAutofillManager*>(
|
||||
cross_driver->autofill_manager())
|
||||
->IsAutofillEnabled(),
|
||||
enabled);
|
||||
}
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(BraveAutofillBrowserTest,
|
||||
AutofillIsNotAllowedInPrivateWindows) {
|
||||
GURL url(
|
||||
embedded_test_server()->GetURL("example.com", "/brave_scheme_load.html"));
|
||||
|
||||
// Disable autofill in private windows.
|
||||
browser()->profile()->GetPrefs()->SetBoolean(kBraveAutofillPrivateWindows,
|
||||
false);
|
||||
TestAutofillInWindow(browser(), url, true);
|
||||
Browser* private_browser = CreateIncognitoBrowser(nullptr);
|
||||
TestAutofillInWindow(private_browser, url, false);
|
||||
|
||||
// Enable autofill in private windows.
|
||||
browser()->profile()->GetPrefs()->SetBoolean(kBraveAutofillPrivateWindows,
|
||||
true);
|
||||
TestAutofillInWindow(browser(), url, true);
|
||||
TestAutofillInWindow(private_browser, url, true);
|
||||
|
||||
CloseBrowserSynchronously(private_browser);
|
||||
}
|
||||
@@ -210,7 +210,8 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
|
||||
brave_perf_predictor::PerfPredictorTabHelper::RegisterProfilePrefs(registry);
|
||||
brave_perf_predictor::P3ABandwidthSavingsTracker::RegisterProfilePrefs(
|
||||
registry);
|
||||
|
||||
// autofill
|
||||
registry->RegisterBooleanPref(kBraveAutofillPrivateWindows, true);
|
||||
// appearance
|
||||
registry->RegisterBooleanPref(kShowBookmarksButton, true);
|
||||
registry->RegisterBooleanPref(kShowSidePanelButton, true);
|
||||
|
||||
@@ -132,6 +132,10 @@ const PrefsUtil::TypedPrefMap& BravePrefsUtil::GetAllowlistedKeys() {
|
||||
(*s_brave_allowlist)[prefs::kSyncedDefaultPrivateSearchProviderGUID] =
|
||||
settings_api::PrefType::PREF_TYPE_NUMBER;
|
||||
|
||||
// autofill prefs
|
||||
(*s_brave_allowlist)[kBraveAutofillPrivateWindows] =
|
||||
settings_api::PrefType::PREF_TYPE_BOOLEAN;
|
||||
|
||||
// appearance prefs
|
||||
(*s_brave_allowlist)[kShowBookmarksButton] =
|
||||
settings_api::PrefType::PREF_TYPE_BOOLEAN;
|
||||
|
||||
@@ -27,8 +27,9 @@ namespace brave {
|
||||
|
||||
const std::vector<const char*>& GetBravePersistentPrefNames() {
|
||||
static base::NoDestructor<std::vector<const char*>> brave_allowlist({
|
||||
kBraveAutofillPrivateWindows,
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
prefs::kSidePanelHorizontalAlignment, kTabMuteIndicatorNotClickable,
|
||||
prefs::kSidePanelHorizontalAlignment, kTabMuteIndicatorNotClickable,
|
||||
brave_tabs::kVerticalTabsExpandedWidth,
|
||||
brave_tabs::kVerticalTabsEnabled, brave_tabs::kVerticalTabsCollapsed,
|
||||
brave_tabs::kVerticalTabsFloatingEnabled,
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2023 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 {html, RegisterPolymerTemplateModifications} from 'chrome://resources/brave/polymer_overriding.js'
|
||||
|
||||
import {loadTimeData} from '../i18n_setup.js'
|
||||
|
||||
RegisterPolymerTemplateModifications({
|
||||
'settings-autofill-page': (templateContent) => {
|
||||
templateContent.appendChild(html`
|
||||
<settings-toggle-button
|
||||
class="hr"
|
||||
label="${loadTimeData.getString('autofillInPrivateSettingLabel')}"
|
||||
sub-label="${loadTimeData.getString('autofillInPrivateSettingDesc')}"
|
||||
id="autofill-private-profies"
|
||||
pref="{{prefs.brave.autofill_private_windows}}"
|
||||
</settings-toggle-button>
|
||||
`)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -12,6 +12,7 @@
|
||||
import './config.js'
|
||||
import { ContentSettingsTypes } from '../site_settings/constants.js'
|
||||
import './about_page.js'
|
||||
import './autofill_page.js'
|
||||
import './appearance_page.js'
|
||||
import './basic_page.js'
|
||||
import './clear_browsing_data_dialog.js'
|
||||
|
||||
@@ -68,6 +68,7 @@ brave_settings_non_web_component_files = [
|
||||
"brave_new_tab_page/brave_new_tab_browser_proxy.ts",
|
||||
"brave_leo_assistant_page/brave_leo_assistant_browser_proxy.ts",
|
||||
"brave_overrides/about_page.ts",
|
||||
"brave_overrides/autofill_page.ts",
|
||||
"brave_overrides/appearance_page.ts",
|
||||
"brave_overrides/basic_page.ts",
|
||||
"brave_overrides/clear_browsing_data_dialog.ts",
|
||||
|
||||
@@ -38,11 +38,15 @@ source_set("tor") {
|
||||
"//brave/components/tor",
|
||||
"//brave/components/tor:pref_names",
|
||||
"//chrome/common",
|
||||
"//components/autofill/content/browser",
|
||||
"//components/autofill/core/browser",
|
||||
"//components/keyed_service/content",
|
||||
"//components/safe_browsing/core/common:safe_browsing_prefs",
|
||||
"//components/translate/core/browser",
|
||||
"//content/public/browser",
|
||||
"//net",
|
||||
"//third_party/blink/public/common",
|
||||
"//url",
|
||||
]
|
||||
|
||||
# Below dep list are not directly used tor target.
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "brave/components/brave_component_updater/browser/brave_component.h"
|
||||
#include "brave/components/brave_shields/browser/brave_shields_util.h"
|
||||
#include "brave/components/constants/brave_paths.h"
|
||||
#include "brave/components/constants/pref_names.h"
|
||||
#include "brave/components/tor/brave_tor_client_updater.h"
|
||||
#include "brave/components/tor/brave_tor_pluggable_transport_updater.h"
|
||||
#include "brave/components/tor/tor_launcher_factory.h"
|
||||
@@ -33,8 +34,10 @@
|
||||
#include "brave/components/tor/tor_utils.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
|
||||
#include "chrome/browser/password_manager/chrome_password_manager_client.h"
|
||||
#include "chrome/browser/prefs/incognito_mode_prefs.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/browser/ui/browser_finder.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
@@ -42,6 +45,9 @@
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "chrome/test/base/in_process_browser_test.h"
|
||||
#include "chrome/test/base/ui_test_utils.h"
|
||||
#include "components/autofill/content/browser/content_autofill_driver.h"
|
||||
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
|
||||
#include "components/autofill/core/browser/browser_autofill_manager.h"
|
||||
#include "components/policy/core/common/policy_pref_names.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "content/public/browser/ssl_host_state_delegate.h"
|
||||
@@ -53,6 +59,29 @@
|
||||
|
||||
namespace {
|
||||
|
||||
void TestAutofillInWindow(content::WebContents* active_contents,
|
||||
const GURL& fake_url,
|
||||
bool enabled) {
|
||||
// Logins.
|
||||
autofill::ChromeAutofillClient* autofill_client =
|
||||
autofill::ChromeAutofillClient::FromWebContentsForTesting(
|
||||
active_contents);
|
||||
EXPECT_EQ(autofill_client->IsAutocompleteEnabled(), enabled);
|
||||
// Passwords.
|
||||
ChromePasswordManagerClient* client =
|
||||
ChromePasswordManagerClient::FromWebContents(active_contents);
|
||||
EXPECT_EQ(client->IsFillingEnabled(fake_url), enabled);
|
||||
// Other info.
|
||||
autofill::ContentAutofillDriver* cross_driver =
|
||||
autofill::ContentAutofillDriverFactory::FromWebContents(active_contents)
|
||||
->DriverForFrame(active_contents->GetPrimaryMainFrame());
|
||||
ASSERT_TRUE(cross_driver);
|
||||
EXPECT_EQ(static_cast<autofill::BrowserAutofillManager*>(
|
||||
cross_driver->autofill_manager())
|
||||
->IsAutofillEnabled(),
|
||||
enabled);
|
||||
}
|
||||
|
||||
struct MockTorLauncherObserver : public TorLauncherObserver {
|
||||
public:
|
||||
MOCK_METHOD(void, OnTorLauncherCrashed, (), (override));
|
||||
@@ -246,7 +275,6 @@ class BraveTorTestWithCustomProfile : public BraveTorTest {
|
||||
private:
|
||||
void SetUpCommandLine(base::CommandLine* command_line) override {
|
||||
InProcessBrowserTest::SetUpCommandLine(command_line);
|
||||
|
||||
if (GetTestPreCount() > 0) {
|
||||
base::ScopedAllowBlockingForTesting allow_blocking;
|
||||
|
||||
@@ -394,6 +422,27 @@ IN_PROC_BROWSER_TEST_F(BraveTorTestWithCustomProfile, Incognito) {
|
||||
EXPECT_TRUE(is_element_enabled("torSnowflake"));
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(BraveTorTestWithCustomProfile, Autofill) {
|
||||
GURL fake_url("http://brave.com/");
|
||||
// Disable autofill in private windows.
|
||||
browser()->profile()->GetPrefs()->SetBoolean(kBraveAutofillPrivateWindows,
|
||||
false);
|
||||
auto* tor_profile = OpenTorWindow();
|
||||
EXPECT_NE(nullptr, tor_profile);
|
||||
EXPECT_TRUE(tor_profile->IsTor());
|
||||
Browser* tor_browser = chrome::FindBrowserWithProfile(tor_profile);
|
||||
content::WebContents* web_contents =
|
||||
tor_browser->tab_strip_model()->GetActiveWebContents();
|
||||
TestAutofillInWindow(web_contents, fake_url, false);
|
||||
|
||||
// Enable autofill in private windows.
|
||||
browser()->profile()->GetPrefs()->SetBoolean(kBraveAutofillPrivateWindows,
|
||||
true);
|
||||
web_contents->GetController().Reload(content::ReloadType::NORMAL, true);
|
||||
EXPECT_TRUE(content::WaitForLoadStop(web_contents));
|
||||
TestAutofillInWindow(web_contents, fake_url, true);
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(BraveTorTest, PRE_ResetBridges) {
|
||||
EXPECT_FALSE(TorProfileServiceFactory::IsTorDisabled(browser()->profile()));
|
||||
DownloadTorClient();
|
||||
|
||||
@@ -193,6 +193,10 @@ void BraveAddCommonStrings(content::WebUIDataSource* html_source,
|
||||
{"braveWebDiscoveryLabel", IDS_SETTINGS_WEB_DISCOVERY_LABEL},
|
||||
{"braveWebDiscoverySubLabel", IDS_SETTINGS_WEB_DISCOVERY_SUBLABEL},
|
||||
#endif
|
||||
{"autofillInPrivateSettingLabel",
|
||||
IDS_SETTINGS_BRAVE_AUTOFILL_PRIVATE_WINDOWS_LABEL},
|
||||
{"autofillInPrivateSettingDesc",
|
||||
IDS_SETTINGS_BRAVE_AUTOFILL_PRIVATE_WINDOWS_DESC},
|
||||
{"mruCyclingSettingLabel", IDS_SETTINGS_BRAVE_MRU_CYCLING_LABEL},
|
||||
{"speedreaderSettingLabel", IDS_SETTINGS_SPEEDREADER_LABEL},
|
||||
{"speedreaderSettingSubLabel", IDS_SETTINGS_SPEEDREADER_SUB_LABEL},
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 2023 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 "brave/components/constants/pref_names.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
|
||||
#define IsGuestSession \
|
||||
IsGuestSession() || \
|
||||
(!profile->GetPrefs()->GetBoolean(kBraveAutofillPrivateWindows) && \
|
||||
(IsOffTheRecord() || profile->IsTor())) || \
|
||||
profile->IsGuestSession
|
||||
#include "src/chrome/browser/password_manager/chrome_password_manager_client.cc"
|
||||
#undef IsGuestSession
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2023 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 "chrome/browser/ui/autofill/chrome_autofill_client.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "brave/components/constants/pref_names.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/ui/autofill/payments/webauthn_dialog_controller_impl.h"
|
||||
#include "chrome/browser/ui/page_info/page_info_dialog.h"
|
||||
|
||||
namespace autofill {
|
||||
|
||||
namespace {
|
||||
bool IsPrivateProfile(content::WebContents* web_contents) {
|
||||
if (!web_contents) {
|
||||
return false;
|
||||
}
|
||||
auto* profile =
|
||||
Profile::FromBrowserContext(web_contents->GetBrowserContext());
|
||||
if (!profile) {
|
||||
return false;
|
||||
}
|
||||
return (profile_metrics::GetBrowserProfileType(profile) ==
|
||||
profile_metrics::BrowserProfileType::kIncognito) ||
|
||||
profile->IsTor();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class BraveChromeAutofillClient : public ChromeAutofillClient {
|
||||
public:
|
||||
using ChromeAutofillClient::ChromeAutofillClient;
|
||||
|
||||
bool IsAutocompleteEnabled() const override {
|
||||
auto enabled = ChromeAutofillClient::IsAutocompleteEnabled();
|
||||
if (!IsPrivateProfile(web_contents())) {
|
||||
return enabled;
|
||||
}
|
||||
enabled = enabled && GetPrefs()->GetBoolean(kBraveAutofillPrivateWindows);
|
||||
return enabled;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace autofill
|
||||
|
||||
#define WrapUnique WrapUnique(new autofill::BraveChromeAutofillClient(web_contents))); \
|
||||
if (0) std::unique_ptr<autofill::ChromeAutofillClient> dummy(
|
||||
#include "src/chrome/browser/ui/autofill/chrome_autofill_client.cc"
|
||||
#undef WrapUnique
|
||||
@@ -0,0 +1,3 @@
|
||||
include_rules = [
|
||||
"+brave/components/constants",
|
||||
]
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2023 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 "components/autofill/content/browser/content_autofill_driver_factory.h"
|
||||
|
||||
#include "brave/components/constants/pref_names.h"
|
||||
#include "components/autofill/core/browser/browser_autofill_manager.h"
|
||||
|
||||
namespace autofill {
|
||||
|
||||
class BraveBrowserAutofillManager : public BrowserAutofillManager {
|
||||
public:
|
||||
using BrowserAutofillManager::BrowserAutofillManager;
|
||||
|
||||
bool IsAutofillEnabled() const override {
|
||||
auto enabled = BrowserAutofillManager::IsAutofillEnabled();
|
||||
if (client()->GetProfileType() !=
|
||||
profile_metrics::BrowserProfileType::kIncognito &&
|
||||
client()->GetProfileType() !=
|
||||
profile_metrics::BrowserProfileType::kOtherOffTheRecordProfile) {
|
||||
return enabled;
|
||||
}
|
||||
enabled = enabled &&
|
||||
client()->GetPrefs()->GetBoolean(kBraveAutofillPrivateWindows);
|
||||
return enabled;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace autofill
|
||||
|
||||
#define BrowserAutofillManager BraveBrowserAutofillManager
|
||||
#include "src/components/autofill/content/browser/content_autofill_driver_factory.cc"
|
||||
#undef BrowserAutofillManager
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "brave/components/constants/pref_names.h"
|
||||
|
||||
const char kBraveAutofillPrivateWindows[] = "brave.autofill_private_windows";
|
||||
const char kManagedBraveShieldsDisabledForUrls[] =
|
||||
"brave.managed_shields_disabled";
|
||||
const char kManagedBraveShieldsEnabledForUrls[] =
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
extern const char kBraveAutofillPrivateWindows[];
|
||||
extern const char kManagedBraveShieldsEnabledForUrls[];
|
||||
extern const char kManagedBraveShieldsDisabledForUrls[];
|
||||
extern const char kAdsBlocked[];
|
||||
|
||||
@@ -1107,6 +1107,7 @@ test("brave_browser_tests") {
|
||||
|
||||
if (!is_android) {
|
||||
sources += [
|
||||
"//brave/browser/brave_autofill_browsertest.cc",
|
||||
"//brave/browser/brave_resources_browsertest.cc",
|
||||
"//brave/browser/misc_metrics/vertical_tab_metrics_browsertest.cc",
|
||||
"//brave/browser/ssl/certificate_transparency_browsertest.cc",
|
||||
@@ -1119,6 +1120,8 @@ test("brave_browser_tests") {
|
||||
"//brave/browser/ui/whats_new:browser_test",
|
||||
"//chrome/browser/apps/app_service:app_service",
|
||||
"//chrome/browser/apps/app_service:constants",
|
||||
"//components/autofill/content/browser",
|
||||
"//components/autofill/core/browser",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user