From 533cc0f30091619700d6268573003fca9ab90db4 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 22 Apr 2010 15:54:28 +0200 Subject: [PATCH] Add exit node configuration dialog --- Makefile.am | 3 + src/exit-node-dialog.vala | 152 +++++++++++++++++++++++++++++++++++++++ src/status-area-applet-tor.vala | 54 +++++++++++++- 3 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 src/exit-node-dialog.vala diff --git a/Makefile.am b/Makefile.am index 2a86f5d..8e2d3da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,12 +24,14 @@ icon18_DATA = \ status_area_applet_tor_la_SOURCES = \ src/status-area-applet-tor.c \ src/bridge-dialog.c \ + src/exit-node-dialog.c \ src/torcontrol.c \ src/torcontrol-socket.c status_area_applet_tor_la_VALASOURCES = \ src/status-area-applet-tor.vala \ src/bridge-dialog.vala \ + src/exit-node-dialog.vala \ src/torcontrol.vala src/status-area-applet-tor.c: ${status_area_applet_tor_la_VALASOURCES} @@ -48,4 +50,5 @@ ACLOCAL_AMFLAGS = -Im4 CLEANFILES = \ src/status-area-applet-tor.c \ src/bridge-dialog.c \ + src/exit-node-dialog.c \ src/torcontrol.c diff --git a/src/exit-node-dialog.vala b/src/exit-node-dialog.vala new file mode 100644 index 0000000..033e94d --- /dev/null +++ b/src/exit-node-dialog.vala @@ -0,0 +1,152 @@ +class ExitNodeDialog : Gtk.Dialog { + private const string GCONF_DIR_TOR = "/apps/maemo/tor"; + private const string GCONF_KEY_EXITNODES = GCONF_DIR_TOR + "/exit_nodes"; + + GConf.Client gconf; + Gtk.ListStore list_store; + + /** + * Show the exit node configuration dialog + */ + private const int RESPONSE_NEW = 1; + public ExitNodeDialog (TorControl.Connection? tor_control = null) { + var content = (Gtk.VBox) get_content_area (); + content.set_size_request (-1, 5*70); + + set_title (_("Exit nodes")); + + gconf = GConf.Client.get_default (); + var exit_nodes = new SList (); + try { + exit_nodes = gconf.get_list (GCONF_KEY_EXITNODES, GConf.ValueType.STRING); + } catch (Error e) { + Hildon.Banner.show_information (this, null, "Error loading exit nodes: %s".printf (e.message)); + } + + list_store = new Gtk.ListStore (1, typeof (string)); + Gtk.TreeIter iter; + foreach (string exit_node in exit_nodes) { + list_store.append (out iter); + list_store.@set (iter, 0, exit_node); + } + + var pannable_area = new Hildon.PannableArea (); + var tree_view = new Gtk.TreeView.with_model (list_store); + var renderer = new Gtk.CellRendererText (); + var column = new Gtk.TreeViewColumn.with_attributes ("IP", renderer, "text", 0); + tree_view.append_column (column); + pannable_area.add (tree_view); + content.pack_start (pannable_area, true, true, 0); + + tree_view.row_activated.connect ((path, column) => { + exit_node_edit_dialog (list_store, path); + }); + + add_button (_("New"), RESPONSE_NEW); + response.connect ((response_id) => { + if (response_id == RESPONSE_NEW) { + exit_node_edit_dialog (list_store, null); + } + }); + + content.show_all (); + } + + /** + * Show the exit node edit dialog + */ + private const int RESPONSE_DELETE = 1; + private void exit_node_edit_dialog (Gtk.ListStore store, Gtk.TreePath? path) { + var dialog = new Gtk.Dialog (); + var content = (Gtk.VBox) dialog.get_content_area (); + + if (path == null) + dialog.set_title (_("New exit node")); + else + dialog.set_title (_("Edit exit node")); + + var size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL); + + var hbox = new Gtk.HBox (false, Hildon.MARGIN_DOUBLE); + var label = new Gtk.Label (_("Name")); + label.set_alignment (0, 0.5f); + size_group.add_widget (label); + hbox.pack_start (label, false, false, 0); + var name_entry = new Hildon.Entry (Hildon.SizeType.FINGER_HEIGHT); + hbox.pack_start (name_entry, true, true, 0); + content.pack_start (hbox, false, false, 0); + + var iter = Gtk.TreeIter (); + if (path != null && store.get_iter (out iter, path)) { + string tmp; + store.@get (iter, 0, out tmp); + name_entry.set_text (tmp); + + dialog.add_button (_("Delete"), RESPONSE_DELETE); + } + dialog.add_button (_("Save"), Gtk.ResponseType.OK); + dialog.response.connect ((response_id) => { + var exit_nodes = new SList (); + + if (response_id == RESPONSE_DELETE) { + if (path != null) { + Gtk.TreeIter iter2; + store.get_iter (out iter2, path); + store.remove (iter2); + string exit_node; + if (store.get_iter_first (out iter2)) do { + store.@get (iter2, 0, out exit_node); + exit_nodes.append (exit_node); + } while (store.iter_next (ref iter2)); + try { + gconf.set_list (GCONF_KEY_EXITNODES, + GConf.ValueType.STRING, + exit_nodes); + } catch (Error e) { + Hildon.Banner.show_information (dialog, null, + "Failed to save exit node list: %s".printf (e.message)); + } + } + dialog.destroy (); + } + if (response_id == Gtk.ResponseType.OK) { + Gtk.TreeIter iter2; + if (path == null) { + store.append (out iter2); + } else { + store.get_iter (out iter2, path); + } + store.@set (iter2, 0, name_entry.get_text ()); + try { + exit_nodes = gconf.get_list (GCONF_KEY_EXITNODES, + GConf.ValueType.STRING); + } catch (Error e) { + Hildon.Banner.show_information (null, null, + "Error loading exit nodes: %s".printf (e.message)); + } + if (path == null) { + exit_nodes.append (name_entry.get_text ()); + } else { + exit_nodes = null; + string exit_node; + if (store.get_iter_first (out iter2)) do { + store.@get (iter2, 0, out exit_node); + exit_nodes.append (exit_node); + } while (store.iter_next (ref iter2)); + } + try { + gconf.set_list (GCONF_KEY_EXITNODES, + GConf.ValueType.STRING, + exit_nodes); + } catch (Error e) { + Hildon.Banner.show_information (dialog, null, + "Failed to save exit node list: %s".printf (e.message)); + } + + dialog.destroy (); + } + }); + + dialog.show_all (); + } +} diff --git a/src/status-area-applet-tor.vala b/src/status-area-applet-tor.vala index 038f8fb..83225b2 100644 --- a/src/status-area-applet-tor.vala +++ b/src/status-area-applet-tor.vala @@ -37,6 +37,7 @@ class TorStatusMenuItem : HD.StatusMenuItem { private const string GCONF_DIR_TOR = "/apps/maemo/tor"; private const string GCONF_KEY_TOR_ENABLED = GCONF_DIR_TOR + "/enabled"; private const string GCONF_KEY_BRIDGES = GCONF_DIR_TOR + "/bridges"; + private const string GCONF_KEY_EXITNODES = GCONF_DIR_TOR + "/exit_nodes"; private const string GCONF_DIR_PROXY_HTTP = "/system/http_proxy"; private const string GCONF_KEY_PROXY_HTTP_ENABLED = GCONF_DIR_PROXY_HTTP + "/use_http_proxy"; @@ -189,6 +190,20 @@ class TorStatusMenuItem : HD.StatusMenuItem { "Failed to set up bridge relays"); } } + + var exits = gconf.get_list (GCONF_KEY_EXITNODES, GConf.ValueType.STRING); + + if (exits.length () > 0) { + // Enable strict exit nodes + tor_control.set_conf_list ("ExitNodes", exits); + tor_control.set_conf_bool ("StrictExitNodes", true); + + bool strict = yield tor_control.get_conf_bool_async ("StrictExitNodes"); + if (!strict) { + Hildon.Banner.show_information (null, null, + "Failed to set up strict exit nodes"); + } + } } /** @@ -356,6 +371,14 @@ class TorStatusMenuItem : HD.StatusMenuItem { } /** + * Show the exit node configuration dialog + */ + private void exit_nodes_clicked_cb () { + var dialog = new ExitNodeDialog (tor_control); + dialog.show (); + } + + /** * Check whether the IP address consists of four numbers in the 0..255 range */ bool is_valid_ip_address (string address) { @@ -404,7 +427,7 @@ class TorStatusMenuItem : HD.StatusMenuItem { private void button_clicked_cb () { var dialog = new Gtk.Dialog (); var content = (Gtk.VBox) dialog.get_content_area (); - content.set_size_request (-1, 2*70); + content.set_size_request (-1, 3*70); dialog.set_title (_("Tor: anonymity online")); @@ -422,6 +445,15 @@ class TorStatusMenuItem : HD.StatusMenuItem { button.clicked.connect (bridges_clicked_cb); content.pack_start (button, true, true, 0); + button = new Hildon.Button.with_text (Hildon.SizeType.FINGER_HEIGHT, + Hildon.ButtonArrangement.VERTICAL, + _("Restrict exit nodes"), + get_exit_node_list ()); + button.set_style (Hildon.ButtonStyle.PICKER); + button.set_alignment (0, 0.5f, 0, 0.5f); + button.clicked.connect (exit_nodes_clicked_cb); + content.pack_start (button, true, true, 0); + dialog.add_button (_("Log"), RESPONSE_LOG); dialog.add_button (_("Save"), Gtk.ResponseType.ACCEPT); @@ -473,6 +505,26 @@ class TorStatusMenuItem : HD.StatusMenuItem { return list; } + private string get_exit_node_list () { + string list = null; + var exits = new SList (); + try { + exits = gconf.get_list (GCONF_KEY_EXITNODES, GConf.ValueType.STRING); + } catch (Error e) { + error ("Error loading exit nodes: %s", e.message); + } + foreach (string exit in exits) { + if (list == null) + list = exit; + else + list += ", " + exit; + } + if (list == null) + list = _("None"); + + return list; + } + /** * Callback for the ConIc connection-event signal */ -- 1.7.9.5