diff --git a/gnome-shell/firewall@subgraph.com/dialog.js b/gnome-shell/firewall@subgraph.com/dialog.js index 8a6f84c..0c35343 100644 --- a/gnome-shell/firewall@subgraph.com/dialog.js +++ b/gnome-shell/firewall@subgraph.com/dialog.js @@ -164,14 +164,14 @@ const OptionList = new Lang.Class({ }, addTLSOption: function(tlsGuardEnabled) { - let tlsg = new OptionListItem("Drop connection if not TLS with valid certificate",0); - tlsg.setSelected(tlsGuardEnabled); - tlsg.connect('selected', Lang.bind(this, function() { - this._toggleTLSGuard(tlsg); + this._tlsg = new OptionListItem("Drop connection if not TLS with valid certificate",0); + this._tlsg.setSelected(tlsGuardEnabled); + this._tlsg.connect('selected', Lang.bind(this, function() { + this._toggleTLSGuard(this._tlsg); })); - let emptyRow = new OptionListItem("",0); + let emptyRow = new OptionListItem("-------------------------------------------------", 0); this.actor.add_child(emptyRow.actor); - this.actor.add_child(tlsg.actor); + this.actor.add_child(this._tlsg.actor); }, _toggleTLSGuard: function(item) { @@ -251,6 +251,44 @@ const OptionList = new Lang.Class({ log("SGFW: unexpected scope value "+ scope); return 1; } + }, + + scopeNext: function() { + this.buttonGroup.next(); + }, + + scopePrevious: function() { + this.buttonGroup.previous(); + }, + + ruleNext: function() { + let idx = this.selectedIdx() + , l = this.items.length; + idx++; + if (l == 0) { + return; + } + if (idx >= l) { + idx = 0; + } + this._optionSelected(this.items[idx]); + }, + + rulePrevious: function() { + let idx = this.selectedIdx() + , l = this.items.length; + idx--; + if (l == 0) { + return; + } + if (idx < 0) { + idx = (l - 1); + } + this._optionSelected(this.items[idx]); + }, + + ruleToggleTLSGuard: function() { + this._toggleTLSGuard(this._tlsg); } }); @@ -261,7 +299,7 @@ const ButtonGroup = new Lang.Class({ _init: function() { this.actor = new St.BoxLayout({ style_class: 'fw-button-group'}); this._checked = -1; - this._buttons= []; + this._buttons = []; for(let i = 0; i < arguments.length; i++) { let idx = i; this._buttons[i] = new St.Button({ style_class: 'fw-group-button button', @@ -277,7 +315,6 @@ const ButtonGroup = new Lang.Class({ }, _setChecked: function(idx) { - if (idx == this._checked) { return; } @@ -288,6 +325,32 @@ const ButtonGroup = new Lang.Class({ this._checked = idx; }, + next: function() { + let idx = this._checked + , l = this._buttons.length; + idx++; + if (l == 0) { + return + } + if (idx >= l) { + idx = 0; + } + this._setChecked(idx); + }, + + previous: function() { + let idx = this._checked + , l = this._buttons.length; + idx--; + if (l == 0) { + return + } + if (idx < 0) { + idx = (l - 1); + } + this._setChecked(idx); + } + }); const ExpandingSection = new Lang.Class({ @@ -497,6 +560,48 @@ const PromptDialog = new Lang.Class({ ]); }, + _onPromptScopeNext: function() { + if (this.details.isOpen) { + this.optionList.scopeNext(); + } + }, + + _onPromptScopePrevious: function() { + if (this.details.isOpen) { + this.optionList.scopePrevious(); + } + }, + + _onPromptRuleAllow: function() { + this.onAllow(); + }, + + _onPromptRuleDeny: function() { + this.onDeny(); + }, + + _onPromptRuleNext: function() { + if (this.details.isOpen) { + this.optionList.ruleNext(); + } + }, + + _onPromptRulePrevious: function() { + if (this.details.isOpen) { + this.optionList.rulePrevious(); + } + }, + + _onPromptToggleDetails: function() { + this.details.activate(); + }, + + _onPromptToggleTlsguard: function() { + if (this.details.isOpen) { + this.optionList.ruleToggleTLSGuard(); + } + }, + onAllow: function() { if (this.cbClose !== undefined && this.cbClose !== null) { this.cbClose(); diff --git a/gnome-shell/firewall@subgraph.com/extension.js b/gnome-shell/firewall@subgraph.com/extension.js index 9fa65ca..a9c74a7 100644 --- a/gnome-shell/firewall@subgraph.com/extension.js +++ b/gnome-shell/firewall@subgraph.com/extension.js @@ -1,12 +1,17 @@ const Lang = imports.lang; +const Main = imports.ui.main; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; + const Gio = imports.gi.Gio; const Extension = imports.misc.extensionUtils.getCurrentExtension(); +const Convenience = Extension.imports.convenience; + const Dialog = Extension.imports.dialog; const Menu = Extension.imports.menu; //const ConnectionMonitor = Extension.imports.cmonitor; - function init() { return new FirewallSupport(); } @@ -75,18 +80,70 @@ const FirewallPromptHandler = new Lang.Class({ Name: 'FirewallPromptHandler', _init: function() { + this._settings = Convenience.getSettings(); this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(FirewallPromptInterface, this); this._dbusImpl.export(Gio.DBus.system, '/com/subgraph/FirewallPrompt'); Gio.bus_own_name_on_connection(Gio.DBus.system, 'com.subgraph.FirewallPrompt', Gio.BusNameOwnerFlags.REPLACE, null, null); this._dialogs = new Array(); + this._initKeybindings(); }, destroy: function() { + log("SGFW: Exited"); this._closeDialogs(); this._dbusImpl.unexport(); + this._destroyKeybindings(); + }, + + _initKeybindings: function() { + this._keyBindings = new Array( + "prompt-scope-previous" + , "prompt-scope-next" + , "prompt-rule-next" + , "prompt-rule-previous" + , "prompt-rule-allow" + , "prompt-rule-deny" + , "prompt-toggle-details" + , "prompt-toggle-tlsguard" + ); + for (var i = 0 , ii = this._keyBindings.length; i < ii; i++) { + Main.wm.addKeybinding(this._keyBindings[i], + this._settings, + Meta.KeyBindingFlags.NONE, + Shell.ActionMode.ALL, + Lang.bind(this, this._handleKeybinding, this._keyBindings[i])); + } + }, + + _handleKeybinding: function(a, b, c, d, binding) { + if (this._dialogs.length <= 0) { + return false; + } + + let fname = binding.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); }); + let fname = "_on"+ fname[0].toUpperCase() + fname.substr(1); + if (!( fname in this._dialogs[0] )) { + log("SGFW: Invalid key binding (1)... " + fname); + return true; + } + let fn = this._dialogs[0][fname]; + if (typeof fn !== "function") { + log("SGFW: Invalid key binding (2)... " + fname + " " + (typeof fn)); + return true; + } + + Lang.bind(this._dialogs[0], fn)(); + return true; + }, + + _destroyKeybindings: function() { + for (var i = 0 , ii = keyBindings.length; i < ii; i++) { + Main.wm.removeKeybinding(this._keyBindings[i]); + } }, _closeDialogs: function() { + log("SGFW: Closing all dialogs"); if (this._dialogs.length > 0) { dialog = this._dialogs.shift(); dialog.close(); @@ -108,17 +165,21 @@ const FirewallPromptHandler = new Lang.Class({ }, onCloseDialog: function() { + log("SGFW: Closed dialog"); this._dialogs.shift(); if (this._dialogs.length > 0) { + log("SGFW: Opening next dialogs (remaining: " + this._dialogs.length + ")"); this._dialogs[0].open(); } }, CloseAsync: function(params, invocation) { + log("SGFW: Close Async Requested"); this._closeDialogs(); }, TestPrompt: function(params, invocation) { + log("SGFW: Test Prompt Requested"); this.RequestPromptAsync(["Firefox", "firefox", "/usr/bin/firefox-esr", "242.12.111.18", "443", "linux", "2342", "TCP", true, true], nil); } }); diff --git a/gnome-shell/firewall@subgraph.com/schemas/com.subgraph.firewall.gschema.xml b/gnome-shell/firewall@subgraph.com/schemas/com.subgraph.firewall.gschema.xml index 559b079..2efc43f 100644 --- a/gnome-shell/firewall@subgraph.com/schemas/com.subgraph.firewall.gschema.xml +++ b/gnome-shell/firewall@subgraph.com/schemas/com.subgraph.firewall.gschema.xml @@ -1,9 +1,55 @@ - + + + ']]]> + Show prompt dialog shortcuts + + + + left']]]> + Select previous scope + + + + right']]]> + Select next scope + + + + up']]]> + Select previous rule + + + + down']]]> + Select next rule + + + + a']]]> + Accept rule + + + + d']]]> + Deny rule + + + + space']]]> + Toggle details view + + + + s']]]> + Toggle TLS Guard mode + - \ No newline at end of file + diff --git a/gnome-shell/firewall@subgraph.com/schemas/gschemas.compiled b/gnome-shell/firewall@subgraph.com/schemas/gschemas.compiled index 5a7e9d7..238e1ad 100644 Binary files a/gnome-shell/firewall@subgraph.com/schemas/gschemas.compiled and b/gnome-shell/firewall@subgraph.com/schemas/gschemas.compiled differ