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. the “enabled-extension” setting.
</description> </description>
</key> </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"> <key name="disable-extension-version-validation" type="b">
<default>false</default> <default>false</default>
<summary>Disables the validation of extension version compatibility</summary> <summary>Disables the validation of extension version compatibility</summary>

View File

@ -40,6 +40,7 @@ export const ExtensionError = {
DOWNLOAD_FAILED: 1, DOWNLOAD_FAILED: 1,
EXTRACT_FAILED: 2, EXTRACT_FAILED: 2,
ENABLE_FAILED: 3, ENABLE_FAILED: 3,
NOT_ALLOWED: 4,
}; };
export const ExtensionErrors = export const ExtensionErrors =
registerErrorDomain('Extensions', ExtensionError); registerErrorDomain('Extensions', ExtensionError);

View File

@ -32,6 +32,13 @@ let _httpSession;
* @returns {void} * @returns {void}
*/ */
export async function installExtension(uuid, invocation) { 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 = { const params = {
uuid, uuid,
shell_version: Config.PACKAGE_VERSION, shell_version: Config.PACKAGE_VERSION,

View File

@ -86,8 +86,11 @@ export class ExtensionManager extends Signals.EventEmitter {
get updatesSupported() { get updatesSupported() {
const appSys = Shell.AppSystem.get_default(); const appSys = Shell.AppSystem.get_default();
return (appSys.lookup_app('org.gnome.Extensions.desktop') !== null) || const hasUpdatesApp =
(appSys.lookup_app('com.mattjakeman.ExtensionManager.desktop') !== null); 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) { lookup(uuid) {
@ -745,7 +748,8 @@ export class ExtensionManager extends Signals.EventEmitter {
let perUserDir = Gio.File.new_for_path(global.userdatadir); 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}) => { const extensionObjects = extensionFiles.map(({dir, info}) => {
let fileType = info.get_file_type(); let fileType = info.get_file_type();
if (fileType !== Gio.FileType.DIRECTORY) if (fileType !== Gio.FileType.DIRECTORY)