class PluginConfig(object): BOOL = 'boolean' STR = 'string' LIST = 'list' INT = 'integer' URL = 'url' INPUT_FILE = 'input_file' def __init__(self, name, *opts): self._name = name self._options = OptionList() for optname, optval, optty in opts: self._options.append(opt_factory(optname, str(optval), '', optty)) @property def name(self): return self._name @property def options(self): return self._options
class OnlyOptions(gtk.VBox): '''Only the options for configuration. :param parentwidg: The parentwidg, to propagate changes :param plugin: The selected plugin, for which the configuration is. :param options: The options to configure. :param save_btn: The save button. :param rvrt_btn: The revert button. :author: Facundo Batista <facundobatista =at= taniquetil.com.ar> ''' def __init__(self, parentwidg, w3af, plugin, save_btn, rvrt_btn, overwriter=None): super(OnlyOptions, self).__init__() if overwriter is None: overwriter = {} self.set_spacing(5) self.w3af = w3af self.parentwidg = parentwidg self.widgets_status = {} self.tab_widget = {} self.propagAnyWidgetChanged = helpers.PropagateBuffer( self._changedAnyWidget) self.propagLabels = {} self.saved_successfully = False # options self.options = OptionList() options = plugin.get_options() # let's use the info from the core coreopts = self.w3af.plugins.get_plugin_options( plugin.ptype, plugin.pname) if coreopts is None: coreopts = {} # let's get the real info for opt in options: if opt.get_name() in coreopts: opt.set_value(coreopts[opt.get_name()].get_value_str()) if opt.get_name() in overwriter: opt.set_value(overwriter[opt.get_name()]) self.options.append(opt) # buttons save_btn.connect("clicked", self._save_panel, plugin) save_btn.set_sensitive(False) rvrt_btn.set_sensitive(False) rvrt_btn.connect("clicked", self._revertPanel) self.save_btn = save_btn self.rvrt_btn = rvrt_btn # middle (the heart of the panel) if self.options: tabbox = gtk.HBox() heart = self._createNotebook() tabbox.pack_start(heart, expand=True) tabbox.show() self.pack_start(tabbox, expand=True, fill=False) self.show() def _createNotebook(self): '''This create the notebook with all the options. :return: The created notebook if more than one grouping ''' # let's get the tabs, but in order! tabs = [] for o in self.options: t = o.get_tabid() if t not in tabs: tabs.append(t) # see if we have more than a tab to create a nb if len(tabs) < 2: table = self._makeTable(self.options, None) return table # the notebook nb = gtk.Notebook() for tab in tabs: options = [x for x in self.options if x.get_tabid() == tab] if not tab: tab = "General" label = gtk.Label(tab) prop = helpers.PropagateBufferPayload(self._changedLabelNotebook, label, tab) table = self._makeTable(options, prop) nb.append_page(table, label) nb.show() return nb def _makeTable(self, options, prop): '''Creates the table in which the options are shown. :param options: The options to show :param prop: The propagation function for this options :return: The created table For each row, it will put: - the option label - the configurable widget (textentry, checkbox, etc.) - an optional button to get more help (if the help is available) Also, the configurable widget gets a tooltip for a small description. ''' table = entries.EasyTable(len(options), 3) for _, opt in enumerate(options): titl = gtk.Label(opt.get_name()) titl.set_alignment(0.0, 0.5) input_widget_klass = entries.wrapperWidgets.get(opt.get_type(), entries.TextInput) widg = input_widget_klass(self._changedWidget, opt) opt.widg = widg widg.set_tooltip_text(opt.get_desc()) if opt.get_help(): helpbtn = entries.SemiStockButton("", gtk.STOCK_INFO) cleanhelp = helpers.clean_description(opt.get_help()) helpbtn.connect("clicked", self._showHelp, cleanhelp) else: helpbtn = None table.auto_add_row(titl, widg, helpbtn) self.widgets_status[widg] = (titl, opt.get_name(), "<b>%s</b>" % opt.get_name()) self.propagLabels[widg] = prop table.show() return table def _changedAnyWidget(self, like_initial): '''Adjust the save/revert buttons and alert the tree of the change. :param like_initial: if the widgets are modified or not. It only will be called if any widget changed its state, through a propagation buffer. ''' self.save_btn.set_sensitive(not like_initial) self.rvrt_btn.set_sensitive(not like_initial) self.parentwidg.config_changed(like_initial) def _changedLabelNotebook(self, like_initial, label, text): if like_initial: label.set_text(text) else: label.set_markup("<b>%s</b>" % text) def _changedWidget(self, widg, like_initial): '''Receives signal when a widget changed or not. :param widg: the widget who changed. :param like_initial: if it's modified or not Handles the boldness of the option label and then propagates the change. ''' (labl, orig, chng) = self.widgets_status[widg] if like_initial: labl.set_text(orig) else: labl.set_markup(chng) self.propagAnyWidgetChanged.change(widg, like_initial) propag = self.propagLabels[widg] if propag is not None: propag.change(widg, like_initial) def _showHelp(self, widg, helpmsg): '''Shows a dialog with the help message of the config option. :param widg: the widget who generated the signal :param helpmsg: the message to show in the dialog ''' dlg = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, helpmsg) dlg.set_title('Configuration help') dlg.run() dlg.destroy() def _save_panel(self, widg, plugin): '''Saves the config changes to the plugins. :param widg: the widget who generated the signal :param plugin: the plugin to save the configuration First it checks if there's some invalid configuration, then gets the value of each option and save them to the plugin. ''' # check if all widgets are valid invalid = [] for opt in self.options: if hasattr(opt.widg, "is_valid"): if not opt.widg.is_valid(): invalid.append(opt.get_name()) if invalid: msg = "The configuration can't be saved, there is a problem in the"\ " following parameter(s):\n\n" msg += "\n-".join(invalid) dlg = gtk.MessageDialog( None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, msg) dlg.set_title('Configuration error') dlg.run() dlg.destroy() return try: # Get the value from the GTK widget and set it to the option object for opt in self.options: SetOptionsWrapper(opt.set_value, opt.widg.get_value()) if isinstance(plugin, Plugin): SetOptionsWrapper(self.w3af.plugins.set_plugin_options, plugin.ptype, plugin.pname, self.options) else: SetOptionsWrapper(plugin.set_options, self.options) except (w3afException, ValueError): return for opt in self.options: opt.widg.save() # Tell the profile tree that something changed self.w3af.mainwin.profiles.profile_changed(changed=True) # Status bar self.w3af.mainwin.sb("Configuration saved successfully") self.saved_successfully = True def _revertPanel(self, *vals): '''Revert all widgets to their initial state.''' for widg in self.widgets_status: widg.revert_value() msg = "The plugin configuration was reverted to its last saved state" self.w3af.mainwin.sb(msg)
class OnlyOptions(gtk.VBox): '''Only the options for configuration. :param parentwidg: The parentwidg, to propagate changes :param plugin: The selected plugin, for which the configuration is. :param options: The options to configure. :param save_btn: The save button. :param rvrt_btn: The revert button. :author: Facundo Batista <facundobatista =at= taniquetil.com.ar> ''' def __init__(self, parentwidg, w3af, plugin, save_btn, rvrt_btn, overwriter=None): super(OnlyOptions, self).__init__() if overwriter is None: overwriter = {} self.set_spacing(5) self.w3af = w3af self.parentwidg = parentwidg self.widgets_status = {} self.tab_widget = {} self.propagAnyWidgetChanged = helpers.PropagateBuffer( self._changedAnyWidget) self.propagLabels = {} self.saved_successfully = False # options self.options = OptionList() options = plugin.get_options() # let's use the info from the core coreopts = self.w3af.plugins.get_plugin_options( plugin.ptype, plugin.pname) if coreopts is None: coreopts = {} # let's get the real info for opt in options: if opt.get_name() in coreopts: opt.set_value(coreopts[opt.get_name()].get_value_str()) if opt.get_name() in overwriter: opt.set_value(overwriter[opt.get_name()]) self.options.append(opt) # buttons save_btn.connect("clicked", self._save_panel, plugin) save_btn.set_sensitive(False) rvrt_btn.set_sensitive(False) rvrt_btn.connect("clicked", self._revertPanel) self.save_btn = save_btn self.rvrt_btn = rvrt_btn # middle (the heart of the panel) if self.options: tabbox = gtk.HBox() heart = self._createNotebook() tabbox.pack_start(heart, expand=True) tabbox.show() self.pack_start(tabbox, expand=True, fill=False) self.show() def _createNotebook(self): '''This create the notebook with all the options. :return: The created notebook if more than one grouping ''' # let's get the tabs, but in order! tabs = [] for o in self.options: t = o.get_tabid() if t not in tabs: tabs.append(t) # see if we have more than a tab to create a nb if len(tabs) < 2: table = self._makeTable(self.options, None) return table # the notebook nb = gtk.Notebook() for tab in tabs: options = [x for x in self.options if x.get_tabid() == tab] if not tab: tab = "General" label = gtk.Label(tab) prop = helpers.PropagateBufferPayload(self._changedLabelNotebook, label, tab) table = self._makeTable(options, prop) nb.append_page(table, label) nb.show() return nb def _makeTable(self, options, prop): '''Creates the table in which the options are shown. :param options: The options to show :param prop: The propagation function for this options :return: The created table For each row, it will put: - the option label - the configurable widget (textentry, checkbox, etc.) - an optional button to get more help (if the help is available) Also, the configurable widget gets a tooltip for a small description. ''' table = entries.EasyTable(len(options), 3) for _, opt in enumerate(options): titl = gtk.Label(opt.get_name()) titl.set_alignment(0.0, 0.5) input_widget_klass = entries.wrapperWidgets.get( opt.get_type(), entries.TextInput) widg = input_widget_klass(self._changedWidget, opt) opt.widg = widg widg.set_tooltip_text(opt.get_desc()) if opt.get_help(): helpbtn = entries.SemiStockButton("", gtk.STOCK_INFO) cleanhelp = helpers.clean_description(opt.get_help()) helpbtn.connect("clicked", self._showHelp, cleanhelp) else: helpbtn = None table.auto_add_row(titl, widg, helpbtn) self.widgets_status[widg] = (titl, opt.get_name(), "<b>%s</b>" % opt.get_name()) self.propagLabels[widg] = prop table.show() return table def _changedAnyWidget(self, like_initial): '''Adjust the save/revert buttons and alert the tree of the change. :param like_initial: if the widgets are modified or not. It only will be called if any widget changed its state, through a propagation buffer. ''' self.save_btn.set_sensitive(not like_initial) self.rvrt_btn.set_sensitive(not like_initial) self.parentwidg.config_changed(like_initial) def _changedLabelNotebook(self, like_initial, label, text): if like_initial: label.set_text(text) else: label.set_markup("<b>%s</b>" % text) def _changedWidget(self, widg, like_initial): '''Receives signal when a widget changed or not. :param widg: the widget who changed. :param like_initial: if it's modified or not Handles the boldness of the option label and then propagates the change. ''' (labl, orig, chng) = self.widgets_status[widg] if like_initial: labl.set_text(orig) else: labl.set_markup(chng) self.propagAnyWidgetChanged.change(widg, like_initial) propag = self.propagLabels[widg] if propag is not None: propag.change(widg, like_initial) def _showHelp(self, widg, helpmsg): '''Shows a dialog with the help message of the config option. :param widg: the widget who generated the signal :param helpmsg: the message to show in the dialog ''' dlg = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, helpmsg) dlg.set_title('Configuration help') dlg.run() dlg.destroy() def _save_panel(self, widg, plugin): '''Saves the config changes to the plugins. :param widg: the widget who generated the signal :param plugin: the plugin to save the configuration First it checks if there's some invalid configuration, then gets the value of each option and save them to the plugin. ''' # check if all widgets are valid invalid = [] for opt in self.options: if hasattr(opt.widg, "is_valid"): if not opt.widg.is_valid(): invalid.append(opt.get_name()) if invalid: msg = "The configuration can't be saved, there is a problem in the"\ " following parameter(s):\n\n" msg += "\n-".join(invalid) dlg = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, msg) dlg.set_title('Configuration error') dlg.run() dlg.destroy() return try: # Get the value from the GTK widget and set it to the option object for opt in self.options: SetOptionsWrapper(opt.set_value, opt.widg.get_value()) if isinstance(plugin, Plugin): SetOptionsWrapper(self.w3af.plugins.set_plugin_options, plugin.ptype, plugin.pname, self.options) else: SetOptionsWrapper(plugin.set_options, self.options) except (w3afException, ValueError): return for opt in self.options: opt.widg.save() # Tell the profile tree that something changed self.w3af.mainwin.profiles.profile_changed(changed=True) # Status bar self.w3af.mainwin.sb("Configuration saved successfully") self.saved_successfully = True def _revertPanel(self, *vals): '''Revert all widgets to their initial state.''' for widg in self.widgets_status: widg.revert_value() msg = "The plugin configuration was reverted to its last saved state" self.w3af.mainwin.sb(msg)