예제 #1
0
class ChildDialogExportSelection:
    """
    Open a child dialog of a tkinter application to ask the user to select fields between many.
    """
    def __init__(self, parent, keys):
        """
        Open a child dialog of a tkinter application to ask details about
        an export of treeview items.

        Args:
            parent: the tkinter parent view to use for this window construction.
            keys: The keys to export
        """
        self.rvalue = None
        self.parent = parent
        self.app = tk.Toplevel(parent)
        self.app.title("Export selection")
        appFrame = ttk.Frame(self.app)
        self.form = FormPanel()
        self.form.addFormChecklist("Fields", sorted(keys), [])
        self.form.addFormButton("Export", self.onOk)
        self.rvalue = None
        self.form.constructView(appFrame)
        appFrame.pack(ipadx=10, ipady=10)
        try:
            self.app.wait_visibility()
            self.app.transient(parent)
            self.app.focus_force()
            self.app.grab_set()
            self.app.lift()
        except tk.TclError:
            pass

    def onOk(self, _event=None):
        """Called the the Export button is pressed.
        return a list of strings corresponding to the selected fields.
        
        Args:
            _event: not used but mandatory"""
        res, msg = self.form.checkForm()
        if res:
            form_values = self.form.getValue()
            form_values_as_dicts = ViewElement.list_tuple_to_dict(form_values)
            mfields = form_values_as_dicts["Fields"]
            fields = [k for k, v in mfields.items() if v == 1]
            self.rvalue = fields
            self.app.destroy()
        else:
            tk.messagebox.showwarning("Form not validated",
                                      msg,
                                      parent=self.app)
class ChildDialogEditCommandSettings:
    """
    Open a child dialog of a tkinter application to fill settings for a command
    """

    def __init__(self, parent, displayMsg="Choose a database to open:", default=None):
        """
        Open a child dialog of a tkinter application to ask a combobox option.

        Args:
            parent: the tkinter parent view to use for this window construction.
            options: A list of string correspondig to options of the combobox
            displayMsg: The message that will explain to the user what he is choosing.
            default: Choose a default selected option (one of the string in options). default is None
        """
        self.app = tk.Toplevel(parent)
        self.app.title("Upload result file")
        self.rvalue = None
        self.parent = parent
        appFrame = ttk.Frame(self.app)
        self.form = FormPanel()
        self.form.addFormLabel(displayMsg, side=tk.TOP)
        optionsFrame = self.form.addFormPanel(grid=True)
        optionsFrame.addFormLabel("Remote bin path", row=0, column=0)
        optionsFrame.addFormStr("bin", r".+", row=0, column=1)
        optionsFrame.addFormLabel("Plugin", row=1, column=0)
        apiclient = APIClient.getInstance()
        optionsFrame.addFormCombo("plugin", tuple(apiclient.getPlugins()), row=1, column=1)
        self.form.addFormButton("Cancel", self.onError)
        self.form.addFormButton("OK", self.onOk)
        self.form.constructView(appFrame)
        appFrame.pack(ipadx=10, ipady=10)
        try:
            self.app.wait_visibility()
            self.app.transient(parent)
            self.app.focus_force()
            self.app.grab_set()
            self.app.lift()
        except tk.TclError:
            pass

    def onOk(self, _event):
        """
        Called when the user clicked the validation button. Set the rvalue attributes to the value selected and close the window.
        """
        # send the data to the parent
        res, msg = self.form.checkForm()
        if not res:
            tk.messagebox.showwarning(
                "Form not validated", msg, parent=self.app)
            return
        form_values = self.form.getValue()
        form_values_as_dicts = ViewElement.list_tuple_to_dict(form_values)
        self.rvalue = (form_values_as_dicts["bin"], form_values_as_dicts["plugin"])
        self.app.destroy()

    def onError(self, _event=None):
        """
        Close the dialog and set rvalue to None
        """
        self.rvalue = None
        self.app.destroy()
예제 #3
0
class Settings:
    """
    Represents the settings of pollenisator.
    There are three level of settings:
        * local settings: stored in a file under ../../config/settings.cfg
        * pentest db settings: stored in the pentest database under settings collection
        * global settings: stored in the pollenisator database under settings collection
    """
    tags_cache = None
    __pentest_types = None

    def __init__(self):
        """
        Load the tree types of settings and stores them in dictionnaries
        """
        dir_path = os.path.dirname(os.path.realpath(__file__))
        self.confdir = os.path.join(dir_path, "../../config/settings.cfg")

        self.local_settings = {}
        try:
            with open(self.confdir, "r") as f:
                self.local_settings = json.loads(f.read())
        except json.JSONDecodeError:
            self.local_settings = {}
        except IOError:
            self.local_settings = {}
        self.db_settings = {}
        self.global_settings = {}
        self.text_pentest_types = None
        self.text_tags = None
        self.text_db_tags = None
        self.box_pentest_type = None
        self.visual_include_domains_with_ip_in_scope = None
        self.visual_include_domains_with_topdomain_in_scope = None
        self.visual_search_show_hidden = None
        self.visual_search_exact_match = None
        self.visual_include_all_domains = None
        #self.text_pentesters = None
        self.box_favorite_term = None
        self.text_terms = None
        self.visual_trap_commands = None
        self.pentesters_treevw = None

    @classmethod
    def getPentestTags(cls):
        apiclient = APIClient.getInstance()
        db_tags = apiclient.find("settings", {"key": "tags"}, False)
        if db_tags is None:
            db_tags = {}
        else:
            db_tags = db_tags["value"]
        return db_tags

    @classmethod
    def getTags(cls, onlyGlobal=False, **kwargs):
        """
        Returns tags defined in settings.
        Returns:
            If none are defined returns {"todo":"orange", "pwned":"red", "Interesting":"dark green", "Uninteresting":"sky blue", "neutral":"white"}
            otherwise returns a dict with defined key values
        """
        apiclient = APIClient.getInstance()
        if kwargs.get("ignoreCache", False):  #Check if ignore cache is true
            cls.tags_cache = None
        if cls.tags_cache is not None and not onlyGlobal:
            return cls.tags_cache
        cls.tags_cache = {
            "todo": "orange",
            "pwned": "red",
            "Interesting": "dark green",
            "Uninteresting": "sky blue",
            "neutral": "white"
        }
        try:
            global_tags = apiclient.getSettings({"key": "tags"})
        except ErrorHTTP:
            global_tags = None
        if global_tags is not None:
            if isinstance(global_tags["value"], dict):
                global_tags = global_tags["value"]
            elif isinstance(global_tags["value"], str):
                global_tags = json.loads(global_tags["value"])
        if global_tags is None:
            global_tags = {}
        if not onlyGlobal:
            try:
                db_tags = cls.getPentestTags()
            except ErrorHTTP:
                db_tags = {}
            cls.tags_cache = {**global_tags, **db_tags}
            return cls.tags_cache
        return global_tags

    @classmethod
    def getPentestTypes(cls):
        """
        Returns pentest types and associeted defect type defined in settings.
        Returns:
            If none are defined returns {"Web":["Base", "Application", "Data", "Policy"], "LAN":["Infrastructure", "Active Directory", "Data", "Policy"]}
            otherwise returns a dict with defined key values
        """
        apiclient = APIClient.getInstance()
        if cls.__pentest_types is None:
            pentest_types = apiclient.getSettings({"key": "pentest_types"})
            if pentest_types is not None:
                if isinstance(pentest_types["value"], str):
                    cls.__pentest_types = json.loads(pentest_types["value"])
                elif isinstance(pentest_types["value"], dict):
                    cls.__pentest_types = pentest_types["value"]
                else:
                    cls.__pentest_types = {
                        "Web": ["Base", "Application", "Data", "Policy"],
                        "LAN": [
                            "Infrastructure", "Active Directory", "Data",
                            "Policy"
                        ]
                    }
            else:
                cls.__pentest_types = {
                    "Web": ["Base", "Application", "Data", "Policy"],
                    "LAN":
                    ["Infrastructure", "Active Directory", "Data", "Policy"]
                }
        return cls.__pentest_types

    def getTerms(self):
        """
        Returns terminals configured with a command execution option
        Returns:
            If none are defined returns ['''gnome-terminal --window --''',
             '''xfce4-terminal -x'',
             '''xterm -hold -e''',
             '''konsole --noclose -e''']
            otherwise returns a list with defined  values
        """
        self._reloadLocalSettings()
        return self.local_settings.get("terms", [
            """gnome-terminal --window --""", """xfce4-terminal -x""",
            "xterm -e", "konsole --noclose -e"
        ])

    def getFavoriteTerm(self):
        """
        Returns favorite terminal configured 
        Returns:
            If none are defined returns first in the list of terms
            Otherwise returns the favorite terminal configured 
        """
        self._reloadLocalSettings()
        fav = self.local_settings.get("fav_term", None)
        if fav is None:
            terms = self.getTerms()
            for term in terms:
                term_name = term.split(" ")[0].strip()
                if which(term_name):
                    fav = term_name
        return fav

    def isTrapCommand(self):
        self._reloadLocalSettings()
        return self.local_settings.get("trap_commands", False)

    def setTrapCommand(self):
        self._reloadLocalSettings()
        self.local_settings["trap_commands"] = self.visual_trap_commands.get()
        self.saveLocalSettings()

    def setFavoriteTerm(self):
        """
        Change favorite term 
        """
        self._reloadLocalSettings()
        self.local_settings["fav_term"] = self.box_favorite_term.get()
        self.saveLocalSettings()

    def _reloadLocalSettings(self):
        """
        Reload local settings from local conf file
        """
        try:
            with open(self.confdir, "r") as f:
                self.local_settings = json.loads(f.read())
        except json.JSONDecodeError:
            self.local_settings = {}
        except IOError:
            self.local_settings = {}

    def _reloadDbSettings(self):
        """
        Reload pentest database settings from pentest database
        """
        apiclient = APIClient.getInstance()
        dbSettings = apiclient.find("settings", {})
        if dbSettings is None:
            dbSettings = {}
        self.__class__.tags_cache = None
        for settings_dict in dbSettings:
            try:
                self.db_settings[settings_dict["key"]] = settings_dict["value"]
            except KeyError:
                pass

    def _reloadGlobalSettings(self):
        """
        Reload pentest database settings from pollenisator database
        """
        apiclient = APIClient.getInstance()
        globalSettings = apiclient.getSettings()
        self.__class__.tags_cache = None
        for settings_dict in globalSettings:
            self.global_settings[settings_dict["key"]] = settings_dict["value"]

    def reloadSettings(self):
        """
        Reload local, database and global settings.
        """
        self._reloadLocalSettings()
        self._reloadDbSettings()
        self._reloadGlobalSettings()

    def reloadUI(self):
        """
        Reload all settings and refresh view with values
        """
        self.reloadSettings()
        self.visual_include_all_domains.set(
            self.db_settings.get("include_all_domains", False))
        self.visual_include_domains_with_ip_in_scope.set(
            self.db_settings.get("include_domains_with_ip_in_scope", False))
        self.visual_include_domains_with_topdomain_in_scope.set(
            self.db_settings.get("include_domains_with_topdomain_in_scope",
                                 False))
        self.visual_search_show_hidden.set(
            self.local_settings.get("search_show_hidden", True))
        self.visual_search_exact_match.set(
            self.local_settings.get("search_exact_match", False))
        self.visual_trap_commands.set(
            self.local_settings.get("trap_commands", False))
        self.text_terms.delete('1.0', tk.END)
        terms_cmd = self.getTerms()
        self.text_terms.insert(tk.INSERT, "\n".join(terms_cmd))
        #self.text_pentesters.delete('1.0', tk.END)
        #self.text_pentesters.insert(
        #    tk.INSERT, "\n".join(
        #        self.db_settings.get("pentesters", [])))
        self.pentesters_treevw.reset()
        pentesters_as_list = self.db_settings.get("pentesters", [""])
        dict_for_tw = {}
        for pentester in pentesters_as_list:
            dict_for_tw[pentester] = tuple([pentester])
        self.pentesters_treevw.recurse_insert(dict_for_tw)
        terms_name = [term_cmd.split(" ")[0] for term_cmd in terms_cmd]
        self.box_favorite_term.config(values=terms_name)
        fav_term = self.getFavoriteTerm()
        if fav_term in terms_name:
            self.box_favorite_term.set(fav_term)
        self.box_pentest_type.set(self.db_settings.get("pentest_type", "None"))
        self.text_pentest_types.delete('1.0', tk.END)
        pentestTypes = Settings.getPentestTypes()
        buffer = ""
        for pentestType, pentestTypeDefectTypes in pentestTypes.items():
            buffer += pentestType + " : " + (
                ", ".join(pentestTypeDefectTypes)) + "\n"
        self.text_pentest_types.insert(tk.INSERT, buffer)
        self.text_tags.delete('1.0', tk.END)
        tagsRegistered = Settings.getTags(onlyGlobal=True)
        buffer = ""
        for tagName, tagColor in tagsRegistered.items():
            buffer += tagName + " : " + tagColor + "\n"
        self.text_tags.insert(tk.INSERT, buffer)
        self.text_db_tags.delete('1.0', tk.END)
        tagsPentestRegistered = Settings.getPentestTags()
        buffer = ""
        for tagName, tagColor in tagsPentestRegistered.items():
            buffer += tagName + " : " + tagColor + "\n"
        self.text_db_tags.insert(tk.INSERT, buffer)
        self.canvas.bind('<Enter>', self.boundToMousewheel)
        self.canvas.bind('<Leave>', self.unboundToMousewheel)
        self.canvas.update()
        self.canvas.create_window((0, 0),
                                  window=self.settingsFrame,
                                  anchor='nw')
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        self.canvas.configure(yscrollcommand=self.myscrollbar.set)

    def saveLocalSettings(self):
        """
        Save local settings to conf file
        """
        with open(self.confdir, "w") as f:
            f.write(json.dumps(self.local_settings))

    def savePentestSettings(self):
        apiclient = APIClient.getInstance()
        settings = apiclient.find("settings")
        existing_settings = {}
        for setting in settings:
            existing_settings[setting["key"]] = setting
        for k, v in self.db_settings.items():
            if k in existing_settings:
                if k == "tags":
                    for line_key, line_value in v.items():
                        tag, color = line_key, line_value
                        if tag not in existing_settings["tags"]["value"]:
                            apiclient.registerTag(tag, color, False)
                        else:
                            apiclient.updateTag(tag, color, False)
                    for tag in existing_settings["tags"].get("value", {}):
                        if tag not in v:
                            apiclient.unregisterTag(tag, False)
                else:
                    apiclient.updateInDb(apiclient.getCurrentPentest(),
                                         "settings", {"key": k},
                                         {"$set": {
                                             "value": v
                                         }})

    def save(self):
        """
        Save all the settings (local, database and global)
        """
        apiclient = APIClient.getInstance()

        for k, v in self.global_settings.items():
            if apiclient.getSettings({"key": k}) is None:
                apiclient.createSetting(k, v)
            else:
                apiclient.updateSetting(k, v)
        self.savePentestSettings()
        self.saveLocalSettings()
        self.reloadUI()

    def _onMousewheel(self, event):
        """Scroll the settings canvas
        Args:
            event: scroll info filled when scroll event is triggered"""
        if event.num == 5 or event.delta == -120:
            count = 1
        if event.num == 4 or event.delta == 120:
            count = -1
        self.canvas.yview_scroll(count, "units")

    def boundToMousewheel(self, _event):
        """Called when the main view canvas is focused.
        Bind the command scrollbar button on linux to the main view canvas
        Args:
            _event: not used but mandatory"""
        self.canvas.bind_all("<Button-4>", self._onMousewheel)
        self.canvas.bind_all("<Button-5>", self._onMousewheel)

    def unboundToMousewheel(self, _event):
        """Called when the main view canvas is unfocused.
        Unbind the command scrollbar button on linux to the main view canvas
        Args:
            _event: not used but mandatory"""
        self.canvas.unbind_all("<Button-4>")
        self.canvas.unbind_all("<Button-5>")

    def initUI(self, parent):
        """Create settings widgets and initialize them
        Args:
            parent: parent tkinter container widget"""
        if self.visual_include_all_domains is not None:  # Already built
            self.reloadUI()
            return
        self.canvas = tk.Canvas(parent, bg="white")
        self.settingsFrame = ttk.Frame(self.canvas)
        self.myscrollbar = tk.Scrollbar(parent,
                                        orient="vertical",
                                        command=self.canvas.yview)
        self.myscrollbar.grid(column=1, row=0, sticky="ns")

        self.canvas.grid(column=0, row=0, sticky="nsew")
        parent.columnconfigure(0, weight=1)
        parent.rowconfigure(0, weight=1)

        self.visual_include_all_domains = tk.BooleanVar()
        self.visual_include_domains_with_ip_in_scope = tk.BooleanVar()
        self.visual_include_domains_with_topdomain_in_scope = tk.BooleanVar()
        self.visual_search_show_hidden = tk.BooleanVar()
        self.visual_search_exact_match = tk.BooleanVar()
        self.visual_trap_commands = tk.BooleanVar()

        lbl_domains = ttk.LabelFrame(self.settingsFrame,
                                     text="Discovered domains options:")
        lbl_domains.pack(padx=10,
                         pady=10,
                         side=tk.TOP,
                         anchor=tk.W,
                         fill=tk.X,
                         expand=tk.YES)
        chkbox_include_domains_with_ip_in_scope = ttk.Checkbutton(
            lbl_domains,
            text="Check if discovered subdomains ips are in scope",
            variable=self.visual_include_domains_with_ip_in_scope)
        chkbox_include_domains_with_ip_in_scope.pack(padx=10,
                                                     pady=10,
                                                     side=tk.TOP,
                                                     anchor=tk.W)

        chkbox_include_domains_with_topdomain_in_scope = ttk.Checkbutton(
            lbl_domains,
            text=
            "Check if discovered subdomains have a top domain already in scope",
            variable=self.visual_include_domains_with_topdomain_in_scope)
        chkbox_include_domains_with_topdomain_in_scope.pack(padx=10,
                                                            pady=10,
                                                            side=tk.TOP,
                                                            anchor=tk.W)
        chkbox_include_all_domains = ttk.Checkbutton(
            lbl_domains,
            text="/!\\ Include every domain found in scope",
            variable=self.visual_include_all_domains)
        chkbox_include_all_domains.pack(padx=10,
                                        pady=10,
                                        side=tk.TOP,
                                        anchor=tk.W)

        frame_term = ttk.LabelFrame(self.settingsFrame,
                                    text="Local terminals:")
        self.text_terms = tk.scrolledtext.ScrolledText(frame_term,
                                                       relief=tk.SUNKEN,
                                                       height=4,
                                                       width=130,
                                                       font=("Sans", 10))
        self.text_terms.pack(side=tk.TOP, fill=tk.X, pady=5)
        chkbox_trap_commands = ttk.Checkbutton(
            frame_term,
            text="Trap every command (instead of using pollex)",
            variable=self.visual_trap_commands)
        chkbox_trap_commands.pack(side=tk.TOP, pady=5)
        frame_fav_term = ttk.Frame(frame_term)
        lbl_fav_term = ttk.Label(frame_fav_term, text="Favorite term:")
        lbl_fav_term.grid(row=0, column=0, sticky=tk.E, pady=5)
        self.box_favorite_term = ttk.Combobox(frame_fav_term,
                                              values=(self.getTerms()),
                                              state="readonly")
        self.box_favorite_term.grid(row=0, column=1, sticky=tk.W, pady=5)

        frame_fav_term.pack(padx=10,
                            pady=10,
                            side=tk.TOP,
                            anchor=tk.W,
                            fill=tk.X,
                            expand=tk.YES)
        frame_term.pack(padx=10,
                        pady=10,
                        side=tk.TOP,
                        anchor=tk.W,
                        fill=tk.X,
                        expand=tk.YES)
        lbl_SearchBar = ttk.LabelFrame(self.settingsFrame,
                                       text="Search settings:")
        lbl_SearchBar.pack(padx=10,
                           pady=10,
                           side=tk.TOP,
                           anchor=tk.W,
                           fill=tk.X,
                           expand=tk.YES)
        chkbox_search_show_hidden = ttk.Checkbutton(
            lbl_SearchBar,
            text="Show hidden objects",
            variable=self.visual_search_show_hidden)
        chkbox_search_show_hidden.pack(padx=10,
                                       pady=10,
                                       side=tk.TOP,
                                       anchor=tk.W)
        chkbox_search_exact_match = ttk.Checkbutton(
            lbl_SearchBar,
            text="Exact match",
            variable=self.visual_search_exact_match)
        chkbox_search_exact_match.pack(padx=10,
                                       pady=10,
                                       side=tk.TOP,
                                       anchor=tk.W)

        lblframe_pentest_params = ttk.LabelFrame(self.settingsFrame,
                                                 text="Pentest parameters:")
        lblframe_pentest_params.pack(padx=10,
                                     pady=10,
                                     side=tk.TOP,
                                     anchor=tk.W,
                                     fill=tk.X,
                                     expand=tk.YES)
        lbl_pentest_type = ttk.Label(lblframe_pentest_params,
                                     text="Pentest type:")
        lbl_pentest_type.grid(row=0, column=0, sticky=tk.E)
        self.box_pentest_type = ttk.Combobox(
            lblframe_pentest_params,
            values=tuple(Settings.getPentestTypes().keys()),
            state="readonly")
        self.box_pentest_type.grid(row=1, column=1, sticky=tk.W)
        # self.text_pentesters = tk.scrolledtext.ScrolledText(
        #     lblframe_pentest_params, relief=tk.SUNKEN, height=3, font = ("Sans", 10))
        # lbl_pentesters = ttk.Label(
        #     lblframe_pentest_params, text="Pentester names:")
        # lbl_pentesters.grid(row=2, column=0, sticky=tk.E)
        # self.text_pentesters.grid(row=2, column=1, sticky=tk.W, pady=5)
        form_pentesters_panel = ttk.Frame(self.settingsFrame)
        self.form_pentesters = FormPanel(side=tk.TOP, fill=tk.X, pady=5)
        self.form_pentesters.addFormSearchBar("Pentester search",
                                              self.searchCallback,
                                              self.form_pentesters,
                                              side=tk.TOP)
        self.form_pentesters.addFormLabel("Pentesters added", side=tk.LEFT)
        self.pentesters_treevw = self.form_pentesters.addFormTreevw(
            "Additional pentesters names", ["Additional pentesters names"],
            (""),
            height=30,
            width=200,
            pady=5,
            fill=tk.X,
            side=tk.RIGHT)

        self.form_pentesters.constructView(form_pentesters_panel)
        form_pentesters_panel.pack(padx=10,
                                   pady=10,
                                   side=tk.TOP,
                                   anchor=tk.W,
                                   fill=tk.X,
                                   expand=tk.YES)
        lblframe_global_params = ttk.LabelFrame(self.settingsFrame,
                                                text="Other parameters:")
        lblframe_global_params.pack(padx=10,
                                    pady=10,
                                    side=tk.TOP,
                                    anchor=tk.W,
                                    fill=tk.X,
                                    expand=tk.YES)
        lbl_pentest_types = ttk.Label(lblframe_global_params,
                                      text="Pentests possible types:")
        lbl_pentest_types.grid(row=0, column=0, sticky=tk.E)
        self.text_pentest_types = tk.scrolledtext.ScrolledText(
            lblframe_global_params,
            relief=tk.SUNKEN,
            height=6,
            font=("Sans", 10))
        self.text_pentest_types.grid(row=0, column=1, sticky=tk.W)
        lbl_tags = ttk.Label(lblframe_global_params, text="Registered tags:")
        lbl_tags.grid(row=1, column=0, sticky=tk.E)
        self.text_tags = tk.scrolledtext.ScrolledText(lblframe_global_params,
                                                      relief=tk.SUNKEN,
                                                      height=6,
                                                      font=("Sans", 10))
        self.text_tags.grid(row=1, column=1, sticky=tk.W)
        lbl_db_tags = ttk.Label(lblframe_global_params,
                                text="Pentest only tags:")
        lbl_db_tags.grid(row=2, column=0, sticky=tk.E)
        self.text_db_tags = tk.scrolledtext.ScrolledText(
            lblframe_global_params,
            relief=tk.SUNKEN,
            height=6,
            font=("Sans", 10))
        self.text_db_tags.grid(row=2, column=1, sticky=tk.W)
        btn_save = ttk.Button(parent, text="Save", command=self.on_ok)
        btn_save.grid(row=3, column=0, padx=10, pady=10, sticky="s")
        self.settingsFrame.pack(fill=tk.BOTH, expand=1)

        #self.reloadUI()
    def searchCallback(self, searchreq):
        apiclient = APIClient.getInstance()
        users = apiclient.searchUsers(searchreq)
        if users is None:
            return [], "Invalid response from API"
        ret = [{
            "title": user,
            "additional pentesters names": user
        } for user in users]
        return ret, ""

    def on_ok(self):
        """Callback on click save button. loads some data and calls save.
        Args:
            parent: parent tkinter container widget"""
        self.db_settings[
            "include_all_domains"] = self.visual_include_all_domains.get() == 1
        self.db_settings[
            "include_domains_with_ip_in_scope"] = self.visual_include_domains_with_ip_in_scope.get(
            ) == 1
        self.db_settings["pentest_type"] = self.box_pentest_type.get()
        self.db_settings[
            "include_domains_with_topdomain_in_scope"] = self.visual_include_domains_with_topdomain_in_scope.get(
            ) == 1
        self.db_settings["pentesters"] = []
        form_values = self.form_pentesters.getValue()
        form_values_as_dicts = ViewElement.list_tuple_to_dict(form_values)
        self.db_settings["pentesters"] = [
            x for x in form_values_as_dicts["Additional pentesters names"]
            if x != ""
        ]
        self.db_settings["tags"] = {}
        for tagRegistered in self.text_db_tags.get('1.0', tk.END).split("\n"):
            if tagRegistered.strip() != "":
                line_splitted = tagRegistered.strip().split(":")
                if len(line_splitted) == 2:
                    self.db_settings["tags"][
                        line_splitted[0].strip()] = line_splitted[1].strip()

        self.local_settings[
            "search_show_hidden"] = self.visual_search_show_hidden.get() == 1
        self.local_settings[
            "search_exact_match"] = self.visual_search_exact_match.get() == 1
        self.local_settings["terms"] = [
            x.strip() for x in self.text_terms.get('1.0', tk.END).split("\n")
            if x.strip() != ""
        ]
        self.local_settings["fav_term"] = self.box_favorite_term.get().strip()
        self.local_settings["trap_commands"] = self.visual_trap_commands.get(
        ) == 1
        self.global_settings["pentest_types"] = {}
        for type_of_pentest in self.text_pentest_types.get('1.0',
                                                           tk.END).split("\n"):
            if type_of_pentest.strip() != "":
                line_splitted = type_of_pentest.strip().split(":")
                if len(line_splitted) == 2:
                    typesOfDefects = list(
                        map(lambda x: x.strip(), line_splitted[1].split(",")))
                    self.global_settings["pentest_types"][
                        line_splitted[0].strip()] = typesOfDefects
        self.global_settings["tags"] = {}
        for tagRegistered in self.text_tags.get('1.0', tk.END).split("\n"):
            if tagRegistered.strip() != "":
                line_splitted = tagRegistered.strip().split(":")
                if len(line_splitted) == 2:
                    self.global_settings["tags"][
                        line_splitted[0].strip()] = line_splitted[1].strip()
        self.save()
        tkinter.messagebox.showinfo("Settings", "Settings saved.")

    def getPentestType(self):
        """Return selected database pentest type.
        Returns:
            Open database pentest type. string "None" if not defined"""
        return self.db_settings.get("pentest_type", "None")

    def getPentesters(self):
        """Return a list of pentesters registered for open pentest database
        Returns:
            List of pentesters names"""
        return self.db_settings.get("pentesters", [])

    def notify(self, db, iid, action):
        if db == "pollenisator":
            self._reloadGlobalSettings()
        else:
            self._reloadDbSettings()
예제 #4
0
class ViewElement(object):
    """
    Defines a basic view to be inherited. Those functions are generic entry points to models.
    Most of them should not be redefined in other Views.
    Attributes:
        icon: icon name to show in treeview. Icon filename must be in icon directory
        cachedClassIcon: a cached loaded PIL image icon of ViewElement.icon. Starts as None.
    """
    icon = 'undefined.png'
    cachedClassIcon = None

    def __init__(self, appTw, appViewFrame, mainApp, controller):
        """Constructor
        Args:
            appTw: a PollenisatorTreeview instance to put this view in
            appViewFrame: an view frame to build the forms in.
            mainApp: the Application instance
            controller: a CommandController for this view.
        """
        self.appliTw = appTw
        self.appliViewFrame = appViewFrame
        self.mainApp = mainApp
        self.controller = controller
        self.form = FormPanel()

    @classmethod
    def getClassIcon(cls):
        """
        Load the class icon in cache if it is not yet done, and returns it

        Return:
            Returns the ImageTk.PhotoImage icon representing this class .
        """
        from PIL import Image, ImageTk
        if cls.cachedClassIcon == None:
            abs_path = os.path.dirname(os.path.abspath(__file__))
            path = os.path.join(abs_path, "../../icon/" + cls.icon)
            cls.cachedClassIcon = ImageTk.PhotoImage(Image.open(path))
        return cls.cachedClassIcon

    def getIcon(self):
        """
        Load the object icon in cache if it is not yet done, and returns it

        Return:
            Returns the icon representing this object.
        """
        return self.__class__.getClassIcon()

    def addChildrenBaseNodes(self, newNode):
        """
        Add to the given node from a treeview the mandatory childrens.
        Will be redefined in children.

        Args:
            newNode: the newly created node we want to add children to.
        """
        # pass

    def delete(self, _event=None, showWarning=True):
        """
        Entry point to the model doDelete function.

        Args:
            _event: automatically filled if called by an event. Not used
            showWarning: a boolean. If true, the user will be asked a confirmation before supression. Default to True.
        """
        ret = True
        if showWarning:
            ret = tkinter.messagebox.askokcancel(
                "Delete",
                "You are going to delete this element, do you want to continue?"
            )
        if (ret):
            self.controller.doDelete()

    def update(self, event=None):
        """
        Entry point to the model doUpdate function.

        Args:
            event: automatically filled if called by an event. Holds info on update clicked widget.
        Returns:
            * a boolean to shwo success or failure
            * an empty message on success, an error message on failure
        """
        res, msg = self.form.checkForm()
        if (res):
            form_values = self.form.getValue()
            form_values_as_dicts = ViewElement.list_tuple_to_dict(form_values)
            self.controller.doUpdate(form_values_as_dicts)
            if event is not None:
                caller = event.widget
                toast = ChildDialogToast(self.appliViewFrame,
                                         "Done",
                                         x=caller.winfo_rootx(),
                                         y=caller.winfo_rooty() +
                                         caller.winfo_reqheight(),
                                         width=caller.winfo_reqwidth())
                toast.show()
            return True, ""
        else:
            tkinter.messagebox.showwarning("Form not validated",
                                           msg,
                                           parent=self.appliViewFrame)
            return False, msg

    def insert(self, _event=None):
        """
        Entry point to the model doInsert function.

        Args:
            _event: automatically filled if called by an event. Not used
        Returns:
            * a boolean to shwo success or failure
            * an empty message on success, an error message on failure
        """
        res, msg = self.form.checkForm()
        if (res):
            form_values = self.form.getValue()
            form_values_as_dicts = ViewElement.list_tuple_to_dict(form_values)
            res, nbErrors = self.controller.doInsert(form_values_as_dicts)
            if not res:
                msg = "This element cannot be inserted, check for conflicts with existings elements."
                tkinter.messagebox.showerror("Insertion failed",
                                             msg,
                                             parent=self.appliViewFrame)
                return False, msg
            else:
                if nbErrors > 0:
                    msg = str(len(res)) + " were inserted, " + str(
                        nbErrors
                    ) + " were not to avoid conflicts or out of wave elements."
                    tkinter.messagebox.showwarning(
                        "Insertion succeeded with warnings",
                        msg,
                        parent=self.appliViewFrame)
                    return True, msg
                else:
                    return True, ""
        else:
            tkinter.messagebox.showwarning("Form not validated",
                                           msg,
                                           parent=self.appliViewFrame)
            return False, msg

    def tagClicked(self, name):
        """Callback intermediate for tag clicked
        Ensure that the tag name clicked is added to View item
        Args:
            name: a tag name
        """
        return lambda _event: self.tagButtonClicked(name)

    def tagButtonClicked(self, name):
        """Callback for tag button clicked
        Ensure that the tag name clicked is set to View item
        Args:
            name: a tag name
        """
        self.controller.setTags([name])

    def completeModifyWindow(self, editable=True, addTags=True):
        """
        Add the buttons for an update window.
            -Submit button that validates the form with the update function.
            -Delete button that asks the user to delete the object with the delete function.
        """
        pan = self.form.addFormPanel()
        if editable:
            pan.addFormButton("Submit", self.update)
            pan.addFormButton("Delete", self.delete)
            if addTags:
                registeredTags = Settings.Settings.getTags()
                keys = list(registeredTags.keys())
                column = 0
                item_no = 0
                listOfLambdas = [
                    self.tagClicked(keys[i]) for i in range(len(keys))
                ]
                for registeredTag, color in registeredTags.items():
                    if column == 0:
                        panTags = self.form.addFormPanel(pady=0)
                    s = ttk.Style(self.mainApp)
                    try:  # CHECK IF COLOR IS VALID
                        ttk.Label(self.mainApp, background=color)
                    except tkinter.TclError as e:
                        #color incorrect
                        color = "white"
                    s.configure("" + color + "V.TButton",
                                background=color,
                                foreground="black",
                                borderwidth=1,
                                bordercolor="black")
                    s.map("" + color + "V.TButton",
                          foreground=[('active', "dark gray")],
                          background=[('active', color)])
                    s.layout("" + color + "V.TButton", [('VButton.border', {
                        'sticky':
                        'nswe',
                        'border':
                        '1',
                        'children': [('Button.focus', {
                            'sticky':
                            'nswe',
                            'children': [('Button.padding', {
                                'sticky':
                                'ew',
                                'children': [('Button.label', {
                                    'sticky': 'ew'
                                })]
                            })]
                        })]
                    })])
                    btn_tag = panTags.addFormButton(registeredTag,
                                                    listOfLambdas[item_no],
                                                    side="left",
                                                    padx=1,
                                                    pady=0)
                    btn_tag.configure(style="" + color + "V.TButton")
                    column += 1
                    item_no += 1
                    if column == 4:
                        column = 0
        self.showForm()

    def showForm(self):
        """Resets the application view frame and start displaying the form in it
        """
        for widget in self.appliViewFrame.winfo_children():
            widget.destroy()
        self.form.constructView(self.appliViewFrame)

    def completeInsertWindow(self):
        """
        Add the button for an insert window.
            -Insert button that validate the form with the insert function.
        """
        pan = self.form.addFormPanel()
        pan.addFormButton("Insert", self.insert)
        for widget in self.appliViewFrame.winfo_children():
            widget.destroy()
        self.form.constructView(self.appliViewFrame)

    def hide(self):
        """Tells the application treeview to hide this node
        """
        self.appliTw.hide(str(self.controller.getDbId()))

    def unhide(self):
        """Tells the application treeview to unhide this node
        """
        self.appliTw.unhide(self)

    def __str__(self):
        """
        Return the __str__ method of the model
        """
        return str(self.controller.getModelRepr())

    @classmethod
    def DbToTreeviewListId(cls, parent_db_id):
        """Converts a mongo Id to a unique string identifying a list of view elemnt given its parent
        Args:
            parent_db_id: the parent node mongo ID
        Returns:
            A string that should be unique to describe the parent list of viewelement node
        """
        return str(parent_db_id)

    def getParentId(self):
        """
        Return the id of the parent node in treeview.

        Returns:
            return the model parent id DbToTreeviewListId
        """
        return self.controller.getParentId()

    def getParentNode(self):
        """
        Return the parent node in treeview.
        """
        return self.__class__.DbToTreeviewListId(self.controller.getParentId())

    def updateReceived(self):
        """Called when any view element update is received by notification.
        Resets the node tags according to database and hide it if "hidden" is in tags
        """
        if self.controller.getDbId() is None:
            return
        tags = self.controller.getTags()
        try:
            self.appliTw.item(str(self.controller.getDbId()), tags=tags)
        except TclError:
            pass
        if "hidden" in tags:
            self.hide()

    def insertReceived(self):
        """Called when any view element insert is received by notificaiton
        To be overriden
        """
        pass

    def key(self):
        """Returns a key for sorting this node
        Returns:
            string, basic key: string so alphanumerical sorting will be used
        """
        return str(self.controller.getModelRepr())

    @classmethod
    def list_tuple_to_dict(cls, list_of_tuple):
        """Transforms a list of 2-tuple to a dictionnary
        Args:
            list_of_tuple: a 2-tuple with (key, value)
        Returns:
            A dictionnary with all key-values pair inserted
        """
        ret = dict()
        for key, value in list_of_tuple:
            ret[key] = value
        return ret
예제 #5
0
class ChildDialogEditPassword:
    """
    Open a child dialog of a tkinter application to ask a user to reset its password.
    """
    def __init__(self, parent, username, askOldPwd=True):
        """
        Open a child dialog of a tkinter application to ask the new password and possibly the old

        Args:
            parent: the tkinter parent view to use for this window construction.
            username: The username to reset the password of
            askOldPwd : a boolean to use changePassword (user api) or resetPassword (admin api)
        """
        self.parent = parent
        self.app = tk.Toplevel(parent)
        self.askOldPwd = askOldPwd
        self.app.title("Change " + str(username) + " password")
        appFrame = ttk.Frame(self.app)
        self.form = FormPanel()
        self.form.addFormLabel("Username")
        self.form.addFormStr("Username", ".+", default=username, readonly=True)
        if askOldPwd:
            self.form.addFormLabel("Old password")
            self.form.addFormStr("Old password", ".+", show="*")
        self.form.addFormLabel("New Password")
        self.form.addFormStr(
            "New password",
            ".{8,}",
            show="*",
            error_msg="New password must be at least 8 characters long")
        self.form.addFormButton("OK", self.onOk)
        self.rvalue = None
        self.form.constructView(appFrame)
        appFrame.pack(ipadx=10, ipady=10)
        try:
            self.app.wait_visibility()
            self.app.transient(parent)
            self.app.focus_force()
            self.app.grab_set()
            self.app.lift()
        except tk.TclError:
            pass

    def onOk(self, _event=None):
        """Called the ok button is pressed.
        
        Args:
            _event: not used but mandatory"""
        res, msg = self.form.checkForm()
        apiclient = APIClient.getInstance()
        success = False
        if res:
            form_values = self.form.getValue()
            form_values_as_dicts = ViewElement.list_tuple_to_dict(form_values)
            username = form_values_as_dicts["Username"]
            newPwd = form_values_as_dicts["New password"]
            if self.askOldPwd:
                oldPwd = form_values_as_dicts["Old password"]
                msg = apiclient.changeUserPassword(oldPwd, newPwd)
            else:
                msg = apiclient.resetPassword(username, newPwd)
            if msg != "":
                tk.messagebox.showwarning("Change password",
                                          msg,
                                          parent=self.app)
        else:
            tk.messagebox.showwarning("Form not validated",
                                      msg,
                                      parent=self.app)

        self.app.destroy()
class ChildDialogFileParser:
    """
    Open a child dialog of a tkinter application to ask details about
    existing files parsing.
    """
    def __init__(self, default_path=""):
        """
        Open a child dialog of a tkinter application to ask details about
        existing files parsing.

        Args:
            default_path: a default path to be added
        """
        self.app = tkinterDnD.Tk()
        Utils.setStyle(self.app)
        self.app.title("Upload result file")
        self.rvalue = None
        self.default = default_path
        appFrame = ttk.Frame(self.app)
        apiclient = APIClient.getInstance()
        self.form = FormPanel()
        self.form.addFormLabel("Import one file or choose a directory",
                               "",
                               side=tk.TOP)
        self.form.addFormFile("File",
                              ".+",
                              self.default,
                              width=50,
                              side=tk.TOP,
                              mode="file|directory")
        self.form.addFormLabel("Plugins", side=tk.TOP)
        self.form.addFormCombo("Plugin",
                               ["auto-detect"] + apiclient.getPlugins(),
                               "auto-detect",
                               side=tk.TOP)
        self.form.addFormButton("Parse", self.onOk, side=tk.RIGHT)

        self.form.constructView(appFrame)
        appFrame.pack(ipadx=10, ipady=10)

        try:
            self.app.wait_visibility()
            self.app.focus_force()
            self.app.grab_set()
            self.app.lift()
        except tk.TclError:
            pass
        self.app.mainloop()
        self.app.destroy()

    def onOk(self, _event=None):
        """
        Called when the user clicked the validation button.
        launch parsing with selected parser on selected file/directory.
        Close the window.

        Args:
            _event: not used but mandatory
        """
        res, msg = self.form.checkForm()
        if not res:
            tk.messagebox.showwarning("Form not validated",
                                      msg,
                                      parent=self.app)
            return
        notes = None
        tags = None
        form_values = self.form.getValue()
        form_values_as_dicts = ViewElement.list_tuple_to_dict(form_values)
        files_paths = form_values_as_dicts["File"]
        plugin = form_values_as_dicts["Plugin"]
        files = set()
        for filepath in files_paths:
            if os.path.isdir(filepath):
                # r=root, d=directories, f = files
                for r, _d, f in os.walk(filepath):
                    for fil in f:
                        files.add(os.path.join(r, fil))
            else:
                files.add(filepath)
        dialog = ChildDialogProgress(
            self.app, "Importing files", "Importing " + str(len(files)) +
            " files. Please wait for a few seconds.", 200, "determinate")
        dialog.show(len(files))
        # LOOP ON FOLDER FILES
        results = {}
        apiclient = APIClient.getInstance()
        for f_i, file_path in enumerate(files):
            additional_results = apiclient.importExistingResultFile(
                file_path, plugin)
            for key, val in additional_results.items():
                results[key] = results.get(key, 0) + val
            dialog.update(f_i)
        dialog.destroy()
        # DISPLAY RESULTS
        presResults = ""
        filesIgnored = 0
        for key, value in results.items():
            presResults += str(value) + " " + str(key) + ".\n"
            if key == "Ignored":
                filesIgnored += 1
        if plugin == "auto-detect":
            if filesIgnored > 0:
                tk.messagebox.showwarning("Auto-detect ended",
                                          presResults,
                                          parent=self.app)
            else:
                tk.messagebox.showinfo("Auto-detect ended",
                                       presResults,
                                       parent=self.app)
        else:
            if filesIgnored > 0:
                tk.messagebox.showwarning("Parsing ended",
                                          presResults,
                                          parent=self.app)
            else:
                tk.messagebox.showinfo("Parsing ended",
                                       presResults,
                                       parent=self.app)

        self.rvalue = None
        self.app.quit()