Add new disable reason BLOCKED_MATURE for mature extensions
Child users should not be able to install extensions and themes with
mature content from Chrome Web Store (CWS). Add a new disable reason
BLOCKED_MATURE to block any extensions or themes marked mature in
CWS for child users.
Bug: 1037965,1040614
Change-Id: I37cec6efb51e0e88c1714e57be0ef279b1b32ed9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2017646
Commit-Queue: Toby Huang <[email protected]>
Reviewed-by: Aga Wronska <[email protected]>
Reviewed-by: Devlin <[email protected]>
Reviewed-by: Brian White <[email protected]>
Cr-Commit-Position: refs/heads/master@{#738456}
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
index ae5cfba..11988e0 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
@@ -560,6 +560,8 @@
info->disable_reasons.custodian_approval_required =
(disable_reasons & disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED) !=
0;
+ info->disable_reasons.blocked_mature =
+ (disable_reasons & disable_reason::DISABLE_BLOCKED_MATURE) != 0;
// Error collection.
bool error_console_enabled =
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 9131c06..e99ce68 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -780,6 +780,8 @@
void ExtensionService::DisableExtension(const std::string& extension_id,
int disable_reasons) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(disable_reasons != disable_reason::DISABLE_BLOCKED_MATURE ||
+ profile()->IsChild());
extension_registrar_.DisableExtension(extension_id, disable_reasons);
}
@@ -1026,6 +1028,7 @@
// related disable reasons.
if (!profile()->IsChild()) {
disable_reasons &= (~disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED);
+ disable_reasons &= (~disable_reason::DISABLE_BLOCKED_MATURE);
}
extension_prefs_->ReplaceDisableReasons(extension->id(), disable_reasons);
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc
index 60151f0e..11000520 100644
--- a/chrome/browser/extensions/extension_sync_service.cc
+++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -77,7 +77,7 @@
return result;
}
-static_assert(extensions::disable_reason::DISABLE_REASON_LAST == (1LL << 17),
+static_assert(extensions::disable_reason::DISABLE_REASON_LAST == (1LL << 18),
"Please consider whether your new disable reason should be"
" syncable, and if so update this bitmask accordingly!");
const int kKnownSyncableDisableReasons =
diff --git a/chrome/browser/metrics/extensions_metrics_provider.cc b/chrome/browser/metrics/extensions_metrics_provider.cc
index 360ad26..201d7cd0 100644
--- a/chrome/browser/metrics/extensions_metrics_provider.cc
+++ b/chrome/browser/metrics/extensions_metrics_provider.cc
@@ -211,7 +211,7 @@
return ExtensionInstallProto::NO_BACKGROUND_SCRIPT;
}
-static_assert(extensions::disable_reason::DISABLE_REASON_LAST == (1LL << 17),
+static_assert(extensions::disable_reason::DISABLE_REASON_LAST == (1LL << 18),
"Adding a new disable reason? Be sure to include the new reason "
"below, update the test to exercise it, and then adjust this "
"value for DISABLE_REASON_LAST");
@@ -250,6 +250,8 @@
ExtensionInstallProto::CUSTODIAN_APPROVAL_REQUIRED},
{extensions::disable_reason::DISABLE_BLOCKED_BY_POLICY,
ExtensionInstallProto::BLOCKED_BY_POLICY},
+ {extensions::disable_reason::DISABLE_BLOCKED_MATURE,
+ ExtensionInstallProto::BLOCKED_MATURE},
};
int disable_reasons = prefs->GetDisableReasons(id);
diff --git a/chrome/browser/resources/extensions/detail_view.js b/chrome/browser/resources/extensions/detail_view.js
index f2658559..155381f 100644
--- a/chrome/browser/resources/extensions/detail_view.js
+++ b/chrome/browser/resources/extensions/detail_view.js
@@ -167,10 +167,8 @@
hasWarnings_() {
return this.data.disableReasons.corruptInstall ||
this.data.disableReasons.suspiciousInstall ||
- this.data.disableReasons.updateRequired ||
- this.data.disableReasons.blockedByPolicy ||
- this.data.disableReasons.custodianApprovalRequired ||
- !!this.data.blacklistText || this.data.runtimeWarnings.length > 0;
+ this.data.disableReasons.updateRequired || !!this.data.blacklistText ||
+ this.data.runtimeWarnings.length > 0;
},
/**
diff --git a/chrome/browser/resources/extensions/item_util.js b/chrome/browser/resources/extensions/item_util.js
index d587ec0e..029ca120 100644
--- a/chrome/browser/resources/extensions/item_util.js
+++ b/chrome/browser/resources/extensions/item_util.js
@@ -68,7 +68,8 @@
item.disableReasons.suspiciousInstall ||
item.disableReasons.updateRequired ||
item.disableReasons.blockedByPolicy ||
- item.disableReasons.custodianApprovalRequired) {
+ item.disableReasons.custodianApprovalRequired ||
+ item.disableReasons.blockedMature) {
return false;
}
// An item with dependent extensions can't be disabled (it would bork the
diff --git a/chrome/browser/supervised_user/supervised_user_extension_browsertest.cc b/chrome/browser/supervised_user/supervised_user_extension_browsertest.cc
index 262c29f..c793353 100644
--- a/chrome/browser/supervised_user/supervised_user_extension_browsertest.cc
+++ b/chrome/browser/supervised_user/supervised_user_extension_browsertest.cc
@@ -5,6 +5,7 @@
#include "base/files/file_path.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/supervised_user/logged_in_user_mixin.h"
#include "chrome/browser/supervised_user/supervised_user_features.h"
@@ -107,6 +108,12 @@
extensions::disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED);
}
+ bool IsDisabledForBlockedMature(const std::string& extension_id) {
+ ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile());
+ return extension_prefs->HasDisableReason(
+ extension_id, extensions::disable_reason::DISABLE_BLOCKED_MATURE);
+ }
+
private:
InProcessBrowserTestMixinHost mixin_host_;
@@ -140,6 +147,7 @@
// disabled.
EXPECT_TRUE(extension_registry()->disabled_extensions().Contains(kGoodCrxId));
EXPECT_TRUE(IsDisabledForCustodianApproval(kGoodCrxId));
+ EXPECT_FALSE(IsDisabledForBlockedMature(kGoodCrxId));
}
IN_PROC_BROWSER_TEST_F(SupervisedUserExtensionTest,
@@ -153,6 +161,47 @@
// The extension should be enabled now after removing supervision.
EXPECT_TRUE(extension_registry()->enabled_extensions().Contains(kGoodCrxId));
EXPECT_FALSE(IsDisabledForCustodianApproval(kGoodCrxId));
+ EXPECT_FALSE(IsDisabledForBlockedMature(kGoodCrxId));
+}
+
+// Removing supervision should also remove associated disable reasons, such as
+// DISABLE_BLOCKED_MATURE. Extensions should become enabled again after removing
+// supervision. Prevents a regression to crbug/1045625.
+IN_PROC_BROWSER_TEST_F(SupervisedUserExtensionTest,
+ PRE_RemovingSupervisionBlockedMature) {
+ SetSupervisedUserExtensionsMayRequestPermissionsPref(true);
+
+ EXPECT_TRUE(profile()->IsChild());
+
+ base::FilePath path = test_data_dir_.AppendASCII("good.crx");
+ EXPECT_FALSE(LoadExtensionWithFlags(path, kFlagNone));
+ const Extension* extension =
+ extension_registry()->GetInstalledExtension(kGoodCrxId);
+ EXPECT_TRUE(extension);
+
+ // Let's pretend this extension is mature.
+ extension_service()->DisableExtension(kGoodCrxId,
+ disable_reason::DISABLE_BLOCKED_MATURE);
+
+ // This extension is a supervised user initiated install and should remain
+ // disabled.
+ EXPECT_TRUE(extension_registry()->disabled_extensions().Contains(kGoodCrxId));
+ EXPECT_TRUE(IsDisabledForCustodianApproval(kGoodCrxId));
+ EXPECT_TRUE(IsDisabledForBlockedMature(kGoodCrxId));
+}
+
+IN_PROC_BROWSER_TEST_F(SupervisedUserExtensionTest,
+ RemovingSupervisionBlockedMature) {
+ EXPECT_FALSE(profile()->IsChild());
+ // The extension should still be installed since we are sharing the same data
+ // directory as the PRE test.
+ const Extension* extension =
+ extension_registry()->GetInstalledExtension(kGoodCrxId);
+ EXPECT_TRUE(extension);
+ // The extension should be enabled now after removing supervision.
+ EXPECT_TRUE(extension_registry()->enabled_extensions().Contains(kGoodCrxId));
+ EXPECT_FALSE(IsDisabledForCustodianApproval(kGoodCrxId));
+ EXPECT_FALSE(IsDisabledForBlockedMature(kGoodCrxId));
}
} // namespace extensions
diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl
index f49c474..dcdb611 100644
--- a/chrome/common/extensions/api/developer_private.idl
+++ b/chrome/common/extensions/api/developer_private.idl
@@ -138,6 +138,7 @@
boolean updateRequired;
boolean blockedByPolicy;
boolean custodianApprovalRequired;
+ boolean blockedMature;
};
dictionary OptionsPage {
diff --git a/chrome/test/data/extensions/api_test/developer/generated_output/behllobkkfkfnphdnhnkndlbkcpglgmj.json b/chrome/test/data/extensions/api_test/developer/generated_output/behllobkkfkfnphdnhnkndlbkcpglgmj.json
index de0f3f99..b15256a 100644
--- a/chrome/test/data/extensions/api_test/developer/generated_output/behllobkkfkfnphdnhnkndlbkcpglgmj.json
+++ b/chrome/test/data/extensions/api_test/developer/generated_output/behllobkkfkfnphdnhnkndlbkcpglgmj.json
@@ -3,6 +3,7 @@
"description": "The first extension that I made.",
"disableReasons": {
"blockedByPolicy": false,
+ "blockedMature": false,
"corruptInstall": false,
"custodianApprovalRequired": false,
"suspiciousInstall": false,
diff --git a/chrome/test/data/extensions/api_test/developer/generated_output/bjafgdebaacbbbecmhlhpofkepfkgcpa.json b/chrome/test/data/extensions/api_test/developer/generated_output/bjafgdebaacbbbecmhlhpofkepfkgcpa.json
index 72544aa..0dc7d98 100644
--- a/chrome/test/data/extensions/api_test/developer/generated_output/bjafgdebaacbbbecmhlhpofkepfkgcpa.json
+++ b/chrome/test/data/extensions/api_test/developer/generated_output/bjafgdebaacbbbecmhlhpofkepfkgcpa.json
@@ -3,6 +3,7 @@
"description": "",
"disableReasons": {
"blockedByPolicy": false,
+ "blockedMature": false,
"corruptInstall": false,
"custodianApprovalRequired": false,
"suspiciousInstall": false,
diff --git a/chrome/test/data/extensions/api_test/developer/generated_output/hpiknbiabeeppbpihjehijgoemciehgk.json b/chrome/test/data/extensions/api_test/developer/generated_output/hpiknbiabeeppbpihjehijgoemciehgk.json
index 560fc5b..d599b716 100644
--- a/chrome/test/data/extensions/api_test/developer/generated_output/hpiknbiabeeppbpihjehijgoemciehgk.json
+++ b/chrome/test/data/extensions/api_test/developer/generated_output/hpiknbiabeeppbpihjehijgoemciehgk.json
@@ -3,6 +3,7 @@
"description": "",
"disableReasons": {
"blockedByPolicy": false,
+ "blockedMature": false,
"corruptInstall": false,
"custodianApprovalRequired": false,
"suspiciousInstall": false,
diff --git a/chrome/test/data/webui/extensions/detail_view_test.js b/chrome/test/data/webui/extensions/detail_view_test.js
index 6eb2c310..ca2d374 100644
--- a/chrome/test/data/webui/extensions/detail_view_test.js
+++ b/chrome/test/data/webui/extensions/detail_view_test.js
@@ -184,6 +184,13 @@
item.set('data.disableReasons.blockedByPolicy', false);
flush();
+ item.set('data.disableReasons.blockedMature', true);
+ flush();
+ expectTrue(testIsVisible('#enableToggle'));
+ expectTrue(item.$$('#enableToggle').disabled);
+ item.set('data.disableReasons.blockedMature', false);
+ flush();
+
item.set('data.disableReasons.custodianApprovalRequired', true);
flush();
expectFalse(testIsVisible('#enableToggle'));
diff --git a/chrome/test/data/webui/extensions/item_test.js b/chrome/test/data/webui/extensions/item_test.js
index c1f2d0bd..0d1d3b0 100644
--- a/chrome/test/data/webui/extensions/item_test.js
+++ b/chrome/test/data/webui/extensions/item_test.js
@@ -355,6 +355,13 @@
item.set('data.disableReasons.blockedByPolicy', false);
flush();
+ item.set('data.disableReasons.blockedMature', true);
+ flush();
+ testVisible(item, '#enableToggle', true);
+ expectTrue(item.$['enableToggle'].disabled);
+ item.set('data.disableReasons.blockedMature', false);
+ flush();
+
item.set('data.disableReasons.custodianApprovalRequired', true);
flush();
testVisible(item, '#enableToggle', false);
diff --git a/chrome/test/data/webui/extensions/test_util.js b/chrome/test/data/webui/extensions/test_util.js
index 713ff49..055511f 100644
--- a/chrome/test/data/webui/extensions/test_util.js
+++ b/chrome/test/data/webui/extensions/test_util.js
@@ -181,6 +181,7 @@
updateRequired: false,
blockedByPolicy: false,
custodianApprovalRequired: false,
+ blockedMature: false,
},
homePage: {specified: false, url: ''},
iconUrl: 'chrome://extension-icon/' + id + '/24/0',