def __init__(self, parent, title, err): """ Open a child dialog of a tkinter application to present the user to an unhandled exception. Can be used to report issue to github. Args: parent: the tkinter parent view to use for this window construction. title: A title for the new windows err: the error that occured causing this window to appear """ self.rvalue = None self.parent = parent self.app = tk.Toplevel(parent) self.app.title(title) appFrame = ttk.Frame(self.app) self.form = FormPanel() self.err = err self.form.addFormLabel( "An error occured. Please make an issue with the below stack trace and when it occured.", side=tk.TOP) self.form.addFormText("Error", ".+", str(self.err), None, side=tk.TOP) self.form.addFormButton("Report bug", self.onOk, side=tk.RIGHT) self.form.addFormButton("Close", self.onError, side=tk.RIGHT) self.rvalue = None self.form.constructView(appFrame) appFrame.pack(ipadx=10, ipady=10) self.app.transient(parent) 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 __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 __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
class ChildDialogException: """ Open a child dialog of a tkinter application to present the user to an unhandled exception. Can be used to report issue to github. """ def __init__(self, parent, title, err): """ Open a child dialog of a tkinter application to present the user to an unhandled exception. Can be used to report issue to github. Args: parent: the tkinter parent view to use for this window construction. title: A title for the new windows err: the error that occured causing this window to appear """ self.rvalue = None self.parent = parent self.app = tk.Toplevel(parent) self.app.title(title) appFrame = ttk.Frame(self.app) self.form = FormPanel() self.err = err self.form.addFormLabel( "An error occured. Please make an issue with the below stack trace and when it occured.", side=tk.TOP) self.form.addFormText("Error", ".+", str(self.err), None, side=tk.TOP) self.form.addFormButton("Report bug", self.onOk, side=tk.RIGHT) self.form.addFormButton("Close", self.onError, side=tk.RIGHT) self.rvalue = None self.form.constructView(appFrame) appFrame.pack(ipadx=10, ipady=10) self.app.transient(parent) 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 when the user clicked the validation button. Set the rvalue attributes to the value selected and close the window. Args: _event: not used but mandatory """ # send the data to the parent postIssue(self.err) def onError(self, _event=None): """ Close the dialog and set rvalue to None Args: _event: not used but mandatory """ self.rvalue = False self.app.destroy()
def __init__(self, parent, user_data): """ 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. user_data: user from database """ self.app = tk.Toplevel(parent, bg="white") self.app.resizable(True, True) appFrame = ttk.Frame(self.app) self.app.title("View user info") self.rvalue = None self.parent = parent panel = FormPanel() panel_info = panel.addFormPanel(grid=True) panel_info.addFormLabel("Domain") panel_info.addFormStr("Domain", "", user_data.get("domain", ""), status="readonly", row=0, column=1) panel_info.addFormLabel("Username", row=1) panel_info.addFormStr("Username", "", user_data.get("username", ""), status="readonly", row=1, column=1) panel_info.addFormLabel("Password", row=2) panel_info.addFormStr("Password", "", user_data.get("password", ""), status="readonly", row=2, column=1) panel.addFormLabel("Desc", text=f"{user_data.get('desc', '')}", side="top") panel.addFormTreevw("Groups", ("Group", ), [[x] for x in user_data.get('groups', [])], side="top") button_panel = panel.addFormPanel(side="bottom") button_panel.addFormButton("Quit", self.onError, side="right") panel.constructView(appFrame) appFrame.pack(ipadx=10, ipady=5, expand=1) try: self.app.wait_visibility() self.app.transient(parent) self.app.grab_set() self.app.focus_force() self.app.lift() except tk.TclError: pass
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()
def __init__(self, parent, info="Input text", default='', multiline=True, **kwargs): """ Open a child dialog of a tkinter application to ask details about existing files parsing. Args: default_path: a default path to be added """ from pollenisatorgui.core.Forms.FormPanel import FormPanel self.app = tk.Toplevel(parent, bg="white") self.app.title(info) self.rvalue = None appFrame = ttk.Frame(self.app) self.form = FormPanel() self.form.addFormLabel("Input text", text=info, side=tk.TOP) if multiline: self.formText = self.form.addFormText(info, "", default, side=tk.TOP, **kwargs) else: self.formText = self.form.addFormStr(info, "", default, side=tk.TOP, **kwargs) btn = self.form.addFormButton("OK", self.onOk, side=tk.RIGHT) self.button = self.form.addFormButton("Cancel", self.onError, side=tk.RIGHT) self.form.constructView(appFrame) self.app.bind("<Return>", self.onOk) self.app.bind("<Escape>", self.onError) 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.formText.setFocus()
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()
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)
def __init__(self, parent, displayMsg="Add AD users"): """ 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. 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, bg="white") self.app.resizable(False, False) appFrame = ttk.Frame(self.app) self.app.title(displayMsg) self.rvalue = None self.parent = parent panel = FormPanel() self.formtext = panel.addFormText("Users", r"^\S+\\\S+:\S+$", default="domain\\username:password", side="top") button_panel = panel.addFormPanel(side="bottom") button_panel.addFormButton("Submit", self.onOk, side="right") button_panel.addFormButton("Cancel", self.onError, side="right") panel.constructView(appFrame) appFrame.pack(ipadx=10, ipady=5) try: self.app.wait_visibility() self.app.transient(parent) self.app.grab_set() self.app.focus_force() self.app.lift() except tk.TclError: pass
def __init__(self, parent, info="Choose a file", 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(info) self.rvalue = None self.default = default_path appFrame = ttk.Frame(self.app) self.form = FormPanel() self.form.addFormLabel("Choose one file", info, side=tk.TOP) self.fileForm = self.form.addFormFile("File", ".+", '', width=50, side=tk.TOP, mode="file") self.button = self.form.addFormButton("Cancel", self.onError, side=tk.RIGHT) self.form.addFormButton("OK", 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 __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
class ChildDialogAskText: """ Open a child dialog of a tkinter application to ask a text area. """ def __init__(self, parent, info="Input text", default='', multiline=True, **kwargs): """ Open a child dialog of a tkinter application to ask details about existing files parsing. Args: default_path: a default path to be added """ from pollenisatorgui.core.Forms.FormPanel import FormPanel self.app = tk.Toplevel(parent, bg="white") self.app.title(info) self.rvalue = None appFrame = ttk.Frame(self.app) self.form = FormPanel() self.form.addFormLabel("Input text", text=info, side=tk.TOP) if multiline: self.formText = self.form.addFormText(info, "", default, side=tk.TOP, **kwargs) else: self.formText = self.form.addFormStr(info, "", default, side=tk.TOP, **kwargs) btn = self.form.addFormButton("OK", self.onOk, side=tk.RIGHT) self.button = self.form.addFormButton("Cancel", self.onError, side=tk.RIGHT) self.form.constructView(appFrame) self.app.bind("<Return>", self.onOk) self.app.bind("<Escape>", self.onError) 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.formText.setFocus() def onError(self, _event=None): self.rvalue = None 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 text = self.formText.getValue() self.rvalue = text self.app.destroy()
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)
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()
def __init__(self, parent, computer_data): """ 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. computer_data: computer from database """ self.app = tk.Toplevel(parent, bg="white") self.app.resizable(True, True) appFrame = ttk.Frame(self.app) self.app.title("View user info") self.rvalue = None self.parent = parent panel = FormPanel() panel_info = panel.addFormPanel(grid=True) panel_info.addFormLabel("IP") panel_info.addFormStr("IP", "", computer_data.get("ip", ""), status="readonly", row=0, column=1) panel_info.addFormLabel("Name", column=2) panel_info.addFormStr("Name", "", computer_data.get("name", ""), status="readonly", column=3) panel_info.addFormLabel("OS", row=1) panel_info.addFormStr("OS", "", computer_data.get("OS", ""), status="readonly", row=1, column=1) panel_info.addFormLabel("Signing", row=2) panel_info.addFormStr("Signing", "", computer_data.get("signing", ""), status="readonly", row=2, column=1) panel_info.addFormLabel("SMBv1", row=3) panel_info.addFormStr("SMBv1", "", computer_data.get("SMBv1", ""), status="readonly", row=3, column=1) panel.addFormLabel("Users", side="top") panel.addFormTreevw("Users", ("Domain", "Username", "Password"), computer_data.get("users", []), side="top") panel.addFormLabel("Admins", side="top") panel.addFormTreevw("Admins", ("Domain", "Username", "Password"), computer_data.get("admins", []), side="top") if computer_data.get("secrets", []): panel.addFormLabel("Secrets", side="top") panel.addFormTreevw("Secrets", ("Secret", ""), list( map(lambda s: (s, ""), computer_data.get("secrets", []))), side="top") ntds = computer_data.get("ntds", []) if ntds: panel.addFormLabel("NTDS", side="top") panel.addFormText("NTDS", "", "\n".join(ntds), side="top") button_panel = panel.addFormPanel(side="bottom") button_panel.addFormButton("Quit", self.onError, side="right") panel.constructView(appFrame) appFrame.pack(ipadx=10, ipady=5, expand=1) try: self.app.wait_visibility() self.app.transient(parent) self.app.grab_set() self.app.focus_force() self.app.lift() except tk.TclError: pass
def __init__(self, parent, displayMsg="Configure AD module"): """ 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. 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, bg="white") self.app.resizable(True, True) appFrame = ttk.Frame(self.app) self.app.title(displayMsg) self.rvalue = None self.parent = parent panel = FormPanel() ad_settings = ActiveDirectory.getSettings() self.explanationLbl = panel.addFormText("Explanation", "", """ Explanations You can use those commands with different Types and Variables: Types: - Computer: those commands will be available when right clicking one or many computer and will execute the selected command for each one of them. It takes into account what user is selected in the user treeview or will ask information otherwise. - Share: those commands will be available when right clicking one File in a share. - OnComputerNewUser: Same as computer + will be launched automatically for each new user that can connect to a computer for this computer/user combo. - OnComputerFirstUser: Same as computer + will be launched automatically for the first user discovered on each computer - OnComputerFirstAdmin: Same as OnComputerFirstUser but only for the first admin user discovered on each computer - OnDCFirstUser: Same as OnComputerFirstUser but only if the computer is a Domain Controller. - OnDCFirstUser: Same as OnDCFirstUser but only if the user is admin (domain admin). Variables: - |ip|: will be replaced by the selected computer IP - |share|: (Only for Share type commands) Will be replaced with the filename selected in the share table. - |username|, |domain|, |password|: will be replaced by the selected user information, or will be prompted if nothing is selected. - |wordlist|: will be prompted for a wordlist type of file and replaced by the filepath given - |ask_text:$name|: prompt for a text where name is what is asked. store it in a file and replace in command by filepath - |users_as_file|: will be replaced with a filename containing all users usernames - |computers_as_file|: will be replaced with a filename containing all computers IPs """, state="disabled") self.formtv = panel.addFormTreevw( "Commands", ("Type", "Command name", "Command line"), ad_settings.get("commands", []), doubleClickBinds=[[ "Computer", "Share", "OnComputerNewUser", "OnComputerFirstUser", "OnComputerFirstAdmin", "OnDCFirstUser", "OnDCFirstAdmin" ], "", ""], side="top", width=800, height=10, fill=tk.BOTH) button_panel = panel.addFormPanel(side="bottom") button_panel.addFormButton("Submit", self.onOk, side="right") button_panel.addFormButton("Cancel", self.onError, side="right") panel.constructView(appFrame) appFrame.pack(ipadx=10, ipady=5, fill=tk.BOTH, expand=tk.TRUE) try: self.app.wait_visibility() self.app.transient(parent) self.app.grab_set() self.app.focus_force() self.app.lift() except tk.TclError: pass
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 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
class ChildDialogAskFile: """ Open a child dialog of a tkinter application to ask details about existing files parsing. """ def __init__(self, parent, info="Choose a file", 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(info) self.rvalue = None self.default = default_path appFrame = ttk.Frame(self.app) self.form = FormPanel() self.form.addFormLabel("Choose one file", info, side=tk.TOP) self.fileForm = self.form.addFormFile("File", ".+", '', width=50, side=tk.TOP, mode="file") self.button = self.form.addFormButton("Cancel", self.onError, side=tk.RIGHT) self.form.addFormButton("OK", 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 onError(self, _event=None): self.rvalue = None self.app.quit() 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 files_paths = self.fileForm.getValue() try: filepath = files_paths[0] except IndexError: self.rvalue = None tk.messagebox.showwarning("Form not validated", "At least one file is asked", parent=self.app) return self.rvalue = filepath self.app.quit() return
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()
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()