diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
index f4fa86d01..4ddc6a119 100644
--- a/data/org.gnome.shell.gschema.xml.in
+++ b/data/org.gnome.shell.gschema.xml.in
@@ -40,6 +40,17 @@
the “enabled-extension” setting.
+
+ true
+ Allow extension installation
+
+ Allow users to install extensions in their home folder. If disabled,
+ the InstallRemoteExtension D-Bus method will fail, and extensions
+ are only loaded from system directories on startup.
+ It does not affect extensions that are already loaded, so a change
+ only takes full effect on the next login.
+
+
false
Disables the validation of extension version compatibility
diff --git a/js/misc/dbusErrors.js b/js/misc/dbusErrors.js
index 6f4f80b51..ec726e89c 100644
--- a/js/misc/dbusErrors.js
+++ b/js/misc/dbusErrors.js
@@ -40,6 +40,7 @@ export const ExtensionError = {
DOWNLOAD_FAILED: 1,
EXTRACT_FAILED: 2,
ENABLE_FAILED: 3,
+ NOT_ALLOWED: 4,
};
export const ExtensionErrors =
registerErrorDomain('Extensions', ExtensionError);
diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js
index 6486bbcad..33f168ce6 100644
--- a/js/ui/extensionDownloader.js
+++ b/js/ui/extensionDownloader.js
@@ -32,6 +32,13 @@ let _httpSession;
* @returns {void}
*/
export async function installExtension(uuid, invocation) {
+ if (!global.settings.get_boolean('allow-extension-installation')) {
+ invocation.return_error_literal(
+ ExtensionErrors, ExtensionError.NOT_ALLOWED,
+ 'Extension installation is not allowed');
+ return;
+ }
+
const params = {
uuid,
shell_version: Config.PACKAGE_VERSION,
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index 07be8066c..76ae58ff4 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -86,8 +86,11 @@ export class ExtensionManager extends Signals.EventEmitter {
get updatesSupported() {
const appSys = Shell.AppSystem.get_default();
- return (appSys.lookup_app('org.gnome.Extensions.desktop') !== null) ||
- (appSys.lookup_app('com.mattjakeman.ExtensionManager.desktop') !== null);
+ const hasUpdatesApp =
+ appSys.lookup_app('org.gnome.Extensions.desktop') !== null ||
+ appSys.lookup_app('com.mattjakeman.ExtensionManager.desktop') !== null;
+ const allowed = global.settings.get_boolean('allow-extension-installation');
+ return allowed && hasUpdatesApp;
}
lookup(uuid) {
@@ -745,7 +748,8 @@ export class ExtensionManager extends Signals.EventEmitter {
let perUserDir = Gio.File.new_for_path(global.userdatadir);
- const extensionFiles = [...FileUtils.collectFromDatadirs('extensions', true)];
+ const includeUserDir = global.settings.get_boolean('allow-extension-installation');
+ const extensionFiles = [...FileUtils.collectFromDatadirs('extensions', includeUserDir)];
const extensionObjects = extensionFiles.map(({dir, info}) => {
let fileType = info.get_file_type();
if (fileType !== Gio.FileType.DIRECTORY)