Codebase list python-faraday / 67a487a
Imported Upstream version 1.0.21 Sophie Brun 7 years ago
13 changed file(s) with 886 addition(s) and 166 deletion(s). Raw diff Collapse all Expand all
1111
1212 Plugins
1313 ---
14 Don't change the way you work today! Faraday plays well with others, right now it has more than [40 supported tools](https://github.com/infobyte/faraday/wiki/Plugin-List), among them you will find:
14 Don't change the way you work today! Faraday plays well with others, right now it has more than [50 supported tools](https://github.com/infobyte/faraday/wiki/Plugin-List), among them you will find:
1515
1616 ![](https://raw.github.com/wiki/infobyte/faraday/images/plugins/Plugins.png)
1717
88
99 New features in the latest update
1010 =====================================
11
12 Jun 13, 2016:
13 ---
14 * Added Import Report dialog to Faraday GTK
15 * Added a 'Loading workspace...' dialog to Faraday GTK
16 * Added host sidebar to Faraday GTK
17 * Added host information dialog to Faraday GTK with the full data about a host, its interfaces, services and vulnerabilities
18 * Added support for run faraday from other directories.
19 * Fixed log reapparing after being disabled if user created a new tab
20 * Fixed bug regarding exception handling in Faraday GTK
21 * Now Faraday GTK supports Ctrl+Shift+C / Ctrl+Shift+V to Copy/Paste
22 * Faraday will now not crash if you suddenly lose connection to your CouchDB
1123
1224 May 23, 2016:
1325 ---
0 1.0.20
0 1.0.21
11 <faraday>
22
33 <appname>Faraday - Penetration Test IDE</appname>
4 <version>1.0.20</version>
4 <version>1.0.21</version>
55 <debug_status>0</debug_status>
66 <font>-Misc-Fixed-medium-r-normal-*-12-100-100-100-c-70-iso8859-1</font>
77 <home_path>~/</home_path>
44
55 '''
66
7 CONST_VERSION_FILE = 'VERSION'
78 CONST_REQUIREMENTS_FILE = 'requirements.txt'
89 CONST_CONFIG = 'views/reports/_attachments/scripts/config/config.json'
910 CONST_FARADAY_HOME_PATH = '~/.faraday'
5959 USER_QTRCBAK = os.path.expanduser(CONST_USER_QTRC_BACKUP)
6060 FARADAY_QTRC = os.path.join(FARADAY_BASE, CONST_FARADAY_QTRC_PATH)
6161 FARADAY_QTRCBAK = os.path.expanduser(CONST_FARADAY_QTRC_BACKUP)
62 CONST_VERSION_FILE = os.path.join(FARADAY_BASE,"VERSION")
62 FARADAY_VERSION_FILE = os.path.join(FARADAY_BASE, CONST_VERSION_FILE)
63 FARADAY_CONFIG = os.path.join(FARADAY_BASE, CONST_CONFIG)
64 FARADAY_REQUIREMENTS_FILE = os.path.join(FARADAY_BASE, CONST_REQUIREMENTS_FILE)
6365
6466 REQUESTS_CA_BUNDLE_VAR = "REQUESTS_CA_BUNDLE"
6567 FARADAY_DEFAULT_PORT_XMLRPC = 9876
213215 try:
214216 import pip
215217 modules = []
216 f = open(CONST_REQUIREMENTS_FILE)
218 f = open(FARADAY_REQUIREMENTS_FILE)
217219 for line in f:
218220 if not line.find('#'):
219221 break
536538 uri = getInstanceConfiguration().getUpdatesUri()
537539 resp = u"OK"
538540 try:
539 f = open(CONST_VERSION_FILE)
541 f = open(FARADAY_VERSION_FILE)
540542
541543 getInstanceConfiguration().setVersion(f.read().strip())
542544 getInstanceConfiguration().setAppname("Faraday - Penetration Test IDE Community")
570572
571573 def checkVersion():
572574 try:
573 f = open(CONST_VERSION_FILE)
575 f = open(FARADAY_VERSION_FILE)
574576 f_version = f.read().strip()
575577 if not args.update:
576578 if getInstanceConfiguration().getVersion() != None and getInstanceConfiguration().getVersion() != f_version:
583585
584586 doc = {"ver": getInstanceConfiguration().getVersion()}
585587
586 if os.path.isfile(CONST_CONFIG):
587 os.remove(CONST_CONFIG)
588 with open(CONST_CONFIG, "w") as doc_file:
588 if os.path.isfile(FARADAY_CONFIG):
589 os.remove(FARADAY_CONFIG)
590 with open(FARADAY_CONFIG, "w") as doc_file:
589591 json.dump(doc, doc_file)
590592 except Exception as e:
591593 getLogger("launcher").error("It seems that something's wrong with your version\nPlease contact customer support")
615617 Main function for launcher.
616618
617619 """
620
621 os.chdir(FARADAY_BASE)
618622
619623 init()
620624 if checkDependencies():
88
99 import os
1010 import sys
11 import threading
1112
1213 try:
1314 import gi
2425 " of GTK and VTE. Check install of VTE 2.91 and GTK+3")
2526
2627 try:
28 # there are several imports not needed here, but they're needed in other
29 # modules. this just checks for every dependence when starting the app
2730 from gi.repository import Gio, Gtk, GdkPixbuf, Vte, GLib, GObject, Gdk
2831 except ImportError as e:
2932 print ("You are missing some of the required dependencies. "
4851 from dialogs import helpDialog
4952 from dialogs import ImportantErrorDialog
5053 from dialogs import ConflictsDialog
54 from dialogs import HostInfoDialog
55 from dialogs import errorDialog
5156
5257 from mainwidgets import Sidebar
58 from mainwidgets import WorkspaceSidebar
59 from mainwidgets import HostsSidebar
5360 from mainwidgets import ConsoleLog
5461 from mainwidgets import Terminal
5562 from mainwidgets import Statusbar
5966
6067 CONF = getInstanceConfiguration()
6168
69
6270 class GuiApp(Gtk.Application, FaradayUi):
6371 """
6472 Creates the application and has the necesary callbacks to FaradayUi
65 Right now handles by itself only the menu, everything is else is
66 appWindow's resposibility as far as the initial UI goes.
67 The dialogs are found inside the dialogs module
73 As far as the GUI goes, this handles only the menu, everything is else is
74 appWindow's resposibility. All logic by the main window should be done
75 here. Some of the logic on the dialogs is implemented in the dialogs own
76 class. Some dialogs are shown by the appwindow to handle errors coming
77 from other threads outside GTK's.
6878 """
6979
7080 def __init__(self, model_controller, plugin_manager, workspace_manager,
7181 plugin_controller):
82 """Does not do much. Most of the initialization work is actually
83 done by the run() method, as specified in FaradayUi."""
7284
7385 FaradayUi.__init__(self,
7486 model_controller,
7991 Gtk.Application.__init__(self, application_id="org.infobyte.faraday",
8092 flags=Gio.ApplicationFlags.FLAGS_NONE)
8193
82 icons = CONF.getImagePath() + "icons/"
83 faraday_icon = icons + "faraday_icon.png"
94 self.icons = CONF.getImagePath() + "icons/"
95 faraday_icon = self.icons + "faraday_icon.png"
8496 self.icon = GdkPixbuf.Pixbuf.new_from_file_at_scale(faraday_icon, 16,
8597 16, False)
8698 self.window = None
94106 return self.window
95107
96108 def updateConflicts(self):
109 """Reassings self.conflicts with an updated list of conflicts"""
97110 self.conflicts = self.model_controller.getConflicts()
111
112 def updateHosts(self):
113 """Reassings the value of self.all_hosts to a current one to
114 catch workspace changes, new hosts added via plugins or any other
115 external interference with out host list"""
116 self.all_hosts = self.model_controller.getAllHosts()
98117
99118 def createWorkspace(self, name, description="", w_type=""):
100119 """Pretty much copy/pasted from the QT3 GUI.
133152 if CONF.getLastWorkspace() == ws_name:
134153 self.openDefaultWorkspace()
135154 self.getWorkspaceManager().removeWorkspace(ws_name)
136 self.sidebar.clearSidebar()
137 self.sidebar.refreshSidebar()
155 self.ws_sidebar.clearSidebar()
156 self.ws_sidebar.refreshSidebar()
138157
139158 def do_startup(self):
140159 """
141160 GTK calls this method after Gtk.Application.run()
142161 Creates instances of the sidebar, terminal, console log and
143162 statusbar to be added to the app window.
144 Sets up necesary acttions on menu and toolbar buttons
163 Sets up necesary actions on menu and toolbar buttons
145164 Also reads the .xml file from menubar.xml
146165 """
147166 Gtk.Application.do_startup(self) # deep GTK magic
148167
149 self.sidebar = Sidebar(self.workspace_manager,
150 self.changeWorkspace,
151 self.removeWorkspace,
152 self.on_new_button,
153 CONF.getLastWorkspace())
168 self.ws_sidebar = WorkspaceSidebar(self.workspace_manager,
169 self.changeWorkspace,
170 self.removeWorkspace,
171 self.on_new_button,
172 CONF.getLastWorkspace())
173
174 self.updateHosts()
175 self.hosts_sidebar = HostsSidebar(self.show_host_info, self.icons)
176 default_model = self.hosts_sidebar.create_model(self.all_hosts)
177 self.hosts_sidebar.create_view(default_model)
178
179 self.sidebar = Sidebar(self.ws_sidebar.get_box(),
180 self.hosts_sidebar.get_box())
154181
155182 host_count, service_count, vuln_count = self.update_counts()
156183
188215
189216 action = Gio.SimpleAction.new("new_terminal") # new terminal = new tab
190217 action.connect("activate", self.on_new_terminal_button)
218 self.add_action(action)
219
220 action = Gio.SimpleAction.new("open_report")
221 action.connect("activate", self.on_open_report_button)
191222 self.add_action(action)
192223
193224 dirname = os.path.dirname(os.path.abspath(__file__))
200231
201232 def do_activate(self):
202233 """If there's no window, create one and present it (show it to user).
203 If there's a window, just present it"""
234 If there's a window, just present it. Also add the log handler
235 and the notifier to the application"""
204236
205237 # We only allow a single window and raise any existing ones
206238 if not self.window:
226258 model.guiapi.notification_center.registerWidget(self.window)
227259
228260 def postEvent(self, receiver, event):
261 """Handles the events from gui/customevents."""
229262 if receiver is None:
230263 receiver = self.getMainWindow()
231264
232 if event.type() == 3131: # new log event
265 elif event.type() == 3131: # new log event
233266 receiver.emit("new_log", event.text)
234267
235 if event.type() == 3141: # new conflict event
268 elif event.type() == 3141: # new conflict event
236269 receiver.emit("set_conflict_label", event.nconflicts)
237270
238 if event.type() == 5100: # new notification event
271 elif event.type() == 5100: # new notification event
239272 self.notificationsModel.prepend([event.change.getMessage()])
240273 receiver.emit("new_notif")
241274 host_count, service_count, vuln_count = self.update_counts()
242275 receiver.emit("update_ws_info", host_count,
243276 service_count, vuln_count)
244277
245 if event.type() == 4100 or event.type() == 3140: # newinfo or changews
278 elif event.type() == 4100 or event.type() == 3140: # newinfo or changews
246279 host_count, service_count, vuln_count = self.update_counts()
280 self.updateHosts()
281 self.hosts_sidebar.update(self.all_hosts)
247282 receiver.emit("update_ws_info", host_count,
248283 service_count, vuln_count)
249284
250 if event.type() == 3132: # error
251 dialog_text = event.text
252 dialog = Gtk.MessageDialog(self.window, 0,
253 Gtk.MessageType.INFO,
254 Gtk.ButtonsType.OK,
255 dialog_text)
256 dialog.run()
257 dialog.destroy()
258
259 if event.type() == 3134: # important error, uncaught exception
260 dialog_text = event.text
261 dialog = ImportantErrorDialog(self.window, dialog_text)
262 response = dialog.run()
263 if response == 42:
264 error = event.error_name
265 event.callback(error, *event.exception_objects)
266 dialog.destroy()
285 elif event.type() == 3132: # error
286 self.window.emit("normal_error", event.text)
287
288 elif event.type() == 3134: # important error, uncaught exception
289 self.window.prepare_important_error(event)
290 self.window.emit("important_error")
267291
268292 def update_counts(self):
293 """Update the counts for host, services and vulns"""
269294 host_count = self.model_controller.getHostsCount()
270295 service_count = self.model_controller.getServicesCount()
271296 vuln_count = self.model_controller.getVulnsCount()
272297 return host_count, service_count, vuln_count
298
299 def on_open_report_button(self, action, param):
300 """What happens when the user clicks the open report button.
301 A dialog will present itself with a combobox to select a plugin.
302 Then a file chooser to select a report. The report will be processed
303 with the selected plugin.
304 """
305
306 def select_plugin():
307 """Creates a simple dialog with a combo box to select a plugin"""
308 plugins_id = [_id for _id in self.plugin_manager.getPlugins()]
309 plugins_id = sorted(plugins_id)
310 dialog = Gtk.Dialog("Select plugin", self.window, 0)
311
312 combo_box = Gtk.ComboBoxText()
313 for plugin_id in plugins_id:
314 combo_box.append_text(plugin_id)
315 combo_box.show()
316
317 dialog.vbox.pack_start(combo_box, True, True, 10)
318
319 dialog.add_button("Cancel", Gtk.ResponseType.DELETE_EVENT)
320 dialog.add_button("OK", Gtk.ResponseType.ACCEPT)
321
322 response = dialog.run()
323 selected = combo_box.get_active_text()
324
325 dialog.destroy()
326 return response, selected
327
328 def on_file_selected(plugin_id, report):
329 """Send the plugin_id and the report file to be processed"""
330 self.report_manager.sendReportToPluginById(plugin_id, report)
331
332 plugin_response, plugin_id = select_plugin()
333
334 while plugin_response == Gtk.ResponseType.ACCEPT and plugin_id is None:
335 # force user to select a plugin if he did not do it
336 errorDialog(self.window,
337 "Please select a plugin to parse your report!")
338 plugin_response, plugin_id = select_plugin()
339 else:
340 if plugin_response == Gtk.ResponseType.ACCEPT:
341 dialog = Gtk.FileChooserNative()
342 dialog.set_title("Import a report")
343 dialog.set_modal(True)
344 dialog.set_transient_for(self.window)
345 dialog.set_action(Gtk.FileChooserAction.OPEN)
346
347 res = dialog.run()
348 if res == Gtk.ResponseType.ACCEPT:
349 on_file_selected(plugin_id, dialog.get_filename())
350 dialog.destroy()
273351
274352 def on_about(self, action, param):
275353 """ Defines what happens when you press 'about' on the menu"""
295373 self.window)
296374 preference_window.show_all()
297375
376 def show_host_info(self, host_id):
377 """Looks up the host selected in the HostSidebar by id and shows
378 its information on the HostInfoDialog"""
379
380 for host in self.all_hosts:
381 if host_id == host.id:
382 selected_host = host
383 break
384
385 info_window = HostInfoDialog(self.window, selected_host)
386 info_window.show_all()
387
298388 def reloadWorkspaces(self):
299 """Used in conjunction with on_preferences: close workspace,
300 resources the workspaces available, clears the sidebar of the old
301 workspaces and injects all the new ones in there too"""
389 """Close workspace, resources the workspaces available,
390 clears the sidebar of the old workspaces and injects all the new ones
391 in there too"""
302392 self.workspace_manager.closeWorkspace()
303393 self.workspace_manager.resource()
304 self.sidebar.clearSidebar()
305 self.sidebar.refreshSidebar()
394 self.ws_sidebar.clearSidebar()
395 self.ws_sidebar.refreshSidebar()
306396
307397 def on_pluginOptions(self, action, param):
308398 """Defines what happens when you press "Plugins" on the menu"""
314404 "Defines what happens when you press the 'new' button on the toolbar"
315405 new_workspace_dialog = NewWorkspaceDialog(self.createWorkspace,
316406 self.workspace_manager,
317 self.sidebar, self.window,
407 self.ws_sidebar, self.window,
318408 title)
319409 new_workspace_dialog.show_all()
320410
328418
329419 def on_click_notifications(self, button):
330420 """Defines what happens when the user clicks on the notifications
331 button."""
421 button: just show a silly window with a treeview containing
422 all the notifications"""
332423
333424 notifications_view = Gtk.TreeView(self.notificationsModel)
334425 renderer = Gtk.CellRendererText()
340431 notifications_dialog.show_all()
341432
342433 def on_click_conflicts(self, button=None):
343 """Doesn't use the button at all. Shows the conflict dialog"""
434 """Doesn't use the button at all, there cause GTK likes it.
435 Shows the conflict dialog.
436 """
344437 self.updateConflicts()
345438 if self.conflicts:
346439 dialog = ConflictsDialog(self.conflicts,
357450 dialog.destroy()
358451
359452 def delete_notifications(self):
453 """Clear the notifications model of all info, also send a signal
454 to get the notification label to 0 on the main window's button
455 """
360456 self.notificationsModel.clear()
361457 self.window.emit("clear_notifications")
362458
363 def changeWorkspace(self, selection):
364 """Pretty much copy/pasted from QT3 GUI.
365 Selection is actually used nowhere, but the connect function is
366 Sidebar passes it as an argument so well there it is"""
367
368 tree_model, treeiter = selection.get_selected()
369 workspaceName = tree_model[treeiter][0]
370
371 try:
372 ws = super(GuiApp, self).openWorkspace(workspaceName)
373 except Exception as e:
374 model.guiapi.notification_center.showDialog(str(e))
375 ws = self.openDefaultWorkspace()
376 workspace = ws.name
377 CONF.setLastWorkspace(workspace)
378 CONF.saveConfig()
379 return ws
459 def changeWorkspace(self, workspaceName):
460 """Changes workspace in a separate thread. Emits a signal
461 to present a 'Loading workspace' dialog while Faraday processes
462 the change"""
463
464 def background_process():
465 self.window.emit("loading_workspace", 'show')
466 try:
467 ws = super(GuiApp, self).openWorkspace(workspaceName)
468 except Exception as e:
469 model.guiapi.notification_center.showDialog(str(e))
470 ws = self.openDefaultWorkspace()
471
472 workspace = ws.name
473 CONF.setLastWorkspace(workspace)
474 CONF.saveConfig()
475 self.window.emit("loading_workspace", "destroy")
476
477 return True
478
479 thread = threading.Thread(target=background_process)
480 thread.daemon = True
481 thread.start()
380482
381483 def run(self, args):
382484 """First method to run, as defined by FaradayUi. This method is
1313 gi.require_version('Vte', '2.91')
1414
1515 from gi.repository import GLib, Gio, Gtk, GObject, Gdk
16 from dialogs import ImportantErrorDialog
17 from dialogs import errorDialog
1618
1719 CONF = getInstanceConfiguration()
1820
4042 "new_notif": (GObject.SIGNAL_RUN_FIRST, None, ()),
4143 "clear_notifications": (GObject.SIGNAL_RUN_FIRST, None, ()),
4244 "update_ws_info": (GObject.SIGNAL_RUN_FIRST, None, (int, int, int, )),
43 "set_conflict_label": (GObject.SIGNAL_RUN_FIRST, None, (int, ))
45 "set_conflict_label": (GObject.SIGNAL_RUN_FIRST, None, (int, )),
46 "loading_workspace": (GObject.SIGNAL_RUN_FIRST, None, (str, )),
47 "normal_error": (GObject.SIGNAL_RUN_FIRST, None, (str, )),
48 "important_error": (GObject.SIGNAL_RUN_FIRST, None, ()),
4449 }
4550
4651 def __init__(self, sidebar, terminal, console_log, statusbar,
6469
6570 self.icons = CONF.getImagePath() + "icons/"
6671
67 # sets up the clipboard
68 self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
69 self.selection_clipboard = Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY)
70
7172 # Keep it in sync with the actual state. Deep dark GTK magic
7273 self.connect("notify::is-maximized",
7374 lambda obj, pspec:
7980 self.topBox.pack_start(self.create_toolbar(), True, True, 0)
8081
8182 # SIDEBAR BOX
82 search = self.sidebar.getSearchEntry()
83 self.sidebarBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
84 self.sidebarBox.pack_start(search, False, False, 0)
85 self.sidebarBox.pack_start(self.sidebar.scrollableView, True, True, 0)
86 self.sidebarBox.pack_start(self.sidebar.getButton(), False, False, 0)
83 self.sidebarBox = self.sidebar.get_box()
8784
8885 # TERMINAL BOX
8986 self.firstTerminalBox = self.terminalBox(self.terminal.getTerminal())
142139 """Defines the menu created when a user rightclicks on the
143140 terminal eventbox"""
144141 menu = Gtk.Menu()
145 copy = Gtk.MenuItem("Copy")
146 paste = Gtk.MenuItem("Paste")
147 menu.append(paste)
148 menu.append(copy)
149
150 # TODO: make accelerators for copy paste work. add accel for paste
151 # accelgroup = Gtk.AccelGroup()
152 # self.add_accel_group(accelgroup)
153 # accellabel = Gtk.AccelLabel("Copy/Paste")
154 # accellabel.set_hexpand(True)
155 # copy.add_accelerator("activate",
156 # accelgroup,
157 # Gdk.keyval_from_name("c"),
158 # Gdk.ModifierType.SHIFT_MASK |
159 # Gdk.ModifierType.CONTROL_MASK,
160 # Gtk.AccelFlags.VISIBLE)
161
162 copy.connect("activate", self.copy_text)
163 paste.connect("activate", self.paste_text)
164
165 copy.show()
166 paste.show()
142 self.copy = Gtk.MenuItem("Copy")
143 self.paste = Gtk.MenuItem("Paste")
144 menu.append(self.paste)
145 menu.append(self.copy)
146
147 self.copy.connect("activate", self.copy_text)
148 self.paste.connect("activate", self.paste_text)
149
150 self.copy.show()
151 self.paste.show()
167152 menu.popup(None, None, None, None, event.button, event.time)
168153
169 def copy_text(self, button):
170 """What happens when the user copies text"""
171 content = self.selection_clipboard.wait_for_text()
172 self.clipboard.set_text(content, -1)
173
174 def paste_text(self, button):
175 """What happens when the user pastes text"""
154 def copy_text(self, _):
155 """When the user presses on the copy button on the menu..."""
156 currentTerminal = self.getCurrentFocusedTerminal()
157 currentTerminal.copy_clipboard()
158
159 def paste_text(self, _):
160 """When the user presses on the paste button on the menu..."""
176161 currentTerminal = self.getCurrentFocusedTerminal()
177162 currentTerminal.paste_clipboard()
178163
183168 def getCurrentFocusedTerminal(self):
184169 """Returns the current focused terminal"""
185170
186 # the focused terminal is the only children of the notebook
187 # thas has only children an event box that has as only children
188 # the scrolled window that has as only children the
189 # terminal. Yeah, I know.
171 # the focused terminal is the child of the event box which is
172 # the top widget of the focused tab. that event box has as only child
173 # a box, which has as only child a scrolled window, which has as
174 # only child the terminal. yeah. I know.
190175
191176 currentTab = self.getFocusedTab()
192177 currentEventBox = self.notebook.get_children()[currentTab]
195180 currentTerminal = currentScrolledWindow.get_child()
196181 return currentTerminal
197182
183 def prepare_important_error(self, event):
184 """Attaches an event to the class, so it can be used by the signal
185 callbacks even if they cannot be passed directly.
186 """
187 self.event = event
188
189 def do_important_error(self):
190 """Creates an importan error dialog with a callback to send
191 the developers the error traceback.
192 """
193 dialog_text = self.event.text
194 dialog = ImportantErrorDialog(self, dialog_text)
195 response = dialog.run()
196 if response == 42:
197 error = self.event.error_name
198 event.callback(error, *self.event.exception_objects)
199 dialog.destroy()
200
201 def do_normal_error(self, dialog_text):
202 """Just a simple, normal, ignorable error"""
203 dialog = Gtk.MessageDialog(self, 0,
204 Gtk.MessageType.ERROR,
205 Gtk.ButtonsType.OK,
206 dialog_text)
207 dialog.run()
208 dialog.destroy()
209
198210 def do_new_log(self, text):
199211 """To be used on a new_log signal. Calls a method on log to append
200212 to it"""
209221 self.statusbar.inc_notif_button_label()
210222
211223 def do_set_conflict_label(self, conflict_number):
224 """Sets the conflict label to the appropiate conflict_number"""
212225 self.statusbar.update_conflict_button_label(conflict_number)
213226
214227 def do_update_ws_info(self, host_count, service_count, vuln_count):
228 """Sets the statusbar workspace info to the appropiate numbers"""
215229 self.statusbar.update_ws_info(host_count, service_count, vuln_count)
230
231 def do_loading_workspace(self, action):
232 """Called by changeWorkspace on the application. Presents
233 a silly loading dialog.
234 Preconditions: show must have been called before destroy can be called
235 """
236 def do_nothing(widget, event):
237 """Do nothing. Well, technically, return True.
238
239 Avoids the user to interact with the dialog in anyway, for example,
240 via the Escape key.
241 You'll have to wait for my dialog to exit by itself, cowboy.
242 """
243 return True
244
245 if action == "show":
246 self.loading_dialog = Gtk.MessageDialog(self, 0,
247 Gtk.MessageType.INFO,
248 Gtk.ButtonsType.NONE,
249 ("Loading workspace. \n"
250 "Please wait."))
251
252 self.loading_dialog.set_modal(True)
253 self.loading_dialog.connect("key_press_event", do_nothing)
254
255 self.loading_dialog.show_all()
256 if action == "destroy":
257 self.loading_dialog.destroy()
258
216259
217260 def getLogConsole(self):
218261 """Returns the LogConsole. Needed by the GUIHandler logger"""
228271
229272 def refreshSidebar(self):
230273 """Call the refresh method on sidebar. It will append new workspaces,
231 but it will *NOT* delete workspaces not found anymore in the current
232 ws anymore"""
274 but it will *NOT* delete workspaces not found in the current
275 ws"""
233276 self.sidebar.refresh()
234277
235278 def create_toolbar(self):
236279 """ Creates toolbar with an open and new button, getting the icons
237 from the stock. The method by which it does this is deprecated,
238 this could be improved"""
280 from the stock. """
239281
240282 toolbar = Gtk.Toolbar()
241283 toolbar.set_hexpand(True)
247289 new_terminal_icon = Gtk.Image.new_from_file(icons + "newshell.png")
248290 preferences_icon = Gtk.Image.new_from_file(icons + "config.png")
249291 toggle_log_icon = Gtk.Image.new_from_file(icons + "debug.png")
292 open_report_icon = Gtk.Image.new_from_file(icons + "FolderSteel-20.png")
250293
251294 new_terminal_button = Gtk.ToolButton.new(new_terminal_icon, None)
252295 new_terminal_button.set_tooltip_text("Create a new tab")
270313 toggle_log_button.connect("clicked", self.toggle_log)
271314 toolbar.insert(toggle_log_button, 3)
272315
316 space = Gtk.ToolItem()
317 space.set_expand(True)
318 toolbar.insert(space, 4)
319
320 open_report_button = Gtk.ToolButton.new(open_report_icon, None)
321 open_report_button.set_tooltip_text("Import report")
322 open_report_button.set_action_name('app.open_report')
323 toolbar.insert(open_report_button, 5)
324
273325 return toolbar
274326
275327 def new_tab(self, scrolled_window):
283335 tab_number = self.tab_number
284336 pageN = self.terminalBox(scrolled_window)
285337 self.notebook.append_page(pageN, Gtk.Label(str(tab_number+1)))
286 self.show_all()
338 self.notebook.show_all()
287339
288340 def delete_tab(self, button=None):
289341 """Deletes the current tab or closes the window if tab is only tab"""
290342 if self.tab_number == 0:
291 # the following confusing but its how gtks handles delete_event
343 # the following is confusing but its how gtks handles delete_event
292344 # if user said YES to confirmation, do_delete_event returns False
293345 if not self.do_delete_event():
294346 self.destroy()
325377 if response == Gtk.ResponseType.YES:
326378 return False # keep on going and destroy
327379 else:
328 # user say you know what i don't want to exit
380 # user said "you know what i don't want to exit"
329381 return True
330382
331383 def on_terminal_exit(self, terminal, status):
1919
2020 CONF = getInstanceConfiguration()
2121
22 """This could probably be made much better with just a little effort.
23 It'd be probably a good idea to make a super class Dialog from which
24 all the dialogs inherit from with the common methods used (particularly the
25 OK and Cancel buttons). Good starting point if we continue on with the idea
26 of using GTK.
27
28 Update: so it seems like Gtk actually already provides a Gtk.Dialog class
29 which would seem practical. All dialogs are already made and it is a
30 convenience class only, but if there's need to add more, it's a good
31 thing to know"""
32
33
3422 class PreferenceWindowDialog(Gtk.Window):
3523 """Sets up a preference dialog with basically nothing more than a
3624 label, a text entry to input your CouchDB IP and a couple of buttons.
4331 self.set_modal(True)
4432 self.set_size_request(400, 100)
4533 self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
46 self.connect("key_press_event", on_scape)
34 self.connect("key_press_event", on_scape_destroy)
4735 self.set_transient_for(parent)
4836 self.timeout_id = None
4937 self.reloadWorkspaces = callback
10492 self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
10593 self.set_transient_for(parent)
10694 self.set_modal(True)
107 self.connect("key_press_event", on_scape)
95 self.connect("key_press_event", on_scape_destroy)
10896 self.set_size_request(200, 200)
10997 self.timeout_id = None
11098 self.callback = callback
196184 self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
197185 self.set_transient_for(parent)
198186 self.set_modal(True)
199 self.connect("key_press_event", on_scape)
187 self.connect("key_press_event", on_scape_destroy)
200188 self.set_size_request(800, 300)
201189
202190 if plugin_manager is not None:
393381 self.createAdecuatePluginSettingView(adecuateModel)
394382
395383
384 class HostInfoDialog(Gtk.Window):
385 """Sets the blueprints for a simple host info window. It will display
386 basic information in labels as well as interfaces/services in a treeview
387 """
388 def __init__(self, parent, host):
389 """Creates a window with the information about a given hosts.
390 The parent is needed so the window can set transient for
391 """
392 Gtk.Window.__init__(self,
393 title="Host " + host.name + " information")
394 self.set_transient_for(parent)
395 self.set_size_request(1200, 500)
396 self.set_modal(True)
397 self.connect("key_press_event", on_scape_destroy)
398 self.host = host
399
400 self.specific_info = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
401 self.specific_info_frame = self.create_scroll_frame(
402 self.specific_info,
403 "Service Information")
404
405 self.specific_vuln_info = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
406 self.specific_vuln_info_frame = self.create_scroll_frame(
407 self.specific_vuln_info,
408 "Vulnerability Information")
409
410 basic_info_frame = self.create_basic_info_box(host)
411 children_of_host_tree = self.create_display_tree_box(host)
412 button = Gtk.Button.new_with_label("OK")
413 button.connect("clicked", self.on_click_ok)
414
415 main_box = Gtk.Box()
416
417 info_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
418 info_box.pack_start(basic_info_frame, True, True, 10)
419 info_box.pack_start(self.specific_info_frame, True, True, 10)
420 info_box.pack_start(self.specific_vuln_info_frame, True, True, 10)
421 info_box.pack_start(button, False, False, 10)
422
423 main_tree_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
424 main_tree_box.pack_start(children_of_host_tree, True, True, 10)
425 main_tree_box.pack_start(Gtk.Box(), False, False, 10)
426
427 vuln_list_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
428 vuln_list_box.pack_start(self.create_vuln_tree_box(), True, True, 10)
429 vuln_list_box.pack_start(Gtk.Box(), False, False, 10)
430
431 main_box.pack_start(main_tree_box, False, False, 5)
432 main_box.pack_start(vuln_list_box, False, False, 0)
433 main_box.pack_start(info_box, True, True, 5)
434
435 self.add(main_box)
436
437 def create_scroll_frame(self, inner_box, label_str):
438 """Create a scrollable frame.
439
440 inner_box will be the scrollable frame content.
441 label_str will be the scrollable frame title.
442
443 Scrollable will be set to always show vertical scrollbars and will
444 have disabled overlay scrolling
445 """
446 label = Gtk.Label()
447 label.set_markup("<big>" + label_str + "</big>")
448
449 scroll_box = Gtk.ScrolledWindow(None, None)
450 scroll_box.set_overlay_scrolling(False)
451 scroll_box.set_policy(Gtk.PolicyType.AUTOMATIC,
452 Gtk.PolicyType.ALWAYS)
453
454 scroll_box.add(inner_box)
455
456 frame = Gtk.Frame()
457 frame.set_label_widget(label)
458 frame.add(scroll_box)
459
460 return frame
461
462 def create_basic_info_box(self, host):
463 """Creates a box where the basic information about the host
464 lives in labels. It include names, OS, Owned status and vulnarability
465 count.
466 """
467 box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
468
469 name_box = Gtk.Box()
470 name_label = Gtk.Label()
471 name_label.set_markup("<b>%s</b>: %s" % ("Name", host.getName()))
472 name_label.set_selectable(True)
473 name_box.pack_start(name_label, False, False, 5)
474
475 os_box = Gtk.Box()
476 os_label = Gtk.Label()
477 os_label.set_markup("<b>%s</b>: %s" % ("OS", host.getOS()))
478 os_label.set_selectable(True)
479 os_box.pack_start(os_label, False, False, 5)
480
481 owned_box = Gtk.Box()
482 owned_label = Gtk.Label()
483 owned_status = ("Yes" if host.isOwned() else "No")
484 owned_label.set_markup("<b>%s: </b>%s" % ("Owned", owned_status))
485 owned_label.set_selectable(True)
486 owned_box.pack_start(owned_label, False, False, 5)
487
488 vulns_box = Gtk.Box()
489 vulns_label = Gtk.Label()
490 vulns_count = str(len(host.getVulns()))
491 vulns_label.set_markup("<b>%s</b>: %s" %
492 ("Vulnerabilities", vulns_count))
493 vulns_label.set_selectable(True)
494
495 vulns_box.pack_start(vulns_label, False, False, 5)
496
497 box.pack_start(name_box, False, True, 0)
498 box.pack_start(os_box, False, True, 0)
499 box.pack_start(owned_box, False, True, 0)
500 box.pack_start(vulns_box, False, False, 0)
501
502 basic_info_frame = self.create_scroll_frame(box, "Host Information")
503
504 return basic_info_frame
505
506 def create_vuln_tree_box(self):
507 """Creates a simple view a vulnerabilities"""
508 box = Gtk.Box()
509 self.vuln_list = Gtk.TreeView()
510 self.vuln_list.set_activate_on_single_click(True)
511 renderer = Gtk.CellRendererText()
512 column = Gtk.TreeViewColumn("Vulnerabilities", renderer, text=1)
513 self.vuln_list.append_column(column)
514
515 vuln_selection = self.vuln_list.get_selection()
516 vuln_selection.connect("changed", self.on_vuln_selection)
517
518 scrolled_view = Gtk.ScrolledWindow(None, None)
519 scrolled_view.add(self.vuln_list)
520 scrolled_view.set_min_content_width(250)
521 box.pack_start(scrolled_view, True, True, 10)
522
523 return box
524
525 def create_display_tree_box(self, host):
526 """Creates a model and a view for the interfaces/services of the host.
527 Puts a scrolled window containing the view into a box and returns
528 that. The models holds quite a bit of information. It has 11 columns
529 holding the host ID and name as parent, all the information about
530 the interfaces of that host and all the information about
531 the services of those interfaces.
532 """
533
534 box = Gtk.Box()
535 interfaces = host.getAllInterfaces()
536 # those are 15 strings
537 model = Gtk.TreeStore(str, str, str, str, str, str, str,
538 str, str, str, str, str, str)
539
540 # GTK is very strict about how many columns the model has.
541 # only the ID and the name are needed, but i still need to 'fill'
542 # the other columns with dummy info
543
544 display_str = host.getName() + " (" + str(len(host.getVulns())) + ")"
545 host_iter = model.append(None, [host.getID(), host.getName(),
546 "", "", "", "", "", "",
547 "", "", "", "", display_str])
548
549 def lst_to_str(lst):
550 """Convenient function to avoid this long line everywhere"""
551 return ', '.join([str(word) for word in lst if word])
552
553 for interface in interfaces:
554 ipv4_dic = interface.getIPv4()
555 ipv6_dic = interface.getIPv6()
556 vulns = interface.getVulns()
557 display_str = interface.getName() + " (" + str(len(vulns)) + ")"
558
559 tree_iter = model.append(host_iter, [interface.getID(),
560 interface.getName(),
561 interface.getDescription(),
562 interface.getMAC(),
563 ipv4_dic['mask'],
564 ipv4_dic['gateway'],
565 lst_to_str(ipv4_dic['DNS']),
566 ipv4_dic['address'],
567 ipv6_dic['prefix'],
568 ipv6_dic['gateway'],
569 lst_to_str(ipv6_dic['DNS']),
570 ipv6_dic['address'],
571 display_str])
572
573 services = interface.getAllServices()
574 for service in services:
575 # Same as with the host, empty strings are there
576 # just to agree with the number of columns the model should
577 # have
578 vulns = service.getVulns()
579 display_str = service.getName() + " (" + str(len(vulns)) + ")"
580 model.append(tree_iter, [service.getID(),
581 service.getName(),
582 service.getDescription(),
583 service.getProtocol(),
584 service.getStatus(),
585 lst_to_str(service.getPorts()),
586 service.getVersion(),
587 "Yes" if service.isOwned() else "No",
588 "", "", "", "", display_str])
589
590 self.view = Gtk.TreeView(model)
591 self.view.set_activate_on_single_click(True)
592
593 renderer = Gtk.CellRendererText()
594 column = Gtk.TreeViewColumn("Host/Interfaces/Services",
595 renderer, text=12)
596
597 self.view.append_column(column)
598 selection = self.view.get_selection()
599 selection.connect("changed", self.on_selection)
600
601 scrolled_view = Gtk.ScrolledWindow(None, None)
602 scrolled_view.add(self.view)
603 scrolled_view.set_min_content_width(250)
604 box.pack_start(scrolled_view, True, True, 10)
605
606 return box
607
608 def on_selection(self, tree_selection):
609 """Defines what happens when the user clicks on a row. Shows
610 the interface or service information according to what the user
611 selected. Before calling the corresponding functions, will clear
612 the current specific_info box.
613 """
614 model, tree_iter = tree_selection.get_selected()
615 iter_depth = model.iter_depth(tree_iter)
616 selected = model[tree_iter]
617 self.specific_info.foreach(self.reset_info) # delete what was there
618 if iter_depth == 0:
619 self.set_vuln_model(self.create_vuln_model(self.host))
620 elif iter_depth == 1:
621 label = self.specific_info_frame.get_label_widget()
622 label.set_markup("<big>Interface information</big>")
623 self.show_interface_info(selected)
624 interface = self.host.getInterface(selected[0])
625 self.set_vuln_model(self.create_vuln_model(interface))
626 elif iter_depth == 2:
627 label = self.specific_info_frame.get_label_widget()
628 label.set_markup("<big>Service information</big>")
629 self.show_service_info(selected)
630 parent_interface_iter = selected.get_parent()
631 parent_interface_id = parent_interface_iter[0]
632 parent_interface = self.host.getInterface(parent_interface_id)
633 service = parent_interface.childs.get(selected[0], None)
634 self.set_vuln_model(self.create_vuln_model(service))
635
636 def on_vuln_selection(self, vuln_selection):
637 """Sets up the information necesarry to show the detailed information
638 of the vulnerability. The try/except block is necesary 'cause GTK
639 is silly and will emit the selection changed signal if the model
640 changes even if nothing is selected"""
641
642 model, vuln_iter = vuln_selection.get_selected()
643 self.specific_vuln_info.foreach(self.reset_vuln_info)
644 try:
645 selected = model[vuln_iter]
646 self.show_vuln_info(selected)
647 except TypeError:
648 return False
649
650 def set_vuln_model(self, model):
651 self.vuln_list.set_model(model)
652
653 def create_vuln_model(self, obj):
654 """Creates a model for the vulnerabilities of the selected object"""
655 # those are 15 strings
656 model = Gtk.ListStore(str, str, str, str, str, str, str, str,
657 str, str, str, str, str, str, str)
658
659 vulns = obj.getVulns()
660 for vuln in vulns:
661 _type = vuln.class_signature
662 if _type == "Vulnerability":
663 model.append([_type, vuln.getName(), vuln.getDescription(),
664 vuln.getData(), vuln.getSeverity(),
665 ', '.join(vuln.getRefs()),
666 "", "", "", "", "", "", "", "", ""])
667
668 elif _type == "VulnerabilityWeb":
669 model.append([_type, vuln.getName(), vuln.getDescription(),
670 vuln.getData(), vuln.getSeverity(),
671 ", ".join(vuln.getRefs()), vuln.getPath(),
672 vuln.getWebsite(), vuln.getRequest(),
673 vuln.getResponse(), vuln.getMethod(),
674 vuln.getPname(), vuln.getParams(),
675 vuln.getQuery(), vuln.getCategory()])
676 return model
677
678 def show_interface_info(self, selected):
679 """Creates labels for each of the properties of an interface. Appends
680 them to the specific_info_box.
681 """
682 for prop in enumerate(["Name: ", "Description: ", "MAC: ",
683 "IPv4 Mask: ", "IPv4 Gateway: ", "IPv4 DNS: ",
684 "IPv4 Address: ", "IPv6 Prefix: ",
685 "IPv6 Gateway", "IPv6 DNS: ",
686 "IPv6 Address: "], start=1):
687 self.append_info_to_box(selected, prop, self.specific_info)
688
689 def show_service_info(self, selected):
690 """Creates labels for each of the properties of a service. Appends
691 them to the specific_info_box.
692 """
693 for prop in enumerate(["Name: ", "Description: ", "Protocol: ",
694 "Status: ", "Port: ", "Version: ",
695 "Is Owned?: "], start=1):
696 self.append_info_to_box(selected, prop, self.specific_info)
697
698 def show_vuln_info(self, selected):
699 """Sends the information about the selected vuln to
700 append_info_to_box.
701 """
702 if selected[0] == "Vulnerability":
703 for prop in enumerate(["Name: ", "Description: ",
704 "Data: ", "Severity: ",
705 "Refs: "], start=1):
706 self.append_info_to_box(selected, prop,
707 self.specific_vuln_info)
708 if selected[0] == "VulnerabilityWeb":
709 for prop in enumerate(["Name: ", "Description: ",
710 "Data: ", "Severity: ",
711 "Refs: ", "Path: ",
712 "Website: ", "Request: ",
713 "Response: ", "Method: ",
714 "Pname: ", "Params: ",
715 "Query: ", "Category: "], start=1):
716 self.append_info_to_box(selected, prop,
717 self.specific_vuln_info)
718
719 def append_info_to_box(self, selected, prop, box):
720 """Gets selected and prop and creates a label and appends
721 them to the box parameter.
722 """
723 prop_box = Gtk.Box()
724 prop_label = Gtk.Label()
725 prop_label.set_markup("<b> %s </b>" % (prop[1]))
726 prop_label.set_selectable(True)
727 value_label = Gtk.Label(selected[prop[0]])
728 value_label.set_selectable(True)
729 prop_box.pack_start(prop_label, False, False, 0)
730 prop_box.pack_start(value_label, False, False, 0)
731 box.pack_start(prop_box, True, True, 0)
732 box.show_all()
733
734 def reset_info(self, widget):
735 """Removes a widget from self.specific_info. Used to clear all
736 the information before displaying new"""
737 self.specific_info.remove(widget)
738
739 def reset_vuln_info(self, widget):
740 """Removes a widget from self.specific_vuln_info. Used to clear
741 all the information before displaying new"""
742 self.specific_vuln_info.remove(widget)
743
744 def on_click_ok(self, button):
745 self.destroy()
746
747
396748 class ConflictsDialog(Gtk.Window):
397749 """Blueprints for a beautiful, colorful, gtk-esque conflicts
398750 dialog. The user is confronted with two objects, one at the left,
408760 self.set_transient_for(parent)
409761 self.set_size_request(600, 400)
410762 self.set_modal(True)
411 self.connect("key_press_event", on_scape)
763 self.connect("key_press_event", on_scape_destroy)
412764 self.conflicts = conflicts
413765 self.conflict_n = 0
414766 self.current_conflict = self.conflicts[self.conflict_n]
493845 else:
494846 self.destroy()
495847
496 except ValueError as e:
848 except ValueError:
497849 dialog = Gtk.MessageDialog(self, 0,
498850 Gtk.MessageType.INFO,
499851 Gtk.ButtonsType.OK,
569921 self.view.append_column(obj_column)
570922 self.second_view = Gtk.TreeView(self.models[conflict_n])
571923
572
573924 self.second_view.append_column(prop2_column)
574925 self.second_view.append_column(obj2_column)
575926
576 self.views_box.pack_start(self.view, True, True, 5)
577 self.views_box.pack_start(self.second_view, True, True, 5)
927 scrolled_view = Gtk.ScrolledWindow(None, None)
928 second_scrolled_view = Gtk.ScrolledWindow(None, None)
929 scrolled_view.add(self.view)
930 second_scrolled_view.add(self.second_view)
931
932 self.views_box.pack_start(scrolled_view, True, True, 5)
933 self.views_box.pack_start(second_scrolled_view, True, True, 5)
578934
579935 else:
580936 self.view.set_model(self.models[conflict_n])
8531209 self.set_transient_for(parent)
8541210 self.set_size_request(400, 200)
8551211 self.set_modal(True)
856 self.connect("key_press_event", on_scape)
1212 self.connect("key_press_event", on_scape_destroy)
8571213
8581214 self.view = view
8591215 self.destroy_notifications = callback
9311287
9321288
9331289 class ImportantErrorDialog(Gtk.Dialog):
1290 """Blueprints for an uncaught exception handler. Presents the
1291 traceback and has option to send error report to developers.
1292 """
9341293
9351294 def __init__(self, parent_window, error):
9361295 Gtk.Dialog.__init__(self, "Error!", parent_window, 0)
9541313 box.pack_start(scrolled_text, True, True, 0)
9551314 self.show_all()
9561315
957 def on_scape(window, event):
1316
1317 def on_scape_destroy(window, event):
9581318 """Silly function to destroy a window on escape key, to use
9591319 with all the dialogs that should be Gtk.Dialogs but are Gtk.Windows
9601320 or with windows that are too complex for gtk dialogs but should behave
1212 gi.require_version('Gtk', '3.0')
1313 gi.require_version('Vte', '2.91')
1414
15 from gi.repository import Gtk, Vte, GLib, Pango
15 from gi.repository import Gtk, Gdk, Vte, GLib, Pango, GdkPixbuf
1616
1717
1818 class Terminal(Vte.Terminal):
2020 corresponding host and port as specified by the CONF"""
2121 def __init__(self, CONF):
2222 super(Vte.Terminal, self).__init__()
23
24 self.pty = self.pty_new_sync(Vte.PtyFlags.DEFAULT, None)
25 self.set_pty(self.pty)
26
2723 self.set_scrollback_lines(-1)
2824 self.set_audible_bell(0)
29
30 self.faraday_directory = os.path.dirname(os.path.realpath(sys.argv[0]))
25 self.connect("key_press_event", self.copy_or_paste)
3126 self.host, self.port = CONF.getApiRestfulConInfo()
32 self.faraday_exec = self.faraday_directory + "/faraday-terminal.zsh"
27
28 faraday_directory = os.path.dirname(os.path.realpath('faraday.py'))
29 self.faraday_exec = faraday_directory + "/faraday-terminal.zsh"
3330
3431 self.startFaraday()
3532
5249 None,
5350 None)
5451
55
56 class Sidebar(Gtk.Widget):
52 def copy_or_paste(self, widget, event):
53 """Decides if the Ctrl+Shift is pressed, in which case returns True.
54 If Ctrl+Shift+C or Ctrl+Shift+V are pressed, copies or pastes,
55 acordingly. Return necesary so it doesn't perform other action,
56 like killing the process, on Ctrl+C.
57 """
58
59 control_key = Gdk.ModifierType.CONTROL_MASK
60 shift_key = Gdk.ModifierType.SHIFT_MASK
61 if event.type == Gdk.EventType.KEY_PRESS:
62 if event.state == shift_key | control_key: #both shift and control
63 if event.keyval == 67: # that's the C key
64 self.copy_clipboard()
65 elif event.keyval == 86: # and that's the V key
66 self.paste_clipboard()
67 return True
68
69 class Sidebar(Gtk.Notebook):
70 """Defines the bigger sidebar in a notebook. One of its tabs will contain
71 the workspace view, listing all the workspaces (WorkspaceSidebar) and the
72 other will contain the information about hosts, services, and vulns
73 (HostsSidebar)
74 """
75
76 def __init__(self, workspace_sidebar, hosts_sidebar):
77 """Attach to the notebok the workspace sidebar and the host_sidebar"""
78 super(Gtk.Notebook, self).__init__()
79 self.workspace_sidebar = workspace_sidebar
80 self.hosts_sidebar = hosts_sidebar
81 self.set_tab_pos(Gtk.PositionType.BOTTOM)
82
83 self.append_page(self.workspace_sidebar, Gtk.Label("Workspaces"))
84 self.append_page(self.hosts_sidebar, Gtk.Label("Hosts"))
85
86 def get_box(self):
87 box = Gtk.Box()
88 box.pack_start(self, True, True, 0)
89 return box
90
91 class HostsSidebar(Gtk.Widget):
92 """Defines the widget displayed when the user is in the "Hosts" tab of
93 the Sidebar notebook. Will list all the host, and when clicking on one,
94 will open a window with more information about it"""
95
96 def __init__(self, open_dialog_callback, icons):
97 """Initializes the HostsSidebar. Initialization by itself does
98 almost nothing, the application will inmediatly call create_model
99 with the last workspace and create_view with that model upon startup.
100 """
101
102 super(Gtk.Widget, self).__init__()
103 self.open_dialog_callback = open_dialog_callback
104 self.current_model = None
105 self.linux_icon = icons + "tux.png"
106 self.windows_icon = icons + "windows.png"
107 self.mac_icon = icons + "Apple.png"
108
109 def create_model(self, hosts):
110 """Creates a model for a lists of hosts. The model contians the
111 host_id in the first column, the icon as a GdkPixbuf.Pixbuf()
112 in the second column and a display_str with the host_name and the
113 vulnerability count on the third column, like this:
114 | HOST_ID | HOST_OS_PIXBUF | DISPLAY_STR |
115 =================================================
116 | a923fd | LINUX_ICON | 192.168.1.2 (5) |
117 """
118 def compute_vuln_count(host):
119 """Returns the total vulnerability count for a given host"""
120 vuln_count = 0
121 vuln_count += len(host.getVulns())
122 for interface in host.getAllInterfaces():
123 vuln_count += len(interface.getVulns())
124 for service in interface.getAllServices():
125 vuln_count += len(service.getVulns())
126 return str(vuln_count)
127
128 def decide_icon(os):
129 """Decides the correct Pixbuf icon for a OS. None if OS not
130 found or not recognized.
131 """
132 os = os.lower()
133 if "linux" in os or "unix" in os:
134 icon = GdkPixbuf.Pixbuf.new_from_file(self.linux_icon)
135 elif "windows" in os:
136 icon = GdkPixbuf.Pixbuf.new_from_file(self.windows_icon)
137 elif "mac" in os:
138 icon = GdkPixbuf.Pixbuf.new_from_file(self.mac_icon)
139 else:
140 icon = None
141 return icon
142
143 hosts_model = Gtk.ListStore(str, GdkPixbuf.Pixbuf(), str)
144 for host in hosts:
145 vuln_count = compute_vuln_count(host)
146 display_str = host.name + " (" + vuln_count + ")"
147 os = host.getOS()
148 hosts_model.append([host.id, decide_icon(os), display_str])
149 self.current_model = hosts_model
150 return hosts_model
151
152 def create_view(self, model):
153 """Creates a view displaying the third column of the given model as
154 a text, and using an icon representing its second column.
155 Will connect activation of a row with the on_click method
156 """
157
158 def display_str(col, cell, model, _iter, user_data):
159 cell.set_property('text', model.get_value(_iter, 2))
160
161 def set_icon(col, cell, model, _iter, user_data):
162 icon = model.get_value(_iter, 1)
163 if icon != "None":
164 cell.set_property('pixbuf',
165 GdkPixbuf.Pixbuf.new_from_file(icon))
166
167 self.view = Gtk.TreeView(model)
168 self.view.set_activate_on_single_click(True)
169
170 text_renderer = Gtk.CellRendererText()
171 icon_renderer = Gtk.CellRendererPixbuf()
172
173 column_hosts = Gtk.TreeViewColumn("Hosts", text_renderer, text=2)
174 column_os = Gtk.TreeViewColumn("", icon_renderer, pixbuf=1)
175
176 self.view.append_column(column_os)
177 self.view.append_column(column_hosts)
178
179 self.view.connect("row_activated", self.on_click)
180
181 self.view.set_enable_search(True)
182 self.view.set_search_column(2)
183
184 return self.view
185
186 def update(self, hosts):
187 """Creates a new model from an updated list of hosts and adapts
188 the view to reflect the changes"""
189 model = self.create_model(hosts)
190 self.update_view(model)
191
192 def update_view(self, model):
193 """Updates the view of the object with a new model"""
194 self.view.set_model(model)
195
196 def on_click(self, tree_view, path, column):
197 """Sends the host_id of the clicked host back to the application"""
198 tree_iter = self.current_model.get_iter(path)
199 host_id = self.current_model[tree_iter][0]
200 self.open_dialog_callback(host_id)
201
202 def get_box(self):
203 """Returns the box to be displayed in the appwindow"""
204 box = Gtk.Box()
205 scrolled_view = Gtk.ScrolledWindow(None, None)
206 scrolled_view.add(self.view)
207 box.pack_start(scrolled_view, True, True, 0)
208 return box
209
210 class WorkspaceSidebar(Gtk.Widget):
57211 """Defines the sidebar widget to be used by the AppWindow, passed as an
58 instance to itby the application. It only handles the view and the model,
212 instance to the application. It only handles the view and the model,
59213 all the backend word is handled by the application via the callback"""
60214
61215 def __init__(self, workspace_manager, callback_to_change_workspace,
82236 self.scrollableView.set_min_content_width(160)
83237 self.scrollableView.add(self.workspace_view)
84238
239 def get_box(self):
240 box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
241 box.pack_start(self.getSearchEntry(), False, False, 0)
242 box.pack_start(self.getScrollableView(), True, True, 0)
243 box.pack_start(self.getButton(), False, False, 0)
244 return box
245
85246 def createSearchEntry(self):
86247 """Returns a simple search entry"""
87248 searchEntry = Gtk.Entry()
92253 def getSearchEntry(self):
93254 """Returns the search entry of the sidebar"""
94255 return self.searchEntry
256
257 def getScrollableView(self):
258 return self.scrollableView
95259
96260 def onSearchEnterKey(self, entry):
97261 """When the users preses enter, if the workspace exists,
102266 self.callbackCreateWs(title=entry.get_text())
103267 entry.set_text("")
104268 else:
105 self.callbackChangeWs(selection)
269 self.callbackChangeWs(self.getSelectedWsName())
106270 ws_iter = self.getSelectedWsIter()
107271 entry.set_text("")
108272 self.selectWs(ws_iter)
187351 select.select_path(path)
188352
189353 # change the workspace to the newly selected
190 self.callbackChangeWs(self.getSelectedWs())
354
355 self.callbackChangeWs(self.getSelectedWsName())
191356
192357 if event.button == 3: # 3 represents right click
193358 menu = Gtk.Menu()
194359 delete_item = Gtk.MenuItem("Delete")
195360 menu.append(delete_item)
196361
197 # get the path of the item where the user clicked
198 # then get its tree_iter. then get its name. then delete
362 # get tree_iter from path. then get its name. then delete
199363 # that workspace
200364
201365 tree_iter = self.workspace_model.get_iter(path)
207371 menu.popup(None, None, None, None, event.button, event.time)
208372 return True # prevents the click from selecting a workspace
209373
374 def change_label(self, new_label):
375 self.sidebar_button.set_label(new_label)
376
377 def restore_label(self):
378 self.sidebar_button.set_label("Refresh workspaces")
379
210380 def addWorkspace(self, ws):
211381 """Append ws workspace to the model"""
212382 self.workspace_model.append([ws])
213383
214384 def getSelectedWs(self):
215 """Returns the name of the current selected workspace"""
385 """Returns the selection of of the view.
386 To retrieve the name, see getSelectedWsName"""
216387 selection = self.workspace_view.get_selection()
217388 return selection
218389
221392 selection = self.getSelectedWs()
222393 _iter = selection.get_selected()[1]
223394 return _iter
395
396 def getSelectedWsName(self):
397 """Return the name of the selected workspace"""
398 selection = self.getSelectedWs()
399 tree_model, treeiter = selection.get_selected()
400 workspaceName = tree_model[treeiter][0]
401 return workspaceName
224402
225403 def selectWs(self, ws):
226404 """Selects workspace ws in the list"""
283461 return self.textBuffer
284462
285463 def customEvent(self, text):
286 """Filters event so that only those with type 3131 get to the log"""
464 """Filters event so that only those with type 3131 get to the log.
465 Also split them, so we can add the correct formatting to the first
466 part of the message"""
467
287468 text = text.split('-')
288469 if text[0] == "INFO ":
289470 self.update("[ " + text[0] + "]", self.bold)
345526 self.notif_button = Gtk.Button.new()
346527 self.set_default_notif_label()
347528 self.notif_button.connect("clicked", notif_callback)
529 self.notif_button.connect("clicked", self.set_default_notif_label)
348530
349531 self.conflict_button = Gtk.Button.new()
350532 self.set_default_conflict_label()
379561 label.show()
380562 self.conflict_button.add(label)
381563
382 def set_default_notif_label(self):
564 def set_default_notif_label(self, button=None):
383565 """Creates the default label"""
384566 self.notif_button_label_int = 0
385567 self.notif_button.set_label(self.notif_text +
4141
4242 #Check if python2 is already installed
4343 if ! which python2 > /dev/null; then
44 echo "[-] Please install Python2 or make sure it is in your path"
45 exit 1
44 if ! which python2.7 > /dev/null; then
45 echo "[-] Please install Python2 or make sure it is in your path"
46 exit 1
47 fi
4648 fi
4749
4850 echo "[+] Install $os $arch"
4343 )
4444 return False
4545
46 return self._sendReport(parser.report_type, filename)
47
48 def _sendReport(self, plugin_id, filename):
46 return self.sendReport(parser.report_type, filename)
47
48 def sendReport(self, plugin_id, filename):
49 """Sends a report to the appropiate plugin specified by plugin_id"""
4950 getLogger(self).debug(
5051 'The file is %s, %s' % (filename, plugin_id))
5152 if not self.plugin_controller.processReport(plugin_id, filename):
140141 if name in psettings:
141142 if psettings[name]['settings']['Enable'] == "1":
142143 self.processor.onlinePlugin(cmd)
144
145 def sendReportToPluginById(self, plugin_id, filename):
146 """Sends a report to be processed by the specified plugin_id"""
147 self.processor.sendReport(plugin_id, filename)
143148
144149
145150 class ReportParser(object):
106106 headers = headers,
107107 data = params, timeout = 1, verify=True)
108108
109 model.api.devlog("Report sent it to faraday server")
109 model.api.devlog("Report sent to faraday server")
110110
111111 except Exception as e:
112112 model.api.devlog("Error reporting to developers:")