extensionSystem: Support locking down extension installation

Currently extensions can only be locked down completely by
restricting the `enabled-extensions` key via dconf.

This is too restrictive for environments that want to allow users
to customize their system with extensions, while still limiting
the set of possible extensions.

To fill that gap, add a new `allow-extension-installation` setting,
which restricts extensions to system extensions when disabled.

As the setting is mainly intended for locking down by system
administrators, there is no attempt to load/unload extensions
on settings changes.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3180>
This commit is contained in:
Florian Müllner 2024-02-10 00:58:27 +01:00 committed by Marge Bot
parent 8f2ab674fc
commit c170d6c956
4 changed files with 26 additions and 3 deletions

View File

@ -40,6 +40,17 @@
the “enabled-extension” setting.
</description>
</key>
<key name="allow-extension-installation" type="b">
<default>true</default>
<summary>Allow extension installation</summary>
<description>
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.
</description>
</key>
<key name="disable-extension-version-validation" type="b">
<default>false</default>
<summary>Disables the validation of extension version compatibility</summary>

View File

@ -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);

View File

@ -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,

View File

@ -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)