extensionSystem: Add an explicit approval dialog

Pop up a dialog when trying to install an extension so that users are aware
they are installing one. This is a security precaution in the case that an XSS
exploit has been found on the website, which could cause someone to inject a
<script> tag and silently install an extension.

https://bugzilla.gnome.org/show_bug.cgi?id=658612
This commit is contained in:
Jasper St. Pierre 2011-09-12 14:17:09 -04:00
parent fa593a3e15
commit 7db92ad5d9

View File

@ -3,6 +3,7 @@
const Lang = imports.lang; const Lang = imports.lang;
const Signals = imports.signals; const Signals = imports.signals;
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const St = imports.gi.St; const St = imports.gi.St;
@ -11,6 +12,7 @@ const Soup = imports.gi.Soup;
const Config = imports.misc.config; const Config = imports.misc.config;
const FileUtils = imports.misc.fileUtils; const FileUtils = imports.misc.fileUtils;
const ModalDialog = imports.ui.modalDialog;
const API_VERSION = 1; const API_VERSION = 1;
@ -110,24 +112,18 @@ function versionCheck(required, current) {
} }
function installExtensionFromUUID(uuid, version_tag) { function installExtensionFromUUID(uuid, version_tag) {
let meta = { uuid: uuid, let params = { uuid: uuid,
state: ExtensionState.DOWNLOADING, version_tag: version_tag,
error: '' };
extensionMeta[uuid] = meta;
_signals.emit('extension-state-changed', meta);
let params = { version_tag: version_tag,
shell_version: Config.PACKAGE_VERSION, shell_version: Config.PACKAGE_VERSION,
api_version: API_VERSION.toString() }; api_version: API_VERSION.toString() };
let url = REPOSITORY_URL_DOWNLOAD.format(uuid); let message = Soup.form_request_new_from_hash('GET', REPOSITORY_URL_INFO, params);
let message = Soup.form_request_new_from_hash('GET', url, params);
_httpSession.queue_message(message, _httpSession.queue_message(message,
function(session, message) { function(session, message) {
gotExtensionZipFile(session, message, uuid); let info = JSON.parse(message.response_body.data);
let dialog = new InstallExtensionDialog(uuid, version_tag, info.name);
dialog.open(global.get_current_time());
}); });
} }
@ -463,3 +459,73 @@ function loadExtensions() {
_loadExtensionsIn(dir, ExtensionType.SYSTEM); _loadExtensionsIn(dir, ExtensionType.SYSTEM);
} }
} }
function InstallExtensionDialog(uuid, version_tag, name) {
this._init(uuid, version_tag, name);
}
InstallExtensionDialog.prototype = {
__proto__: ModalDialog.ModalDialog.prototype,
_init: function(uuid, version_tag, name) {
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'extension-dialog' });
this._uuid = uuid;
this._version_tag = version_tag;
this._name = name;
this.setButtons([{ label: _("Cancel"),
action: Lang.bind(this, this._onCancelButtonPressed),
key: Clutter.Escape
},
{ label: _("Install"),
action: Lang.bind(this, this._onInstallButtonPressed)
}]);
let message = _("Download and install '%s' from extensions.gnome.org?").format(name);
this._descriptionLabel = new St.Label({ text: message });
this.contentLayout.add(this._descriptionLabel,
{ y_fill: true,
y_align: St.Align.START });
},
_onCancelButtonPressed: function(button, event) {
this.close(global.get_current_time());
// Even though the extension is already "uninstalled", send through
// a state-changed signal for any users who want to know if the install
// went through correctly -- using proper async DBus would block more
// traditional clients like the plugin
let meta = { uuid: this._uuid,
state: ExtensionState.UNINSTALLED,
error: '' };
_signals.emit('extension-state-changed', meta);
},
_onInstallButtonPressed: function(button, event) {
let meta = { uuid: this._uuid,
state: ExtensionState.DOWNLOADING,
error: '' };
extensionMeta[this._uuid] = meta;
_signals.emit('extension-state-changed', meta);
let params = { version_tag: this._version_tag,
shell_version: Config.PACKAGE_VERSION,
api_version: API_VERSION.toString() };
let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid);
let message = Soup.form_request_new_from_hash('GET', url, params);
_httpSession.queue_message(message,
Lang.bind(this, function(session, message) {
gotExtensionZipFile(session, message, this._uuid);
}));
this.close(global.get_current_time());
}
};